diff options
| author | svn2git <svn2git@FreeBSD.org> | 1994-05-01 08:00:00 +0000 |
|---|---|---|
| committer | svn2git <svn2git@FreeBSD.org> | 1994-05-01 08:00:00 +0000 |
| commit | a16f65c7d117419bd266c28a1901ef129a337569 (patch) | |
| tree | 2626602f66dc3551e7a7c7bc9ad763c3bc7ab40a /gnu/usr.bin/as | |
| parent | 8503f4f13f77abf7adc8f7e329c6f9c1d52b6a20 (diff) | |
Diffstat (limited to 'gnu/usr.bin/as')
196 files changed, 76265 insertions, 0 deletions
diff --git a/gnu/usr.bin/as/CONTRIBUTORS b/gnu/usr.bin/as/CONTRIBUTORS new file mode 100644 index 000000000000..cfcc7bccd4be --- /dev/null +++ b/gnu/usr.bin/as/CONTRIBUTORS @@ -0,0 +1,11 @@ +(This file under construction). + +If you've contributed to gas and your name isn't listed here, it is +not meant as a slight. I just don't know about it. Email me, +rich@cygnus.com and I'll correct the situation. + +Dean Elsnor wrote the original gas for vax. + +Jay Fenalson maintained gas for a while. + +K. Richard Pixley currently maintains gas. diff --git a/gnu/usr.bin/as/COPYING b/gnu/usr.bin/as/COPYING new file mode 100644 index 000000000000..a43ea2126fb6 --- /dev/null +++ b/gnu/usr.bin/as/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU 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. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), 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 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 show them these terms so they know 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. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + 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 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 derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 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 License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +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. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary 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 + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 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 Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing 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 for copying, distributing or modifying +the Program or works based on it. + + 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. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. 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 this 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 +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. 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 + + 11. 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. + + 12. 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 the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, 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) 19yy 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 is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/gnu/usr.bin/as/ChangeLog b/gnu/usr.bin/as/ChangeLog new file mode 100644 index 000000000000..db772344197c --- /dev/null +++ b/gnu/usr.bin/as/ChangeLog @@ -0,0 +1,429 @@ +Sun Mar 1 17:02:06 1992 K. Richard Pixley (rich@cygnus.com) + + * README: updated to 1.92.3, included mail announcement. + +Sat Feb 29 00:53:16 1992 K. Richard Pixley (rich@cygnus.com) + + * tc-sparc.c (md_apply_fix): relocation overflow checks. + + * atof-generic.c (atof_generic): recognize 99e999 as infinity for + older, broken, compilers. + + * version.c: bump to 1.92.3, drop "Cygnus". + + * input-scrub.c (as_where): use myname (which comes from argv[0]) + as part of all error messages. + + * mess-dose renaming: + flonum-copy.c -> flo-copy.c + flonum-const.c -> flo-const.c + config/a.out.gnu.h -> config/aout.h + config/coff.gnu.h -> config/coff.h + + * Makefile.in, obj-aout.h, obj-coff.h: reflect file renaming. + + * output-file.c (output_file_create): add "b" to the fopen to + humor mess-dos. + + * configure.in: tahoe needs atof-tahoe. + + * config/tc-tahoe.[hc], config/atof-tahoe.c, opcode/tahoe.h: new + files. This is kinda blind cause I don't have anything to run + through it or compare against. + + * read.c (read_a_source_file), expr.c (operand): fix a very old + bug in label reading exposed by m88k. Also, m88k can't have a + pseudo "set". + + * config/m88k.[hc]: freshen copyrights, version 2 gpl, update to + current gas. + + * config/m88k-opcode.h moved to opcode/m88k.h + + * read.c: NO_DOT_PSEUDOS from hacks unfinished work. + + * opcode/m68k.h: Sun's JFcc aliases appear to be variable length. + Make them so. + + * opcode/a29k.h: remove rcsid. + + * config/te-sun3.h: remove semicolon typo. + + * config/obj-vms.c: another patch from eric youngdale. + + * write.c: white space only. + + * config/tc-i960.c: change from intel for header flags. + + * config/te-sequent.h, config/obj-aout.h: first cut at building + sequent headers. + + * config/tc-ns32k.c: patches from Jyrki Kuoppala <jkp@cs.hut.fi>. + + * struct-symbol.h: removed redundant decl of N_TYPE_seg. + + * config/tc-sparc.c (sparc_ip), opcode/sparc.h: changes from chris + torek to correct a problem with "neg". some white space. + + * confic/tc-m68k.c: a fix pulled from hack's unfinished work and + my mail archives. Try again to get pcrel working. Fix stupid + botch on cpu_type comparison. + + * config/tc-sparc.c: .empty pseudo-op from + gordoni@cs.adelaide.edu.au. + + * opcode/sparc.h: some new aliases from chris torek. + + * opcode/i386.h: some new aliases and opcodes. also patches from + Steve Bleazard <steve@robobar.co.uk>. + + * config/te-hpux.h: new file. + + * configure.in: when targetting hpux, use te-hpux.h. + + * config/obj-aout.c (obj-pre-write-hook), config/obj-bout.[ch] + (obj-pre-write-hook), config/obj-coff.[ch] (obj-pre-write-hook), + config/obj-generic.h, config/obj-vms.h, write.c + (write_object_file): move magic number fiddling out of write.c + and into obj-pre-write-hook. + + * config/tc-i860.c: gcc -Wall cleanup. + +Fri Feb 28 00:30:36 1992 K. Richard Pixley (rich@rtl.cygnus.com) + + * configure.in: if target is sun3, use te-sun3.h. + + * config/tc-m68k.h, config/te-sun3.h: moved #define of + default_magic_number_for_object_file from former to latter. + + * config/te-sun3.h: removed sun_asm_syntax and te_sun3, they + aren't used. + + * all: white space changes. + " -> " becomes "->" + "foo [" becomes "foo[" + "a . b" becomes "a.b" + "\(if\|for\|while\|switch\)(" become "\\1(" + "\\([^\n]\\)[ \t]*\\([=!+-*/<>]\\)=[ \t]*" become "\\1 \\2= " + + * read.c, write.c, config/tc-i386.c: white space and comments + only. + + * config/obj-vms.c: convert PUT_LONG and PUT_SHORT to squirt byte + swapped numbers. + + * as.c, flonum-const.c, hex-value.c, input-file.c, version.c, + config/obj-aout.h, config/obj-vms.c: VMS -> HO_VMS. + + * config/ho-vms.h: added HO_VMS. + +Thu Feb 27 18:25:11 1992 K. Richard Pixley (rich@rtl.cygnus.com) + + * config/ChangeLog: removed. entries merged into this file. + + * config/ho-vms.h: new file. Move the VMS stuff out of ho-vax.h + into ho-vms.h. + + * configure.in: use ho-i386v4 for i386-sysvr4. + + * config/ho-i386v4: new file. + +Tue Feb 25 19:54:04 1992 (Eric Youngdale at youngdale@v6550c.nrl.navy.mil) + + * config/obj-vms.c (VMS_write_object_file): Add work-around + for g++ compiler bug involving external vtables. + +Mon Feb 24 22:19:10 1992 (Eric Youngdale at youngdale@v6550c.nrl.navy.mil) + + * README-vms: Describe how to get a VMS obj file to a vms machine + via NFS. + + * configure.in: For i386-sysv*, use gas_host=i386. + + * Makefile.in: Remove continuation line markers when the next line + is blank. + + * read.c (line_comment_chars): Make external. + + * input-file.c: Remove redundant include of <assert.h>. + + * config/ho-vax.h [VMS]: Include <ctype.h> and <perror.h>. + + * config/obj-vms.h: Remove said includes. Add RELOC_32 to + reloc_type to prevent compilation error. + + * config/obj-vms.c: Change bcopy to memcpy throughout. + (VMS_local_stab_Parse): Fix typo. + (VMS_local_stab_Parse, VMS_RSYM_Parse, Define_Local_Symbols, + Define_Routine, VMS_write_object_file): Allow 'f' for functions + as well as 'F'. + +Mon Feb 24 03:48:04 1992 K. Richard Pixley (rich@cygnus.com) + + * README: updated to reflect current testing status. + + * README.rich, NOTES, NOTES.config: updated slightly, marked as + "under construction". + + * CONTRIBUTORS: new file. + + * README-vms: options to configure are now -options=, not + +options=. + + * version.c: bumped version to 1.92.2. + +Mon Feb 24 03:27:00 1992 Eric Youngdale (youngdale at v6550c.nrl.navy.mil) + + * config.sub: Added vms as a target system. (So people do not + have to try to figure out that "vax-dec-vms" would work). + + * configure.in: Added vms as a target os, and object file format. + (Useless on a vms system, but this is for people who want to + cross assemble). + + * config-gas.com: New file. Script for VMS systems to set up the + configuration to build gas for VMS, and create config.status. + + * make-gas.com: Redone to work with the bfd-gas scheme. + + * as.c: Add const modifier to version_string. + + * atof-vax.c: Remove redundant include of flonum.h. (This is also + included via as.h). + + * expr.c: Add "const" modifier to hex_value. + + * read.c: Add "const" modifier to line_comment_chars, and + line_separator_chars. Make use of the -1 switch for backward + compatibility with gcc 1.nn. + (s_ignore): remove redundant declaration of is_end_of_line. + + * symbols.c: Finish conversion to S_* macros in the VMS only + parts of the program. Add "const" modifier to + md_[long,short]_jump_size. Remove declaration of const_flag + (which will be declared in obj-vms.h). + + * write.c: Add "const" modifier to md_[long,short]_jump_size. + Fix arguments to VMS_write_object_file. + + * obj-vms.h: New file (sort of). Mostly canibalized from other + files, using: + + - objrecdef.h: Removed structure definition that we do not use, + and removed dollar signs from identifiers, since Unix System 5 + does not like them. + + - obj-aout.h: Took S_*, some H_* macros, and a number of + symbol definitions. + + - a.out.hp.h: Took nlist structure. We do not really use this + per se, but it is easiest to let gas think that we do. When we + write the object file, we just pick out the parts that we need. + + - stab.h: Just included it, since on non VMS and non a.out systems + we have no guarantee of having it. (Define N_* symbols). + + *obj-vms.c: Renamed from vms.c. Did the following: + + - Reworked to use the S_* macros. + + - Add "const" modifier to version_string. + + - Added global[ref,def,value] support + + - (VMS_Store_PIC_Symbol_Reference):fix a bug with static constants. + + - Remove a few redunant includes - all are now included through as.h. + + - (obj_crawl_symbol_chain): Clean up (a lot), and remove non-VMS + code. Add definition for obj_read_begin_hook. + + - Borrow the stab[s,d,n] routines from obj-aout.c. + + - Borrow the seg_N_TYPE and N_TYPE_seg arrays from aout.c + + - Use <fab.h>,<rab.h> and <xab.h> instead of <vms/fabdef.h> + <vms/rabdef.h> and <vms/xabdef.h>, for more consistent results. + (Some peoples <vms/*.h> files are different than others). + + - Merged vms-dbg.c into obj-vms.c. Modified to use + the S_* macros. Added code to remove the psect hack from + variable names before writing them to the debugger records. + + + + The following patches make cross assembly possible. + + * as.c, read.c, symbols.c, write.c: Change "ifdef VMS" to + "ifdef OBJ_VMS". + + * vms.c: + + - Wrap the #include of some VMS system dependent headers + with "ifdef VMS". + + - (get_VMS_time_on_unix): Add new routine. Generates current + time in VMS format to be written into object file. + + - (Write_VMS_MHD_Records): Use get_VMS_time_on_unix if we are not + running on a VMS system. + + - (Flush_VMS_Object_Record_Buffer): Add code to write correct + record format when running on a non-VMS system. + + - (Create_VMS_Object_File): Use different mode if running under + unix. + + - (VMS_TBT_Source_File): If we are not running on a VMS system, + write a source file record for the debugger that looks reasonable. + +Mon Feb 24 02:06:00 1992 K. Richard Pixley (rich@cygnus.com) + + * Makefile.in: remove $(srcdir)/../include from INCLUDES. It + isn't needed. + + * README: updated with current state. + + * read.c (stringer): read arbitrary expressions between the commas + and treat them as ".byte" values. At least some i860 assembler + does this so now we do too. Also white space throughout. + + * expr.c, expr.h, frags.c, symbols.c, write.c: white space only. + +Mon Feb 24 01:45:40 1992 K. Richard Pixley (rich@cygnus.com) + + * config/te-sequent.h, config/tc-ns32k.h, config/tc-ns32k.c: + SEQUENT_COMPATIBILITY -> TE_SEQUENT. + + * config/obj-aout.c: if OLD_GAS and i386, then screw up the magic + number. + + * config/obj-bout.c: do not include aout/stab_gnu.h if NO_LISTING. + + * config/obj-bout.h: added enum reloc_type. + + * config/tc-i386.c: on OLD_GAS, .align is power of two, rather + than bytes. + + * config/tc-i386.h: on OLD_GAS, the filler byte should be zero + rather than NOOP. + + * config/tc-i860.c: relocs are 12bytes on this target. Also white + space. + + * config/tc-m68kmote.c: removed. Not ready yet. + + * config/a.out.gnu.h, config/tc-a29k.c, config/tc-m68k.c, + config/tc-ns32k.c: white space only. + + * config/tc-a29k.h, config/tc-i860.h, config/tc-i960.h, + config/tc-m68k.h, config/tc-ns32k.h, config/tc-sparc.h, + config/tc-vax.h: NO_LISTING + + * config/tc-m68k.h, config/tc-i860.h, config/tc-vax.h: + REVERSE_SORT_RELOCS if OLD_GAS. + + * config/mt-m68k: removed. not needed. + +Fri Feb 21 06:22:15 1992 K. Richard Pixley (rich@rtl.cygnus.com) + + * config/obj-aout.c: do not include stab.gnu.h if NO_LISTING. + + * config/tc-i860.c, config/a.out.gnu.h: move i860 relocs to a proper place. + + * config/a.out.h: removed. + +Fri Feb 21 06:21:07 1992 K. Richard Pixley (rich@rtl.cygnus.com) + + * Makefile.in: put header files before C source for TAGS; remove + references to non-existent syscalls.h. + + * read.c, write.c subsegs.c: back out the .bss changes. + +Fri Feb 21 02:17:22 1992 Minh Tran-Le (TRANLE@INTELLICORP.COM) + + * config/tc-i386.c: config/tc-i386.c: added handling of the + following opcodes: i/o opcodes - inb, inw, outb and outw. + string manipulation with att syntax - scmp, slod, smov, ssca, + ssto. + +Fri Feb 21 01:53:50 1992 Minh Tran-Le (TRANLE@INTELLICORP.COM) + + * config/obj-coff.c: (for aix386) Moved the symbols .text, .data + and .bss to just after .file . + + In obj_crawl_symbol_chain() where it tries to put the external + symbols apart, with the condition: + (!S_IS_DEFINED(symbolP) && + !S_IS_DEBUG(symbolP) && + !SF_GET_STATICS(symbolP)) + it was moving too many symbols out. So I switch it back to the + condition: + (S_GET_STORAGE_CLASS(symbolP) == C_EXT && !SF_GET_FUNCTION(symbolP)) + + In obj_emit_relocations() added the conditional on KEEP_RELOC_INFO + so that we don't use the F_RELFLG which make the linker complain + that somebody has stripped the relocation info. + + Also, the AIX ld program require that the relocation table + is sorted by r_vaddr like the standard ATT assembler does. + + [he also changed the sizeof(struct ...)'s into the coff + style FOOSZ macros. I'm not sure this is right, but I can't + remember why. xoxorich.] + +Fri Feb 21 01:08:48 1992 Minh Tran-Le (TRANLE@INTELLICORP.COM) + + * symbols.c (local_label_name): symbols now start with ^A. + + * read.c, subsegs.c, write.c obj-coff.c: added handling of + `.bss` pseudo op for unitialized data. The new gcc (1.37.9x) + generate these sections. .align: will use NOP_OPCODE or 0 + for padding. This is just for being nice to the + disassembler. + + * expr.c (operand): changed to generate local label "\001L0" + starting with a ^A so that it is recognized as a local label. + + * as.c (perform_an_assembly_pass): zero bss_fix_root, too. + +Fri Feb 21 01:08:48 1992 K. Richard Pixley (rich@cygnus.com) + + * Makefile.in, configure.in, doc: use the doc. Build it, install + it, clean it, etc. + +Tue Feb 18 02:21:25 1992 K. Richard Pixley (rich at cygnus.com) + + * read.c: white space and comments only. + + * configure.in: use the new atof-ns32.c for ns32k. + + * write.c: comment change only. + +Tue Feb 18 02:11:10 1992 K. Richard Pixley (rich at cygnus.com) + + * config/tc-m88k.[hc]: pulled in from hack's unfinished work. These + aren't yet integrated. + + * config/tc-i860.[hc]: blew off the dust. Something must still be + done about conflicting relocation types. + + * config/tc-ns32k.c: Replaced previous tc_aout_fix_to_chars stub + with the real thing. + + * config/tc-i960.c, tc-sparc.c: white space and comments only. + + * config/tc-a29k.h: delete duplicate macro definition. + + * new file config/atof-ns32k.c copied from hack's last unreleased + gas. + +Mon Feb 17 07:51:06 1992 K. Richard Pixley (rich at cygnus.com) + + * config/tc-ns32k.c: actually make tc_aout_fix_to_chars work + rather than abort. + + * nearly everything. flush ChangeLog, package as gas-1.92.1. + ChangeLog's prior to this are sketchy at best. I have logs. + They just aren't ChangeLogs. + diff --git a/gnu/usr.bin/as/Makefile b/gnu/usr.bin/as/Makefile new file mode 100644 index 000000000000..35090323a5ea --- /dev/null +++ b/gnu/usr.bin/as/Makefile @@ -0,0 +1,73 @@ +# from: @(#)Makefile 6.1 (Berkeley) 3/3/91 +# $Id: Makefile,v 1.3 1994/02/20 16:06:08 rgrimes Exp $ + +.include "config/Makefile.$(MACHINE)" + +.if !defined (gas_hosttype) +gas_hosttype=$(MACHINE) +.endif +.if !defined (gas_target) +gas_target=$(MACHINE) +.endif +.if !defined (gas_objformat) +gas_objformat=aout +.endif + +.if exists(${.CURDIR}/obj) +ADDINCLUDE=-I${.CURDIR}/obj +.endif + +PROG= as +SRCS+= app.c as.c atof-generic.c bignum-copy.c \ + cond.c expr.c flo-const.c flo-copy.c flonum-mult.c \ + frags.c hash.c hex-value.c input-file.c input-scrub.c \ + listing.c messages.c obstack.c output-file.c read.c subsegs.c \ + symbols.c version.c write.c xmalloc.c xrealloc.c \ + obj-$(gas_objformat).c +CFLAGS+= -I$(.CURDIR) ${ADDINCLUDE} -I$(.CURDIR)/config \ + -DPIC -DOLD_GAS -DSIGTY=void -Derror=as_fatal \ + -DSUB_SEGMENT_ALIGN=4 +#LDADD+= -lgnumalloc +#DPADD+= /usr/lib/libgnumalloc.a + +CONF_HEADERS= targ-cpu.h obj-format.h host.h targ-env.h + +.PATH: $(.CURDIR)/config + +beforedepend ${PROG}: ${CONF_HEADERS} + +targ-cpu.h: Makefile config/Makefile.$(MACHINE) + @cmp -s $(.CURDIR)/config/tc-$(gas_target).h targ-cpu.h || \ + ( echo "updating ${.TARGET}..." ; /bin/rm -f targ-cpu.h ; \ + cp $(.CURDIR)/config/tc-$(gas_target).h targ-cpu.h ) + +obj-format.h: Makefile config/Makefile.$(MACHINE) + @cmp -s $(.CURDIR)/config/obj-$(gas_objformat).h obj-format.h || \ + ( echo "updating ${.TARGET}..." ; /bin/rm -f obj-format.h ; \ + cp $(.CURDIR)/config/obj-$(gas_objformat).h obj-format.h ) + +.if exists ($(.CURDIR)/config/ho-$(gas_hosttype).h) +config_hostfile= $(.CURDIR)/config/ho-$(gas_hosttype).h +.else +config_hostfile= $(.CURDIR)/config/ho-generic.h +.endif + +host.h: Makefile config/Makefile.$(MACHINE) + @cmp -s $(config_hostfile) host.h || \ + ( echo "updating ${.TARGET}..." ; /bin/rm -f host.h ; \ + cp $(config_hostfile) host.h ) + +.if exists ($(.CURDIR)/config/te-$(MACHINE).h) +config_targenvfile= $(.CURDIR)/config/te-$(MACHINE).h +.else +config_targenvfile= $(.CURDIR)/config/te-generic.h +.endif + +targ-env.h: Makefile config/Makefile.$(MACHINE) + @cmp -s $(config_targenvfile) targ-env.h || \ + ( echo "updating ${.TARGET}..." ; /bin/rm -f targ-env.h ; \ + cp $(config_targenvfile) targ-env.h ) + +CLEANFILES+= ${CONF_HEADERS} + +.include <bsd.prog.mk> diff --git a/gnu/usr.bin/as/Makefile.in b/gnu/usr.bin/as/Makefile.in new file mode 100644 index 000000000000..1497b1fa2868 --- /dev/null +++ b/gnu/usr.bin/as/Makefile.in @@ -0,0 +1,409 @@ +# Makefile for GNU Assembler +# Copyright (C) 1987-1992 Free Software Foundation, Inc. + +#This file is part of GNU GAS. + +#GNU GAS is free software; you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation; either version 2, or (at your option) +#any later version. + +#GNU GAS is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with GNU GAS; see the file COPYING. If not, write to +#the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# The targets for external use include: +# all, doc, proto, install, uninstall, includes, TAGS, +# clean, cleanconfig, realclean, stage1, stage2, stage3, stage4. + +# Variables that exist for you to override. +# See below for how to change them for certain systems. + +srcdir = . + +prefix = /usr/local + +bindir = $(prefix)/bin +datadir = $(prefix)/lib +libdir = $(prefix)/lib +mandir = $(datadir)/man +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = $(datadir)/info +includedir = $(prefix)/include +docdir = $(datadir)/doc + +SHELL = /bin/sh + +INSTALL = install -c +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = $(INSTALL) + +AR = ar +AR_FLAGS = qv +BISON = bison +MAKEINFO = makeinfo +RANLIB = ranlib +MINUS_G = -g + +# Lists of files for various purposes. + +REAL_SOURCES = \ + $(srcdir)/app.c \ + $(srcdir)/as.c \ + $(srcdir)/atof-generic.c \ + $(srcdir)/bignum-copy.c \ + $(srcdir)/cond.c \ + $(srcdir)/expr.c \ + $(srcdir)/flo-const.c \ + $(srcdir)/flo-copy.c \ + $(srcdir)/flonum-mult.c \ + $(srcdir)/frags.c \ + $(srcdir)/hash.c \ + $(srcdir)/hex-value.c \ + $(srcdir)/input-file.c \ + $(srcdir)/input-scrub.c \ + $(srcdir)/messages.c \ + $(srcdir)/obstack.c \ + $(srcdir)/output-file.c \ + $(srcdir)/read.c \ + $(srcdir)/strerror.c \ + $(srcdir)/strstr.c \ + $(srcdir)/subsegs.c \ + $(srcdir)/symbols.c \ + $(srcdir)/version.c \ + $(srcdir)/write.c \ + $(srcdir)/listing.c \ + $(srcdir)/xmalloc.c \ + $(srcdir)/xrealloc.c + +# in an expedient order +LINKED_SOURCES = \ + targ-cpu.c \ + obj-format.c \ + atof-targ.c + +SOURCES = $(LINKED_SOURCES) $(REAL_SOURCES) + +REAL_HEADERS = \ + $(srcdir)/as.h \ + $(srcdir)/bignum.h \ + $(srcdir)/expr.h \ + $(srcdir)/flonum.h \ + $(srcdir)/frags.h \ + $(srcdir)/hash.h \ + $(srcdir)/input-file.h \ + $(srcdir)/listing.h \ + $(srcdir)/tc.h \ + $(srcdir)/obj.h \ + $(srcdir)/obstack.h \ + $(srcdir)/read.h \ + $(srcdir)/struc-symbol.h \ + $(srcdir)/subsegs.h \ + $(srcdir)/symbols.h \ + $(srcdir)/write.h + +LINKED_HEADERS = \ + a.out.gnu.h \ + a.out.h \ + host.h \ + targ-env.h \ + targ-cpu.h \ + obj-format.h \ + atof-targ.h + +HEADERS = $(LINKED_HEADERS) $(REAL_HEADERS) + +OBJS = \ + targ-cpu.o \ + obj-format.o \ + atof-targ.o \ + app.o \ + as.o \ + atof-generic.o \ + bignum-copy.o \ + cond.o \ + expr.o \ + flo-const.o \ + flo-copy.o \ + flonum-mult.o \ + frags.o \ + hash.o \ + hex-value.o \ + input-file.o \ + input-scrub.o \ + messages.o \ + obstack.o \ + output-file.o \ + read.o \ + strerror.o \ + strstr.o \ + subsegs.o \ + symbols.o \ + version.o \ + write.o \ + listing.o \ + xmalloc.o \ + xrealloc.o + +#### host, target, and site specific Makefile frags come in here. + +all: as.new + (cd doc ; $(MAKE) all) + +info: + (cd doc ; $(MAKE) info) + +install-info: + (cd doc ; $(MAKE) install-info) + +clean-info: + (cd doc ; $(MAKE) clean-info) + +# Now figure out from those variables how to compile and link. + +# This is the variable actually used when we compile. +ALL_CFLAGS = $(MINUS_G) $(INTERNAL_CFLAGS) $(CFLAGS) $(HDEFINES) $(TDEFINES) -DPIC -DOLD_GAS + +# How to link with both our special library facilities +# and the system's installed libraries. + +LIBS = $(HLIBS) + +# Specify the directories to be searched for header files. +# Both . and srcdir are used, in that order, +# so that tm.h and config.h will be found in the compilation +# subdirectory rather than in the source directory. +INCLUDES = -I. -I$(srcdir) -I$(srcdir)/config # -I$(srcdir)/../include +SUBDIR_INCLUDES = -I.. -I$(srcdir) -I$(srcdir)/config + +# Always use -I$(srcdir)/config when compiling. +.c.o: + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $< + +# This tells GNU make version 3 not to export all the variables +# defined in this file into the environment. +.NOEXPORT: + +# Files to be copied away after each stage in building. +STAGESTUFF = *.o as.new + +as.new: $(OBJS) $(LIBDEPS) + -mv -f as.new as.old + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o as.new $(OBJS) $(LIBS) + +config.status: + @echo You must configure gas. Look at the INSTALL file for details. + @false + +# Compiling object files from source files. + +app.o : app.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h +as.o : as.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h +atof-generic.o : atof-generic.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h +bignum-copy.o : bignum-copy.c as.h host.h \ + targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h +cond.o : cond.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h + +debug.o : debug.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + subsegs.h +expr.o : expr.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h + +flo-const.o : flo-const.c flonum.h bignum.h +flo-copy.o : flo-copy.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h +flonum-mult.o : flonum-mult.c flonum.h bignum.h +frags.o : frags.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + subsegs.h +hash.o : hash.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h +hex-value.o : hex-value.c +input-file.o : input-file.c as.h host.h \ + targ-env.h obj-format.h targ-cpu.h \ + struc-symbol.h write.h flonum.h bignum.h expr.h \ + frags.h hash.h read.h symbols.h tc.h obj.h input-file.h +input-scrub.o : input-scrub.c /usr/include/errno.h /usr/include/sys/errno.h \ + as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + input-file.h +listing.o : listing.c as.h host.h targ-env.h flonum.h bignum.h \ + listing.h obj-format.h targ-cpu.h struc-symbol.h write.h expr.h \ + frags.h hash.h read.h symbols.h tc.h obj.h input-file.h +messages.o : messages.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h +obstack.o : obstack.c +output-file.o : output-file.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + output-file.h +read.o : read.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h + +strstr.o : strstr.c +subsegs.o : subsegs.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + subsegs.h +symbols.o : symbols.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + subsegs.h +version.o : version.c +write.o : write.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + subsegs.h output-file.h +xmalloc.o : xmalloc.c +xrealloc.o : xrealloc.c +atof-targ.o : atof-targ.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h \ + symbols.h tc.h obj.h +obj-format.o : obj-format.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h \ + symbols.h tc.h obj.h +targ-cpu.o : targ-cpu.c targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h \ + symbols.h tc.h obj.h $(TARG_CPU_DEPENDENTS) + +# Remake the info files. + +doc: $(srcdir)/as.info + +$(srcdir)/as.info: $(srcdir)/doc/as.texinfo + (cd doc; make as.info; mv as.info $srcdir) + +clean: + (cd doc ; $(MAKE) clean) + -rm -f $(STAGESTUFF) core + +# Like clean but also delete the links made to configure gas. +distclean: clean + -rm -f config.status Makefile host.h targ-env.h targ-cpu.h \ + targ-cpu.c obj-format.h obj-format.c atof-targ.c \ + gas.aux gas.cps gas.fns gas.info gas.kys gas.pgs \ + gas.tps gas.vrs TAGS gas.info* gas.?? gas.??s gas.log \ + gas.toc gas.*aux *.dvi + +# Entry points `install', `includes' and `uninstall'. + +# Copy the files into directories where they will be run. +install: + if [ "$(host_alias)" = "$(target_alias)" ] ; then \ + $(INSTALL_PROGRAM) as.new $(bindir)/as ; \ + else \ + $(INSTALL_PROGRAM) as.new $(bindir)/as-$(target_alias) ; \ + fi + +# Create the installation directory. +install-dir: + -mkdir $(libdir) + -mkdir $(libdir)/gcc + -mkdir $(libdir)/gcc/$(target) + -mkdir $(libdir)/gcc/$(target)/$(version) + +# Cancel installation by deleting the installed files. +uninstall: + -rm -rf $(libsubdir) + -rm -rf $(bindir)/as + -rm -rf $(mandir)/gas.$(manext) + + +# These exist for maintenance purposes. + +tags TAGS: force + etags $(REAL_HEADERS) $(REAL_SOURCES) $(srcdir)/config/*.[hc] $(srcdir)/README $(srcdir)/Makefile.in + +bootstrap: as.new force + $(MAKE) stage1 + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage1/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new + $(MAKE) stage2 + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new + $(MAKE) comparison against=stage2 + +bootstrap2: force + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage1/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new + $(MAKE) stage2 + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new + $(MAKE) comparison against=stage2 + +bootstrap3: force + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new + $(MAKE) comparison against=stage2 + +# Copy the object files from a particular stage into a subdirectory. +stage1: force + -mkdir stage1 + -mv $(STAGESTUFF) stage1 + if [ -f stage1/as.new -a ! -f stage1/as ] ; then (cd stage1 ; ln -s as.new as) ; fi + +stage2: force + -mkdir stage2 + -mv $(STAGESTUFF) stage2 + if [ -f stage2/as.new -a ! -f stage2/as ] ; then (cd stage2 ; ln -s as.new as) ; fi + +stage3: force + -mkdir stage3 + -mv $(STAGESTUFF) stage3 + if [ -f stage3/as.new -a ! -f stage3/as ] ; then (cd stage3 ; ln -s as.new as) ; fi + +against=stage2 + +comparison: force + for i in $(STAGESTUFF) ; do cmp $$i $(against)/$$i ; done + +de-stage1: force + - (cd stage1 ; rm as ; mv -f * ..) + - rmdir stage1 + +de-stage2: force + - (cd stage2 ; rm as ; mv -f * ..) + - rmdir stage2 + +de-stage3: force + - (cd stage3 ; rm as ; mv -f * ..) + - rmdir stage3 + +#In GNU Make, ignore whether `stage*' exists. +.PHONY: stage1 stage2 stage3 stage4 clean realclean TAGS bootstrap + +force: + +Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag) + $(SHELL) ./config.status + diff --git a/gnu/usr.bin/as/NOTES b/gnu/usr.bin/as/NOTES new file mode 100644 index 000000000000..9f18fac04a30 --- /dev/null +++ b/gnu/usr.bin/as/NOTES @@ -0,0 +1,16 @@ +to do: + +remove DONTDEF +remove the ifdef's from fx_callj tests? +what are callj tests? +space tighten sparc alignment. +fix number_to_chars, & family to have no side effects. +md_ => tp_ +multiple segments. +share b.out with a.out. + +regress: + ++-inf + +stack: diff --git a/gnu/usr.bin/as/NOTES.config b/gnu/usr.bin/as/NOTES.config new file mode 100644 index 000000000000..a511519290df --- /dev/null +++ b/gnu/usr.bin/as/NOTES.config @@ -0,0 +1,52 @@ +(This file under construction). + + + The GAS Configuration Plan + +Theory: + +The goal of the new configuration scheme is to bury all object format, +target processor, and host machine dependancies in object, target, and +host specific files. That is, to move as many #ifdef's as possible +out of the gas common code. + +Here's how it works. There is a .h and a .c file for each object file +format, a .h and a .c file for each target processor, and a .h for +each host. configure creates {sym}links in the current directory to +the appropriate files in the config directory. + +Implementation: + +host.h is a {sym}link to .../config/ho-yourhost.h. It is intended to +be used to hide host compiler, system header file, and system library +differences between host machines. If your host needs actual c source +files, then either: these are generally useful functions, in which +case you should probably build a local library outside of the gas +source tree, or someone, perhaps me, is confused about what is needed +by different hosts. + +obj-format.h is a {sym}link to .../config/obj-something.h. It is +intended to hide object file format differences from the bulk of gas, +and from most of the cpu backend. + +All gas .c files include as.h. + +as.h #define's "gas", includes host.h, defines a number of gas +specific structures and types, and then includes tp.h, obj.h, and +target-environment.h. + +te-something.h defines a target environment specific preprocessor +flag, eg, TE_SUN, and then includes obj-format.h. + +obj-format.h defines an object format specific preprocessor flag, eg, +OBJ_AOUT, OBJ_BOUT, OBJ_COFF, includes "target-processor.h", and then +defines the object specific macros, functions, types, and structures. + +target-processor.h + +target-processor. + +Porting: + +There appear to be four major types of ports; new hosts, new target +processors, new object file formats, and new target environments. diff --git a/gnu/usr.bin/as/README b/gnu/usr.bin/as/README new file mode 100644 index 000000000000..73b7605a5ad6 --- /dev/null +++ b/gnu/usr.bin/as/README @@ -0,0 +1,212 @@ +This is a pre-alpha version of the GNU assembler, version 1.92.3. + +(this is a copy of the mail announcement. Real README follows below.) + +This session I merged the m88k support. It configures, builds, and +assembles things, including some gcc2 output. I have no way of +knowing if the output is right. + +I've merged the tahoe support. It configures and builds. I couldn't +build the cygnus version of gcc2 for this machine, so I have no idea +whether gas is assembling anything at all for it. + +I've walked through my bug and patch archives. Gas now makes a +tolerable guess at a.out headers for hpux and sequent, although I have +no way to know if these are right yet. + +Ming tran-le's changes for 386aix will probably drop out soon. He +needs multiple segments and I don't plan to get that in before the +real release. + +Eric youngdale's help with vms has been invaluable. According to him, +this gas is doing vms. I didn't quite get a cross to vms working and +don't plan to spend any more time on it. + +The gas manual is included in the distribution, configuration, and +Makefiles. It should build, be printable, and readable through info. + +I have not yet verified that this gas has all of the unreleased +changes that hack made after the last gas release. At this point I +plan to ignore these until those bugs are re-reported in an alpha or +full release I don't think it's worth my time. + +I have not yet verified any hosts other than sun4, although I have +three-staged sun3 native. + +I have not updated the configuration doc. + +I do not plan to bring in any new backends for the upcoming release +unless someone hands them to me on a platter as eric did for vms. I +merged the m88k and tahoe ports because they were simple for me at +this point, but would have been difficult for someone else. I may yet +do this for the ncube support as well. + +I've looked at the osf stuff and discarded it for this release. I'm +not sure I like what they've done for macho object format and without +macho headers, I can't even build their version. + +I've looked at the utah stuff and discarded it for this release. +They, too, have made some sweeping changes to support their object +format that I'm not sure were necessary. In any case, merging this +would be too much work for me right now. + +I've looked at the tron port. It's remarkably clean and it's a.out +format. I don't plan to merge this for the full release for two +reasons. First, it's so clean, they will be able to add their stuff +on top and build a seperate distribution without much trouble. +Second, I'm get responses from them, and hope that they will be able +to do the merge. + + +To do before alpha: + +* merge patches and address bugs as they arrive. + +* kill a remaining bug. The following input: + + .text +a .word 3 +b .word 4 +c .half b-a + +kills most risc ports. I believe that this represents a failing of +the internal representation of relocs (aka fixS's). The fix is +relatively straightforward and I intend to make it. + +* add autoconf style configuration for hosts (not targets). + +* test via three-staging (preferably with gcc2) on all a.out based + machines to which I have access. + +* update/clean out README's and build a brief porting guide. + +There is still a copyright issue on the coff back end, so it may need +to be pulled for the full release. If this gets resolved, I hope to +see coff run personally on at least one native machine before full +release. + + +Real README: + +This is a pre-alpha version of the GNU assembler, version 1.92.3. + +A number of things have changed and the wonderful world of gas looks +very different. There's still a lot of irrelevant garbage lying +around that will be cleaned up soon. The gas manual now builds and +installs, but internal documentation is still scarce, as are logs of +the changes made since the last gas release. My apologies, and I'll +try to get something useful + +At this point I believe gas to be ansi only code for most target +cpu's. That is, there should be relatively few, if any host system +dependencies. Most of my recent effort has been spent testing and +dusting off ports for which Cygnus hasn't had recent need. + +Hosting has recently been tested on only: + + sun4 + sun3 + +I believe that gas can currently be targetted for: + + sun4 + sun3 + +and "ports" for other cpu's and object file formats from the following +set are probably trivial at this point: + + a.out + + a29k + i386 + i860 + i960 + m68k + m88k + ns32k + tahoe + sparc + vax + +I have tested most of these in "generic" a.out configurations so I +feel pretty confident in them. If anything else works, it's an +accident. + +Some ports now generate object files that are somewhat differently +shaped, but should be more correct. Specifically: + +* Most a.out ports now sort the relocation table in numerically + ascending order. In previous versions of gas, the relocation table + was sorted in descending order. To get the previous functionality, + compile with -DREVERSE_SORT_RELOCS. + +* ns32k: The last gas I have from hack simply looks broken for ns32k. + I think this one works, but don't have an assembler that I trust + against which to compare. + +* i386: now uses ".align x" to mean x bytes rather than 2^x bytes. It + also pads with the noop instruction rather than zeroes. + +In all cases, compiling with -DOLD_GAS will produce an assembler that +should produce object files that are bitwise identical to the previous +version of gas. + + + + NEW FEATURES! + + +This isn't a complete catalog. I've forgotten what all has been done. + +* support for i960, a29k, m88k, and tahoe. + +* support for 68030 and 68040, including the ability to limit the + instructions that gas will accept. ie, you can assemble for EXACTLY + 68000 and no more. + +* object file formats have been broken out into separate backends. + +* a new "backend" has been created to represent the target + environment. That is, gas now mimics various other assemblers + rather than creating it's own requirements. A side effect of this + is that this version of gas may not behave the same way as previous + versions. + +* ansi. gas is now strictly ansi code so host ports should be + trivial. + + + + REPORTING BUGS IN GAS + + +Bugs in THIS RELEASE of gas should be reported directly to +rich@cygnus.com. NOT to bug-gnu-utils@prep.ai.mit.edu. + +If you report a bug in GAS, please remember to include: + +A description of exactly what went wrong. + +How GAS was configured, + +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. diff --git a/gnu/usr.bin/as/README-vms b/gnu/usr.bin/as/README-vms new file mode 100644 index 000000000000..796c603b4f34 --- /dev/null +++ b/gnu/usr.bin/as/README-vms @@ -0,0 +1,248 @@ + This document explains a couple of things that are specific to VMS. +There are currently two "chapters", the first deals with cross-assembly +issues, and the second deals with the VMS debugger and GNU-CC. + + +*********************************************************************** +****************** Notes for Cross Assembly with VMS ****************** +*********************************************************************** + + If you wish to build gas on a non-VMS system to cross-assemble, +you should use: + +configure ${hosttype} -target=vms + +and then follow the usual procedure. The object files generated on +Unix will be correct from a binary point of view, but the real trick is +getting them to the VMS machine. The format of the object file is +a variable-length record, but each record contains binary data. gas +writes the records in the same format that VMS would expect, +namely a two-byte count followed by that number of bytes. + + If you try to copy the file to a VMS system using ftp, the ftp +protocol will screw up the file by looking for nulls (record terminator for +unix) and it will insert it's own record terminators at that point. This +will obviously corrupt the file. + + If you try to transfer the file with ftp in binary mode, the +file itself will not be corrupt, but VMS will think that the file contains +fixed-length records of 512 bytes. You can use the public-domain FILE +utility to change this with a command like: + +$FILE foo.o/type=variable + +If you do not have this utility available, the following program can be +used to perform this task: + + #include <fab.h> + + #define RME$C_SETRFM 1 + + struct FAB * fab; + + main(int argc, char * argv[]){ + int i, status; + fab = (struct FAB*) malloc(sizeof(struct FAB)); + *fab = cc$rms_fab; /* initialize FAB*/ + fab->fab$b_fac = FAB$M_PUT; + fab->fab$l_fop |= FAB$M_ESC; + fab->fab$l_ctx = RME$C_SETRFM; + fab->fab$w_ifi = 0; + for(i=1;i<argc;i++){ + printf("Setting %s to variable length records.\n",argv[i]); + fab->fab$l_fna = argv[i]; + fab->fab$b_fns = strlen(argv[i]); + status = sys$open(fab,0,0); + if((status & 7) != 1) lib$signal(status); + fab->fab$b_rfm = FAB$C_VAR; + status = sys$modify(fab,0,0); + if((status & 7) != 1) lib$signal(status); + status = sys$close(fab,0,0); + if((status & 7) != 1) lib$signal(status); + }; + } + + If you have NFS running on the VMS system, what you need to do +depends upon which NFS software you are running on the VMS system. There +are a number of different TCP/IP packages for VMS available, and only very +limited testing has been performed. In the tests that has been done so +far, the contents of the file will always be correct when transferring the +file via NFS, but the record attributes may or may not be correct. + + One proprietary TCP/IP/NFS package for VMS is known to +automatically fix the record attributes of the object file if you NFS mount +a unix disk from the VMS system, and if the file has a ".obj" extension on +the unix system. Other TCP/IP packages might do this for you as well, but +they have not been checked. + +No matter what method you use to get the file to the VMS system, it is +always a good idea to check to make sure that it is the correct type by +doing a "$dir/full" on the object file. The desired record attributes will +be "None". Undesirable record attributes will be "Stream-LF" or anything +else. + +Once you get the files on the VMS system, you can check their integrity +with the "$anal/obj" command. (Naturally at some point you should rename +the .o files to .obj). As far as the debugger is concerned, the records +will be correct, but the debugger will not be able to find the source files, +since it only has the file name, and not the full directory specification. +You must give the debugger some help by telling it which directories to +search for the individual files - once you have done this you should be +able to proceed normally. + + It is a good idea to use names for your files which will be valid +under VMS, since otherwise you will have no way of getting the debugger to +find the source file when deugging. + +The reason for this is that the object file normally contins specific +information that the debugger can use to positively identify a file, and if +you are assembling on a unix system this information simply does not exist +in a meaningful way. You must help the debugger by using the "SET FILE=" +command to tell the debugger where to look for source files. The debugger +records will be correct, except that the debugger will not be initially +able to find the source files. You can use the "SET FILE" command to tell +the debugger where to look for the source files. + +I have only tested this with a SVr4 i486 machine, and everything seems to +work OK, with the limited testing that I have done. Other machines may +or may not work. You should read the chapters on cross-compilers in the gcc +manual before fooling with this. Since gas does not need to do any floating +point arithmetic, the floating point constants that are generated here should +be correct - the only concern is with constant folding in the main compiler. +The range and precision of floats and doubles are similar on the 486 (with +a builtin 80387) and the VAX, although there is a factor of 2 to 4 +difference in the range. The double, as implemented on the 486, is quite +similar to the G_FLOAT on the VAX. + +*********************************************************************** +****************** Notes for using GNU CC with the VMS debugger******** +*********************************************************************** + + + 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. diff --git a/gnu/usr.bin/as/README.coff b/gnu/usr.bin/as/README.coff new file mode 100644 index 000000000000..46c61cda9093 --- /dev/null +++ b/gnu/usr.bin/as/README.coff @@ -0,0 +1,79 @@ +The coff patches intend to do the following : + + . Generate coff files very compatible with vanilla linker. + . Understands coff debug directives. + +Here are the guidelines of the work I have done : + + . Encapsulate format dependent code in macros where it is possible. + . Where not possible differenciate with #ifdef + . try not to change the calling conventions of the existing functions. + I made one exception : symbol_new. I would be pleased to hear about + a better solution. (symbols.c) + . Extend the use of N_TYPE_seg seg_N_TYPE tables so that segments can + be manipulated without using their format dependent name. (subsegs.c) + . Write a function to parse the .def debug directives + . Write two small peaces of code to handle the .ln directive. + . In write.c try to move all the cross compilation specifics (md_..) to + format dependent files. + . Encapsulate the data structures using generic types, macros calls. + . Added too much code to resolve the complexity of the symbol table + generated. Most of the code deals with debug stuff. + . Create another makefile, shorter, cleaner. + . Create a config.gas shell script to mimic the gcc,gdb... configuration + mechanism. This reduce the complexity of the makefile. + . Isolate the format dependent code in two files + coff.c coff.h + aout.c aout.h + elf.c elf.h [ Not yet ;-] + . added a little stack management routine for coff in file stack.c + . isolate os specific flags in m- files + +If further development is planed on it is should solve the following problems : + + . Encapsulate DESC & OTHER tests in a macro call. I'm not aware + of their exact semantics. + . Clean up the seg_N_TYPE N_TYPE_seg naming scheme + . Try to remove as much reference to segment dependent names as possible + . Find a cleaner solution for symbol_new. + . Report the modifications on vax, ns32k, sparc machine dependent files. + To acheive this goal, search for \<N_, sy_, symbol_new and symbolS. + . Allow an arbitrary number of segments (spare sections .ctor .dtor .bletch) + . Find a way to extend the debug information without breaking sdb + compatibility. Mainly intended for G++. + . should it do something to generate shared libraries objects ? + +I have tested this code on the following processor/os. gcc-1.37.1 was + used for all the tests. + +386 SCO unix ODT + gcc-1.37.1, gas, emacs-18.55 + +386 Esix rev C + gas-1.37/write.s + +386 Ix 2.02 + gas, all the X11R4 mit clients + +386 CTIX 3.2 + xsol (X11R4 solitary game), gas + +68030 unisoft 1.3 + the kernel (V.3.2) + tcp/ip extensions + bash-1.05, bison-1.11, compress-4.0, cproto, shar-3.49, diff-1.14, + dist-18.55, flex-2.3, gas-1.37, gcc-1.37.1, gdb-3.6, grep-1.5, + kermit, make-3.58, makedep, patch, printf, makeinfo, g++-1.37.1, + tar-1.08, texi2roff, uuencode, uutraf-1.2, libg++-1.37.2, groff-0.5 + +68020 sunos 3.5 (no, not coff, just to be sure that I didn't + introduce errors) + gcc-1.37.1, gas, emacs-18.55, gdb-3.6, bison-1.11, diff-1.14, + make-3.58, tar-1.08 + +68030 sunos 4.0.3 (idem) + gas + +I would be glad to hear about new experiences + + Loic (loic@adesign.uucp or loic@afp.uucp) + diff --git a/gnu/usr.bin/as/README.pic b/gnu/usr.bin/as/README.pic new file mode 100644 index 000000000000..adde6fe61981 --- /dev/null +++ b/gnu/usr.bin/as/README.pic @@ -0,0 +1,25 @@ +A few short notes on PIC support. + +. References to the symbol "_GLOBAL_OFFSET_TABLE_" are special. These always + PC relative to the start of the current instruction. Also, they occur + in "complex" expressions in function prologs, eg. + + move _GLOBAL_OFFSET_TABLE_ + (. - L1 ), %some_register + + The expression parser can't handle these generically, so the expression + above is recognised as a special case. + +. Some archs have special PIC assembler syntax to reference static and global + data. This is handled in targ-cpu.c. + +. Correct relocation_info must be output (eg. fields r_jmptable and r_baserel). + +. Internal labels must be output in the symbol table if they are referred to + by PIC instructions. The linker must allocate a GOT slot for them. + +. The former meaning of the -k switch ("WORKING_DOT" stuff), has been nuked + in favour of enabling PIC code recognition. + + +-pk + diff --git a/gnu/usr.bin/as/README.rich b/gnu/usr.bin/as/README.rich new file mode 100644 index 000000000000..5a2ecc455dcf --- /dev/null +++ b/gnu/usr.bin/as/README.rich @@ -0,0 +1,144 @@ +(This file is under construction.) + + + The Code Pedigree of This Directory + + +This directory contains a big merge of several development lines of +gas as well as a few bug fixes and some configuration that I've added +in order to retain my own sanity. + +A little history. + +The only common baseline of all versions was gas-1.31. + +From 1.31, Intel branched off and added: + + support for the Intel 80960 (i960) processor. + support for b.out object files. + some bug fixes. + sloppy mac MPW support + Intel gnu/960 makefiles and version numbering. + +Many of the bug fixes found their way into the main development line +prior to 1.36. ALL intel changes were ifdef'd I80960. This was good +as it isolated the changes, but bad in that it connected the b.out +support to the i960 support, and bad in that the bug fixes were only +active in the i960+b.out executables of gas, (although most of these +were nicely marked with comments indicating that they were probably +general bug fixes.) + +To pick up the main FSF development line again, along the way to 1.36, +several new processors were added, many bugs fixed, and the world was +a somewhat better place in general. + +From gas-1.36, Loic at Axis Design (france!) encapsulated object +format specific actions, added coff versions of those encapsulations, +and a config.gas style configuration and Makefile. This was a big +change and a lot of work. + +Then along came the FIRST FSF release of gas-1.37. I say this because +there have been at least two releases of gas-1.37. Only two of them +do we care about for this story, so let's call them gas-1.37.1 and +gas-1.37.2. + +Here starts the confusion. Firstly, gas-1.37.1 did not compile. + +In the meantime, John Gilmore at Cygnus Support had been hacking +gas-1.37.1. He got it to compile. He added support for the AMD 29000 +processor. AND he started encapsulating some of the a.out specific +pieces of code mostly into functions. AND he rebuilt the relocation +info to be generic. AND he restructured somewhat so that for a single +host, cross assemblers could be built for all targets in the same +directory. Useful work but a considerable nuisance because the a29k +changes were not partitioned from the encapsulation changes, the +encapsulation changes were incomplete, and the encapsulation required +functions where alternate structuring might have used macros. Let's +call this version gas-1.37.1+a29k. + +By the time gas-1.37.2 was "released", (remember that it TOO was +labelled by FSF as gas-1.37), it compiled, but it also added i860 +support and ansi style const declarations. + +At this point, Loic rolled his changes into gas-1.37.2. + +What I've done. + +I collected all the stray versions of gas that sounded relevant to my +goals of cross assembly and alternate object file formats and the FSF +releases from which the stray versions had branched. + +I rolled the Intel i960 changes from 1.31 into versions that I call +1.34+i960, 1.36+i960, and then 1.37.1+i960. + +Then I merged 1.37.1+i960 with 1.37.1+a29k to produce what I call +1.37.1+i960+a29k or 1.37.3. + +From 1.37.3, I pulled in Loic's stuff. This wasn't easy as Loic's +stuff hit all the same points as John's encapsulations. Loic's goal +was to split the a.out from coff dependancies for native assembly on +coff, while John's was to split for multiple cross assembly from a +single host. + +Loic's config arranged files much like emacs into m-*, etc. I've +rearranged these somewhat. + +Theory: + +The goal of the new configuration scheme is to bury all object format, +target processor, and host machine dependancies in object, target, and +host specific files. That is, to move all #ifdef's out of the gas +common code. + +Here's how it works. There is a .h and a .c file for each object file +format, a .h and a .c file for each target processor, and a .h for +each host. config.gas creates {sym}links in the current directory to +the appropriate files in the config directory. config.gas also serves +as a list of triplets {host, target, object-format} that have been +tested at one time or another. I also recommend that config.gas be +used to document triplet specific notes as to purpose of the triplet, +etc. + +Implementation: + +host.h is a {sym}link to .../config/xm-yourhost.h. It is intended to +be used to hide host compiler, system header file, and system library +differences between host machines. If your host needs actual c source +files, then either: these are generally useful functions, in which +case you should probably build a local library outside of the gas +source tree, or someone, perhaps me, is confused about what is needed +by different hosts. + +obj-format.h is a {sym}link to .../config/obj-something.h. It is intended + +All gas .c files include as.h. + +as.h #define's "gas", includes host.h, defines a number of gas +specific structures and types, and then includes tp.h, obj.h, and +target-environment.h. + +target-environment.h defines a target environment specific +preprocessor flag, eg, TE_SUN, and then includes obj-format.h. + +obj-format.h defines an object format specific preprocessor flag, eg, +OBJ_AOUT, OBJ_BOUT, OBJ_COFF, includes "target-processor.h", and then +defines the object specific macros, functions, types, and structures. + +target-processor.h + +target-processor. + +Porting: + +There appear to be four major types of ports; new hosts, new target +processors, new object file formats, and new target environments. + + +----- + +reloc now stored internally as generic. (symbols too?) (segment types +vs. names?) + +I don't mean to overlook anyone here. There have also been several +other development lines here that I looked at and elected to bypass. +Specifically, xxx's stabs in coff stuff was particularly tempting. diff --git a/gnu/usr.bin/as/VERSION b/gnu/usr.bin/as/VERSION new file mode 100644 index 000000000000..a3f79bbc6ff9 --- /dev/null +++ b/gnu/usr.bin/as/VERSION @@ -0,0 +1 @@ +1.92.3 diff --git a/gnu/usr.bin/as/app.c b/gnu/usr.bin/as/app.c new file mode 100644 index 000000000000..186944f8ed43 --- /dev/null +++ b/gnu/usr.bin/as/app.c @@ -0,0 +1,539 @@ +/* Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + Modified by Allen Wirfs-Brock, Instantiations Inc 2/90 + */ +/* This is the Assembler Pre-Processor + Copyright (C) 1987 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* App, the assembler pre-processor. This pre-processor strips out excess + spaces, turns single-quoted characters into a decimal constant, and turns + # <number> <filename> <garbage> into a .line <number>\n.app-file <filename> pair. + This needs better error-handling. + */ +#ifndef lint +static char rcsid[] = "$Id: app.c,v 1.2 1993/11/03 00:51:05 paul Exp $"; +#endif + +#include <stdio.h> +#include "as.h" /* For BAD_CASE() only */ + +#if (__STDC__ != 1) && !defined(const) +#define const /* Nothing */ +#endif + +static char lex[256]; +static char symbol_chars[] = + "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +/* These will go in BSS if not defined elsewhere, producing empty strings. */ +extern const char comment_chars[]; +extern const char line_comment_chars[]; +extern const char line_separator_chars[]; + +#define LEX_IS_SYMBOL_COMPONENT 1 +#define LEX_IS_WHITESPACE 2 +#define LEX_IS_LINE_SEPARATOR 3 +#define LEX_IS_COMMENT_START 4 +#define LEX_IS_LINE_COMMENT_START 5 +#define LEX_IS_TWOCHAR_COMMENT_1ST 6 +#define LEX_IS_TWOCHAR_COMMENT_2ND 7 +#define LEX_IS_STRINGQUOTE 8 +#define LEX_IS_COLON 9 +#define LEX_IS_NEWLINE 10 +#define LEX_IS_ONECHAR_QUOTE 11 +#define IS_SYMBOL_COMPONENT(c) (lex[c] == LEX_IS_SYMBOL_COMPONENT) +#define IS_WHITESPACE(c) (lex[c] == LEX_IS_WHITESPACE) +#define IS_LINE_SEPARATOR(c) (lex[c] == LEX_IS_LINE_SEPARATOR) +#define IS_COMMENT(c) (lex[c] == LEX_IS_COMMENT_START) +#define IS_LINE_COMMENT(c) (lex[c] == LEX_IS_LINE_COMMENT_START) +#define IS_NEWLINE(c) (lex[c] == LEX_IS_NEWLINE) + +/* FIXME-soon: The entire lexer/parser thingy should be + built statically at compile time rather than dynamically + each and every time the assembler is run. xoxorich. */ + +void do_scrub_begin() { + const char *p; + + lex[' '] = LEX_IS_WHITESPACE; + lex['\t'] = LEX_IS_WHITESPACE; + lex['\n'] = LEX_IS_NEWLINE; + lex[';'] = LEX_IS_LINE_SEPARATOR; + lex['"'] = LEX_IS_STRINGQUOTE; + lex['\''] = LEX_IS_ONECHAR_QUOTE; + lex[':'] = LEX_IS_COLON; + + /* Note that these override the previous defaults, e.g. if ';' + is a comment char, then it isn't a line separator. */ + for (p = symbol_chars; *p; ++p) { + lex[*p] = LEX_IS_SYMBOL_COMPONENT; + } /* declare symbol characters */ + + for (p = line_comment_chars; *p; p++) { + lex[*p] = LEX_IS_LINE_COMMENT_START; + } /* declare line comment chars */ + + for (p = comment_chars; *p; p++) { + lex[*p] = LEX_IS_COMMENT_START; + } /* declare comment chars */ + + for (p = line_separator_chars; *p; p++) { + lex[*p] = LEX_IS_LINE_SEPARATOR; + } /* declare line separators */ + + /* Only allow slash-star comments if slash is not in use */ + if (lex['/'] == 0) { + lex['/'] = LEX_IS_TWOCHAR_COMMENT_1ST; + } + /* FIXME-soon. This is a bad hack but otherwise, we + can't do c-style comments when '/' is a line + comment char. xoxorich. */ + if (lex['*'] == 0) { + lex['*'] = LEX_IS_TWOCHAR_COMMENT_2ND; + } +} /* do_scrub_begin() */ + +FILE *scrub_file; + +int scrub_from_file() { + return getc(scrub_file); +} + +void scrub_to_file(ch) +int ch; +{ + ungetc(ch,scrub_file); +} /* scrub_to_file() */ + +char *scrub_string; +char *scrub_last_string; + +int scrub_from_string() { + return scrub_string == scrub_last_string ? EOF : *scrub_string++; +} /* scrub_from_string() */ + +void scrub_to_string(ch) +int ch; +{ + *--scrub_string=ch; +} /* scrub_to_string() */ + +/* Saved state of the scrubber */ +static int state; +static int old_state; +static char *out_string; +static char out_buf[20]; +static int add_newlines = 0; + +/* Data structure for saving the state of app across #include's. Note that + app is called asynchronously to the parsing of the .include's, so our + state at the time .include is interpreted is completely unrelated. + That's why we have to save it all. */ + +struct app_save { + int state; + int old_state; + char *out_string; + char out_buf[sizeof (out_buf)]; + int add_newlines; + char *scrub_string; + char *scrub_last_string; + FILE *scrub_file; +}; + +char *app_push() { + register struct app_save *saved; + + saved = (struct app_save *) xmalloc(sizeof (*saved)); + saved->state = state; + saved->old_state = old_state; + saved->out_string = out_string; + memcpy(out_buf, saved->out_buf, sizeof(out_buf)); + saved->add_newlines = add_newlines; + saved->scrub_string = scrub_string; + saved->scrub_last_string = scrub_last_string; + saved->scrub_file = scrub_file; + + /* do_scrub_begin() is not useful, just wastes time. */ + return (char *)saved; +} + +void app_pop(arg) +char *arg; +{ + register struct app_save *saved = (struct app_save *)arg; + + /* There is no do_scrub_end (). */ + state = saved->state; + old_state = saved->old_state; + out_string = saved->out_string; + memcpy(saved->out_buf, out_buf, sizeof (out_buf)); + add_newlines = saved->add_newlines; + scrub_string = saved->scrub_string; + scrub_last_string = saved->scrub_last_string; + scrub_file = saved->scrub_file; + + free (arg); +} /* app_pop() */ + +int do_scrub_next_char(get,unget) +int (*get)(); +void (*unget)(); +{ + /*State 0: beginning of normal line + 1: After first whitespace on line (flush more white) + 2: After first non-white (opcode) on line (keep 1white) + 3: after second white on line (into operands) (flush white) + 4: after putting out a .line, put out digits + 5: parsing a string, then go to old-state + 6: putting out \ escape in a "d string. + 7: After putting out a .app-file, put out string. + 8: After putting out a .app-file string, flush until newline. + -1: output string in out_string and go to the state in old_state + -2: flush text until a '*' '/' is seen, then go to state old_state + */ + + register int ch, ch2 = 0; + + switch (state) { + case -1: + ch= *out_string++; + if (*out_string == 0) { + state=old_state; + old_state=3; + } + return ch; + + case -2: + for (;;) { + do { + ch=(*get)(); + } while (ch != EOF && ch != '\n' && ch != '*'); + if (ch == '\n' || ch == EOF) + return ch; + + /* At this point, ch must be a '*' */ + while ( (ch=(*get)()) == '*' ){ + ; + } + if (ch == EOF || ch == '/') + break; + (*unget)(ch); + } + state=old_state; + return ' '; + + case 4: + ch=(*get)(); + if (ch == EOF || (ch >= '0' && ch <= '9')) + return ch; + else { + while (ch != EOF && IS_WHITESPACE(ch)) + ch=(*get)(); + if (ch == '"') { + (*unget)(ch); + out_string="\n.app-file "; + old_state=7; + state= -1; + return *out_string++; + } else { + while (ch != EOF && ch != '\n') + ch=(*get)(); + return ch; + } + } + + case 5: + ch=(*get)(); + if (ch == '"') { + state=old_state; + return '"'; + } else if (ch == '\\') { + state=6; + return ch; + } else if (ch == EOF) { + as_warn("End of file in string: inserted '\"'"); + state=old_state; + (*unget)('\n'); + return '"'; + } else { + return ch; + } + + case 6: + state=5; + ch=(*get)(); + switch (ch) { + /* This is neet. Turn "string + more string" into "string\n more string" + */ + case '\n': + (*unget)('n'); + add_newlines++; + return '\\'; + + case '"': + case '\\': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': +#ifdef BACKSLASH_V + case 'v': +#endif /* BACKSLASH_V */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + break; + +#ifdef ONLY_STANDARD_ESCAPES + default: + as_warn("Unknown escape '\\%c' in string: Ignored",ch); + break; +#else /* ONLY_STANDARD_ESCAPES */ + default: + /* Accept \x as x for any x */ + break; +#endif /* ONLY_STANDARD_ESCAPES */ + + case EOF: + as_warn("End of file in string: '\"' inserted"); + return '"'; + } + return ch; + + case 7: + ch=(*get)(); + state=5; + old_state=8; + return ch; + + case 8: + do ch= (*get)(); + while (ch != '\n'); + state=0; + return ch; + } + + /* OK, we are somewhere in states 0 through 4 */ + + /* flushchar: */ + ch=(*get)(); + recycle: + if (ch == EOF) { + if (state != 0) + as_warn("End of file not at end of a line: Newline inserted."); + return ch; + } + + switch (lex[ch]) { + case LEX_IS_WHITESPACE: + do ch=(*get)(); + while (ch != EOF && IS_WHITESPACE(ch)); + if (ch == EOF) + return ch; + if (IS_COMMENT(ch) || (state == 0 && IS_LINE_COMMENT(ch)) || ch == '/' || IS_LINE_SEPARATOR(ch)) { + goto recycle; + } + switch (state) { + case 0: state++; goto recycle; /* Punted leading sp */ + case 1: BAD_CASE(state); /* We can't get here */ + case 2: state++; (*unget)(ch); return ' '; /* Sp after opco */ + case 3: goto recycle; /* Sp in operands */ + default: BAD_CASE(state); + } + break; + + case LEX_IS_TWOCHAR_COMMENT_1ST: + ch2=(*get)(); + if (ch2 != EOF && lex[ch2] == LEX_IS_TWOCHAR_COMMENT_2ND) { + for (;;) { + do { + ch2=(*get)(); + if (ch2 != EOF && IS_NEWLINE(ch2)) + add_newlines++; + } while (ch2 != EOF && + (lex[ch2] != LEX_IS_TWOCHAR_COMMENT_2ND)); + + while (ch2 != EOF && + (lex[ch2] == LEX_IS_TWOCHAR_COMMENT_2ND)){ + ch2=(*get)(); + } + + if (ch2 == EOF + || lex[ch2] == LEX_IS_TWOCHAR_COMMENT_1ST) + break; + (*unget)(ch); + } + if (ch2 == EOF) + as_warn("End of file in multiline comment"); + + ch = ' '; + goto recycle; + } else { + if (ch2 != EOF) + (*unget)(ch2); + return ch; + } + break; + + case LEX_IS_STRINGQUOTE: + old_state=state; + state=5; + return ch; + +#ifndef IEEE_STYLE + case LEX_IS_ONECHAR_QUOTE: + ch=(*get)(); + if (ch == EOF) { + as_warn("End-of-file after a one-character quote; \000 inserted"); + ch=0; + } + sprintf(out_buf,"%d", (int)(unsigned char)ch); + + /* None of these 'x constants for us. We want 'x'. + */ + if ( (ch=(*get)()) != '\'' ) { +#ifdef REQUIRE_CHAR_CLOSE_QUOTE + as_warn("Missing close quote: (assumed)"); +#else + (*unget)(ch); +#endif + } + + old_state=state; + state= -1; + out_string=out_buf; + return *out_string++; +#endif + case LEX_IS_COLON: + if (state != 3) + state=0; + return ch; + + case LEX_IS_NEWLINE: + /* Roll out a bunch of newlines from inside comments, etc. */ + if (add_newlines) { + --add_newlines; + (*unget)(ch); + } + /* fall thru into... */ + + case LEX_IS_LINE_SEPARATOR: + state=0; + return ch; + + case LEX_IS_LINE_COMMENT_START: + if (state != 0) /* Not at start of line, act normal */ + goto de_fault; + + /* FIXME-someday: The two character comment stuff was badly + thought out. On i386, we want '/' as line comment start + AND we want C style comments. hence this hack. The + whole lexical process should be reworked. xoxorich. */ + + if (ch == '/' && (ch2 = (*get)()) == '*') { + state = -2; + return(do_scrub_next_char(get, unget)); + } else { + (*unget)(ch2); + } /* bad hack */ + + do ch=(*get)(); + while (ch != EOF && IS_WHITESPACE(ch)); + if (ch == EOF) { + as_warn("EOF in comment: Newline inserted"); + return '\n'; + } + if (ch<'0' || ch>'9') { + /* Non-numerics: Eat whole comment line */ + while (ch != EOF && !IS_NEWLINE(ch)) + ch=(*get)(); + if (ch == EOF) + as_warn("EOF in Comment: Newline inserted"); + state=0; + return '\n'; + } + /* Numerics begin comment. Perhaps CPP `# 123 "filename"' */ + (*unget)(ch); + old_state=4; + state= -1; + out_string=".line "; + return *out_string++; + + case LEX_IS_COMMENT_START: + do ch=(*get)(); + while (ch != EOF && !IS_NEWLINE(ch)); + if (ch == EOF) + as_warn("EOF in comment: Newline inserted"); + state=0; + return '\n'; + + default: + de_fault: + /* Some relatively `normal' character. */ + if (state == 0) { + state=2; /* Now seeing opcode */ + return ch; + } else if (state == 1) { + state=2; /* Ditto */ + return ch; + } else { + return ch; /* Opcode or operands already */ + } + } + return -1; +} + +#ifdef TEST + +char comment_chars[] = "|"; +char line_comment_chars[] = "#"; + +main() +{ + int ch; + + app_begin(); + while ((ch=do_scrub_next_char(stdin)) != EOF) + putc(ch,stdout); +} + +as_warn(str) +char *str; +{ + fputs(str,stderr); + putc('\n',stderr); +} +#endif + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of app.c */ diff --git a/gnu/usr.bin/as/as.1 b/gnu/usr.bin/as/as.1 new file mode 100644 index 000000000000..57e2dc1f9b9e --- /dev/null +++ b/gnu/usr.bin/as/as.1 @@ -0,0 +1,271 @@ +.\" Copyright (c) 1991, 1992 Free Software Foundation +.\" See section COPYING for conditions for redistribution +.TH as 1 "21 January 1992" "cygnus support" "GNU Development Tools" + +.SH NAME +GNU as \- the portable GNU assembler. + +.SH SYNOPSIS +.na +.B as +.RB "[\|" \-a "\||\|" \-al "\||\|" -as\c +\&\|] +.RB "[\|" \-D "\|]" +.RB "[\|" \-f "\|]" +.RB "[\|" \-I +.I path\c +\&\|] +.RB "[\|" \-k "\|]" +.RB "[\|" \-L "\|]" +.RB "[\|" \-o +.I objfile\c +\&\|] +.RB "[\|" \-R "\|]" +.RB "[\|" \-v "\|]" +.RB "[\|" \-w "\|]" +.RB "[\|" \-\^\- "\ |\ " \c +.I files\c +\&\|.\|.\|.\|] + +.I i960-only options: +.br +.RB "[\|" \-ACA "\||\|" \-ACA_A "\||\|" \-ACB\c +.RB "\||\|" \-ACC "\||\|" \-AKA "\||\|" \-AKB\c +.RB "\||\|" \-AKC "\||\|" \-AMC "\|]" +.RB "[\|" \-b "\|]" +.RB "[\|" \-norelax "\|]" + +.I m680x0-only options: +.br +.RB "[\|" \-l "\|]" +.RB "[\|" \-mc68000 "\||\|" \-mc68010 "\||\|" \-mc68020 "\|]" +.ad b + +.SH DESCRIPTION +GNU \c +.B as\c +\& is really a family of assemblers. +If you use (or have used) the GNU assembler on one architecture, you +should find a fairly similar environment when you use it on another +architecture. Each version has much in common with the others, +including object file formats, most assembler directives (often called +\c +.I pseudo-ops)\c +\& and assembler syntax. + +For information on the syntax and pseudo-ops used by GNU \c +.B as\c +\&, see `\|\c +.B as\c +\|' entry in \c +.B info \c +(or the manual \c +.I +.I +Using as: The GNU Assembler\c +\&). + +\c +.B as\c +\& is primarily intended to assemble the output of the GNU C +compiler \c +.B gcc\c +\& for use by the linker \c +.B ld\c +\&. Nevertheless, +we've tried to make \c +.B as\c +\& assemble correctly everything that the native +assembler would. +This doesn't mean \c +.B as\c +\& always uses the same syntax as another +assembler for the same architecture; for example, we know of several +incompatible versions of 680x0 assembly language syntax. + +Each time you run \c +.B as\c +\& it assembles exactly one source +program. The source program is made up of one or more files. +(The standard input is also a file.) + +If \c +.B as\c +\& is given no file names it attempts to read one input file +from the \c +.B as\c +\& standard input, which is normally your terminal. You +may have to type \c +.B ctl-D\c +\& to tell \c +.B as\c +\& there is no more program +to assemble. Use `\|\c +.B \-\^\-\c +\|' if you need to explicitly name the standard input file +in your command line. + +.B as\c +\& may write warnings and error messages to the standard error +file (usually your terminal). This should not happen when \c +.B as\c +\& is +run automatically by a compiler. Warnings report an assumption made so +that \c +.B as\c +\& could keep assembling a flawed program; errors report a +grave problem that stops the assembly. + +.SH OPTIONS +.TP +.BR \-a \||\| \-al \||\| \-as +Turn on assembly listings; `\|\c +.B \-al\c +\&\|', listing only, `\|\c +.B \-as\c +\&\|', symbols +only, `\|\c +.B \-a\c +\&\|', everything. +.TP +.B \-D +This option is accepted only for script compatibility with calls to +other assemblers; it has no effect on \c +.B as\c +\&. +.TP +.B \-f +``fast''--skip preprocessing (assume source is compiler output). +.TP +.BI "\-I\ " path +Add +.I path +to the search list for +.B .include +directives. +.TP +.B \-k +Handle position independent code, generated by gcc -fpic. +.TP +.B \-L +Keep (in symbol table) local symbols, starting with `\|\c +.B L\c +\|' +.TP +.BI "\-o\ " objfile +Name the object-file output from \c +.B as +.TP +.B \-R +Fold data section into text section +.TP +.B \-v +Announce \c +.B as\c +\& version +.TP +.B \-W +Suppress warning messages +.TP +.IR "\-\^\-" "\ |\ " "files\|.\|.\|." +Source files to assemble, or standard input (\c +.BR "\-\^\-" ")" +.TP +.BI \-A var +.I +(When configured for Intel 960.) +Specify which variant of the 960 architecture is the target. +.TP +.B \-b +.I +(When configured for Intel 960.) +Add code to collect statistics about branches taken. +.TP +.B \-norelax +.I +(When configured for Intel 960.) +Do not alter compare-and-branch instructions for long displacements; +error if necessary. +.TP +.B \-l +.I +(When configured for Motorola 68000). +.br +Shorten references to undefined symbols, to one word instead of two. +.TP +.BR "\-mc68000" "\||\|" "\-mc68010" "\||\|" "\-mc68020" +.I +(When configured for Motorola 68000). +.br +Specify what processor in the 68000 family is the target (default 68020) + +.PP +Options may be in any order, and may be +before, after, or between file names. The order of file names is +significant. + +`\|\c +.B \-\^\-\c +\|' (two hyphens) by itself names the standard input file +explicitly, as one of the files for \c +.B as\c +\& to assemble. + +Except for `\|\c +.B \-\^\-\c +\|' any command line argument that begins with a +hyphen (`\|\c +.B \-\c +\|') is an option. Each option changes the behavior of +\c +.B as\c +\&. No option changes the way another option works. An +option is a `\|\c +.B \-\c +\|' followed by one or more letters; the case of +the letter is important. All options are optional. + +The `\|\c +.B \-o\c +\|' option expects exactly one file name to follow. The file +name may either immediately follow the option's letter (compatible +with older assemblers) or it may be the next command argument (GNU +standard). + +These two command lines are equivalent: +.br +.B +as\ \ \-o\ \ my\-object\-file.o\ \ mumble.s +.br +.B +as\ \ \-omy\-object\-file.o\ \ mumble.s + +.SH "SEE ALSO" +.RB "`\|" as "\|'" +entry in +.B +info\c +\&; +.I +Using as: The GNU Assembler\c +\&; +.BR gcc "(" 1 ")," +.BR ld "(" 1 ")." + +.SH COPYING +Copyright (c) 1991, 1992 Free Software Foundation, Inc. +.PP +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. +.PP +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. +.PP +Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be included in +translations approved by the Free Software Foundation instead of in +the original English. diff --git a/gnu/usr.bin/as/as.c b/gnu/usr.bin/as/as.c new file mode 100644 index 000000000000..909bd066a773 --- /dev/null +++ b/gnu/usr.bin/as/as.c @@ -0,0 +1,429 @@ +/* as.c - GAS main program. + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 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. + * + */ +#ifndef lint +static char rcsid[] = "$Id: as.c,v 1.2 1993/11/03 00:51:09 paul Exp $"; +#endif + +#include <stdio.h> +#include <string.h> + +#ifdef _POSIX_SOURCE +#include <sys/types.h> /* For pid_t in signal.h */ +#endif +#include <signal.h> + +#define COMMON + +#include "as.h" +#include "subsegs.h" +#if __STDC__ == 1 + +/* This prototype for got_sig() is ansi. If you want + anything else, then your compiler is lying to you when + it says that it is __STDC__. If you want to change it, + #ifdef protect it from those of us with real ansi + compilers. */ + +#define SIGTY void + +static void got_sig(int sig); +static char *stralloc(char *str); +static void perform_an_assembly_pass(int argc, char **argv); + +#else /* __STDC__ */ + +#ifndef SIGTY +#define SIGTY int +#endif + +static SIGTY got_sig(); +static char *stralloc(); /* Make a (safe) copy of a string. */ +static void perform_an_assembly_pass(); + +#endif /* not __STDC__ */ + +#ifdef DONTDEF +static char * gdb_symbol_file_name; +long gdb_begin(); +#endif + +int listing; /* true if a listing is wanted */ + +char *myname; /* argv[0] */ +extern const char version_string[]; + +int main(argc,argv) +int argc; +char **argv; +{ + int work_argc; /* variable copy of argc */ + char **work_argv; /* variable copy of argv */ + char *arg; /* an arg to program */ + char a; /* an arg flag (after -) */ + static const int sig[] = { SIGHUP, SIGINT, SIGPIPE, SIGTERM, 0}; + + for (a=0;sig[a] != 0;a++) + if (signal(sig[a], SIG_IGN) != SIG_IGN) + signal(sig[a], got_sig); + + myname=argv[0]; + memset(flagseen, '\0', sizeof(flagseen)); /* aint seen nothing yet */ +#ifndef OBJ_DEFAULT_OUTPUT_FILE_NAME +#define OBJ_DEFAULT_OUTPUT_FILE_NAME "a.out" +#endif /* OBJ_DEFAULT_OUTPUT_FILE_NAME */ + out_file_name = OBJ_DEFAULT_OUTPUT_FILE_NAME; + + symbol_begin(); /* symbols.c */ + subsegs_begin(); /* subsegs.c */ + read_begin(); /* read.c */ + md_begin(); /* MACHINE.c */ + input_scrub_begin(); /* input_scrub.c */ +#ifdef DONTDEF + gdb_symbol_file_name = 0; +#endif + /* + * Parse arguments, but we are only interested in flags. + * When we find a flag, we process it then make it's argv[] NULL. + * This helps any future argv[] scanners avoid what we processed. + * Since it is easy to do here we interpret the special arg "-" + * to mean "use stdin" and we set that argv[] pointing to "". + * After we have munged argv[], the only things left are source file + * name(s) and ""(s) denoting stdin. These file names are used + * (perhaps more than once) later. + */ + /* FIXME-SOMEDAY this should use getopt. */ + work_argc = argc-1; /* don't count argv[0] */ + work_argv = argv+1; /* skip argv[0] */ + for (;work_argc--;work_argv++) { + arg = * work_argv; /* work_argv points to this argument */ + + if (*arg != '-') /* Filename. We need it later. */ + continue; /* Keep scanning args looking for flags. */ + if (arg[1] == '-' && arg[2] == 0) { + /* "--" as an argument means read STDIN */ + /* on this scan, we don't want to think about filenames */ + * work_argv = ""; /* Code that means 'use stdin'. */ + continue; + } + /* This better be a switch. */ + arg ++; /*->letter. */ + + while ((a = * arg) != '\0') {/* scan all the 1-char flags */ + arg ++; /* arg->after letter. */ + a &= 0x7F; /* ascii only please */ + /* if (flagseen[a]) + as_tsktsk("%s: Flag option - %c has already been seen.", myname, a); */ + flagseen[a] = 1; + switch (a) { + + case 'a': + { + int loop =1; + + while (loop) { + switch (*arg) + { + case 'l': + listing |= LISTING_LISTING; + arg++; + break; + case 's': + listing |= LISTING_SYMBOLS; + arg++; + break; + case 'h': + listing |= LISTING_HLL; + arg++; + break; + + case 'n': + listing |= LISTING_NOFORM; + arg++; + break; + case 'd': + listing |= LISTING_NODEBUG; + arg++; + break; + default: + if (!listing) + listing= LISTING_DEFAULT; + loop = 0; + break; + } + } + } + + break; + + + case 'f': + break; /* -f means fast - no need for "app" preprocessor. */ + + case 'D': + /* DEBUG is implemented: it debugs different */ + /* things to other people's assemblers. */ + break; + +#ifdef DONTDEF + case 'G': /* GNU AS switch: include gdbsyms. */ + if (*arg) /* Rest of argument is file-name. */ + gdb_symbol_file_name = stralloc (arg); + else if (work_argc) { /* Next argument is file-name. */ + work_argc --; + * work_argv = NULL; /* Not a source file-name. */ + gdb_symbol_file_name = * ++ work_argv; + } else + as_warn("%s: I expected a filename after -G", myname); + arg = ""; /* Finished with this arg. */ + break; +#endif + + case 'I': { /* Include file directory */ + + char *temp = NULL; + if (*arg) + temp = stralloc (arg); + else if (work_argc) { + * work_argv = NULL; + work_argc--; + temp = * ++ work_argv; + } else + as_warn("%s: I expected a filename after -I", myname); + add_include_dir (temp); + arg = ""; /* Finished with this arg. */ + break; + } + +#if 00000 + 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 OBJ_VMS + { + extern char *compiler_version_string; + compiler_version_string = arg; + } +#else /* not OBJ_VMS */ + fprintf(stderr,version_string); + if (*arg && strcmp(arg,"ersion")) + as_warn("Unknown -v option ignored"); +#endif /* not OBJ_VMS */ + while (*arg) arg++; /* Skip the rest */ + break; + + case 'W': + /* -W means don't warn about things */ + case 'X': + /* -X means treat warnings as errors */ + case 'Z': + /* -Z means attempt to generate object file even after errors. */ + break; + + default: + --arg; + if (md_parse_option(&arg,&work_argc,&work_argv) == 0) + as_warn("%s: I don't understand '%c' flag.", myname, a); + if (arg && *arg) + arg++; + break; + } + } + /* + * We have just processed a "-..." arg, which was not a + * file-name. Smash it so the + * things that look for filenames won't ever see it. + * + * Whatever work_argv points to, it has already been used + * as part of a flag, so DON'T re-use it as a filename. + */ + *work_argv = NULL; /* NULL means 'not a file-name' */ + } +#ifdef DONTDEF + if (gdb_begin(gdb_symbol_file_name) == 0) + flagseen['G'] = 0; /* Don't do any gdbsym stuff. */ +#endif + /* Here with flags set up in flagseen[]. */ + + perform_an_assembly_pass(argc,argv); /* Assemble it. */ +#ifdef TC_I960 + brtab_emit(); +#endif + if (seen_at_least_1_file() + && !((had_warnings() && flagseen['Z']) + || had_errors() > 0)) { + write_object_file(); /* relax() addresses then emit object file */ + } /* we also check in write_object_file() just before emit. */ + + input_scrub_end(); + md_end(); /* MACHINE.c */ + +#ifndef NO_LISTING + listing_print(""); +#endif + +#ifndef HO_VMS + return((had_warnings() && flagseen['Z']) + || had_errors() > 0); /* WIN */ +#else /* HO_VMS */ + return(!((had_warnings() && flagseen['Z']) + || had_errors() > 0)); /* WIN */ +#endif /* HO_VMS */ + +} /* main() */ + + +/* perform_an_assembly_pass() + * + * Here to attempt 1 pass over each input file. + * We scan argv[*] looking for filenames or exactly "" which is + * shorthand for stdin. Any argv that is NULL is not a file-name. + * We set need_pass_2 TRUE if, after this, we still have unresolved + * expressions of the form (unknown value)+-(unknown value). + * + * Note the un*x semantics: there is only 1 logical input file, but it + * may be a catenation of many 'physical' input files. + */ +static void perform_an_assembly_pass(argc, argv) +int argc; +char **argv; +{ + int saw_a_file = 0; + need_pass_2 = 0; + +#ifdef MANY_SEGMENTS + unsigned int i; + + for (i= SEG_E0; i < SEG_UNKNOWN; i++) + { + segment_info[i].fix_root = 0; + } + /* Create the three fixed ones */ + subseg_new (SEG_E0, 0); + subseg_new (SEG_E1, 0); + subseg_new (SEG_E2, 0); + strcpy(segment_info[SEG_E0].scnhdr.s_name,".text"); + strcpy(segment_info[SEG_E1].scnhdr.s_name,".data"); + strcpy(segment_info[SEG_E2].scnhdr.s_name,".bss"); + + subseg_new (SEG_E0, 0); +#else /* not MANY_SEGMENTS */ + text_fix_root = NULL; + data_fix_root = NULL; + bss_fix_root = NULL; + + subseg_new (SEG_TEXT, 0); +#endif /* not MANY_SEGMENTS */ + + argv++; /* skip argv[0] */ + argc--; /* skip argv[0] */ + while (argc--) { + if (*argv) { /* Is it a file-name argument? */ + saw_a_file++; + /* argv->"" if stdin desired, else->filename */ + read_a_source_file(*argv); + } + argv++; /* completed that argv */ + } + if (!saw_a_file) + read_a_source_file(""); +} /* perform_an_assembly_pass() */ + +/* + * stralloc() + * + * Allocate memory for a new copy of a string. Copy the string. + * Return the address of the new string. Die if there is any error. + */ + +static char * + stralloc (str) +char * str; +{ + register char * retval; + register long len; + + len = strlen (str) + 1; + retval = xmalloc (len); + (void) strcpy(retval, str); + return(retval); +} + +#ifdef comment +static void lose() { + as_fatal("%s: 2nd pass not implemented - get your code from random(3)", myname); + return; +} /* lose() */ +#endif /* comment */ + +static SIGTY + got_sig(sig) +int sig; +{ + static here_before = 0; + + as_bad("Interrupted by signal %d", sig); + if (here_before++) + exit(1); + return((SIGTY) 0); +} + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of as.c */ diff --git a/gnu/usr.bin/as/as.h b/gnu/usr.bin/as/as.h new file mode 100644 index 000000000000..f214453c4a3c --- /dev/null +++ b/gnu/usr.bin/as/as.h @@ -0,0 +1,416 @@ +/* as.h - global header file + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * $Id: as.h,v 1.2 1993/11/03 00:51:11 paul Exp $ + */ + +#define GAS 1 +/* #include <ansidecl.h> */ +#include "host.h" +#include "flonum.h" + +#if __STDC__ != 1 +#define volatile /**/ +#ifndef const +#define const /**/ +#endif /* const */ +#endif /* __STDC__ */ + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#define register +#endif /* __GNUC__ */ + +#ifndef __LINE__ +#define __LINE__ "unknown" +#endif /* __LINE__ */ + +#ifndef __FILE__ +#define __FILE__ "unknown" +#endif /* __FILE__ */ + +/* + * I think this stuff is largely out of date. xoxorich. + * + * CAPITALISED names are #defined. + * "lowercaseH" is #defined if "lowercase.h" has been #include-d. + * "lowercaseT" is a typedef of "lowercase" objects. + * "lowercaseP" is type "pointer to object of type 'lowercase'". + * "lowercaseS" is typedef struct ... lowercaseS. + * + * #define DEBUG to enable all the "know" assertion tests. + * #define SUSPECT when debugging. + * #define COMMON as "extern" for all modules except one, where you #define + * COMMON as "". + * If TEST is #defined, then we are testing a module: #define COMMON as "". + */ + +/* These #defines are for parameters of entire assembler. */ + +/* #define SUSPECT JF remove for speed testing */ +/* These #includes are for type definitions etc. */ + +#include <stdio.h> +#include <assert.h> +#include <string.h> + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free xfree + +#define xfree free + +#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 */ +#define DEBUG /* temporary */ + +#ifdef DEBUG +#undef NDEBUG +#ifndef know +#define know(p) assert(p) /* Verify our assumptions! */ +#endif /* not yet defined */ +#else +#define know(p) /* know() checks are no-op.ed */ +#endif + +/* input_scrub.c */ + +/* + * Supplies sanitised buffers to read.c. + * Also understands printing line-number part of error messages. + */ + + +/* subsegs.c Sub-segments. Also, segment(=expression type)s.*/ + +/* + * This table describes the use of segments as EXPRESSION types. + * + * X_seg X_add_symbol X_subtract_symbol X_add_number + * SEG_ABSENT no (legal) expression + * SEG_PASS1 no (defined) " + * SEG_BIG * > 32 bits const. + * SEG_ABSOLUTE 0 + * SEG_DATA * 0 + * SEG_TEXT * 0 + * SEG_BSS * 0 + * SEG_UNKNOWN * 0 + * SEG_DIFFERENCE 0 * 0 + * SEG_REGISTER * + * + * The blank fields MUST be 0, and are nugatory. + * The '0' fields MAY be 0. The '*' fields MAY NOT be 0. + * + * SEG_BIG: X_add_number is < 0 if the result is in + * generic_floating_point_number. The value is -'c' where c is the + * character that introduced the constant. e.g. "0f6.9" will have -'f' + * as a X_add_number value. + * X_add_number > 0 is a count of how many littlenums it took to + * represent a bignum. + * SEG_DIFFERENCE: + * If segments of both symbols are known, they are the same segment. + * X_add_symbol != X_sub_symbol (then we just cancel them, => SEG_ABSOLUTE). + */ + + +#ifdef MANY_SEGMENTS +#define N_SEGMENTS 10 +#define SEG_NORMAL(x) ((x) >= SEG_E0 && (x) <= SEG_E9) +#define SEG_LIST SEG_E0,SEG_E1,SEG_E2,SEG_E3,SEG_E4,SEG_E5,SEG_E6,SEG_E7,SEG_E8,SEG_E9 +#define SEG_DATA SEG_E1 +#define SEG_TEXT SEG_E0 +#define SEG_BSS SEG_E2 +#else +#define N_SEGMENTS 3 +#define SEG_NORMAL(x) ((x) == SEG_TEXT || (x) == SEG_DATA || (x) == SEG_BSS) +#define SEG_LIST SEG_TEXT,SEG_DATA,SEG_BSS +#endif + +typedef enum _segT { + SEG_ABSOLUTE = 0, + SEG_LIST, + SEG_UNKNOWN, + SEG_ABSENT, /* Mythical Segment (absent): NO expression seen. */ + SEG_PASS1, /* Mythical Segment: Need another pass. */ + SEG_GOOF, /* Only happens if AS has a logic error. */ + /* Invented so we don't crash printing */ + /* error message involving weird segment. */ + SEG_BIG, /* Bigger than 32 bits constant. */ + SEG_DIFFERENCE, /* Mythical Segment: absolute difference. */ + SEG_DEBUG, /* Debug segment */ + SEG_NTV, /* Transfert vector preload segment */ + SEG_PTV, /* Transfert vector postload segment */ + SEG_REGISTER, /* Mythical: a register-valued expression */ +} segT; + +#define SEG_MAXIMUM_ORDINAL (SEG_REGISTER) + +typedef int subsegT; + +COMMON subsegT now_subseg; +/* What subseg we are accreting now? */ + + +COMMON segT now_seg; +/* Segment our instructions emit to. */ +/* Only OK values are SEG_TEXT or SEG_DATA. */ + + +extern char *const seg_name[]; +extern int section_alignment[]; + + +/* relax() */ + +typedef enum _relax_state { + rs_fill, /* Variable chars to be repeated fr_offset times. Fr_symbol + unused. Used with fr_offset == 0 for a constant length + frag. */ + + rs_align, /* Align: Fr_offset: power of 2. 1 variable char: fill + character. */ + + rs_org, /* Org: Fr_offset, fr_symbol: address. 1 variable char: fill + character. */ + + rs_machine_dependent, + +#ifndef WORKING_DOT_WORD + rs_broken_word, /* JF: gunpoint */ +#endif +} relax_stateT; + +/* typedef unsigned char relax_substateT; */ +/* JF this is more likely to leave the end of a struct frag on an align + boundry. Be very careful with this. */ +typedef unsigned long relax_substateT; + +typedef unsigned long relax_addressT;/* Enough bits for address. */ +/* Still an integer type. */ + + +/* frags.c */ + +/* + * A code fragment (frag) is some known number of chars, followed by some + * unknown number of chars. Typically the unknown number of chars is an + * instruction address whose size is yet unknown. We always know the greatest + * possible size the unknown number of chars may become, and reserve that + * much room at the end of the frag. + * Once created, frags do not change address during assembly. + * We chain the frags in (a) forward-linked list(s). The object-file address + * of the 1st char of a frag is generally not known until after relax(). + * Many things at assembly time describe an address by {object-file-address + * of a particular frag}+offset. + + BUG: it may be smarter to have a single pointer off to various different + notes for different frag kinds. See how code pans + */ +struct frag /* a code fragment */ +{ + unsigned long fr_address; /* Object file address. */ + struct frag *fr_next; /* Chain forward; ascending address order. */ + /* Rooted in frch_root. */ + + long fr_fix; /* (Fixed) number of chars we know we have. */ + /* May be 0. */ + long fr_var; /* (Variable) number of chars after above. */ + /* May be 0. */ + struct symbol *fr_symbol; /* For variable-length tail. */ + long fr_offset; /* For variable-length tail. */ + char *fr_opcode; /*->opcode low addr byte,for relax()ation*/ + relax_stateT fr_type; /* What state is my tail in? */ + relax_substateT fr_subtype; + /* These are needed only on the NS32K machines */ + char fr_pcrel_adjust; + char fr_bsr; +#ifndef NO_LISTING + struct list_info_struct *line; +#endif + char fr_literal[1]; /* Chars begin here. */ + /* One day we will compile fr_literal[0]. */ +}; +#define SIZEOF_STRUCT_FRAG \ +((int)zero_address_frag.fr_literal-(int)&zero_address_frag) +/* We want to say fr_literal[0] above. */ + +typedef struct frag fragS; + +COMMON fragS *frag_now; /* -> current frag we are building. */ +/* This frag is incomplete. */ +/* It is, however, included in frchain_now. */ +/* Frag_now->fr_fix is bogus. Use: */ +/* Virtual frag_now->fr_fix == obstack_next_free(&frags)-frag_now->fr_literal.*/ + +COMMON fragS zero_address_frag; /* For foreign-segment symbol fixups. */ +COMMON fragS bss_address_frag; /* For local common (N_BSS segment) fixups. */ + +/* main program "as.c" (command arguments etc) */ + +COMMON char + flagseen[128]; /* ['x'] TRUE if "-x" seen. */ + +COMMON char * + out_file_name; /* name of emitted object file */ + +COMMON int need_pass_2; /* TRUE if we need a second pass. */ + +typedef struct { + char * poc_name; /* assembler mnemonic, lower case, no '.' */ + void (*poc_handler)(); /* Do the work */ + int poc_val; /* Value to pass to handler */ +} pseudo_typeS; + +#if (__STDC__ == 1) & !defined(NO_STDARG) + +int had_errors(void); +int had_warnings(void); +void as_bad(const char *Format, ...); +void as_fatal(const char *Format, ...); +void as_tsktsk(const char *Format, ...); +void as_warn(const char *Format, ...); + +#else + +int had_errors(); +int had_warnings(); +void as_bad(); +void as_fatal(); +void as_tsktsk(); +void as_warn(); + +#endif /* __STDC__ & !NO_STDARG */ + +#if __STDC__ == 1 + +char *app_push(void); +char *atof_ieee(char *str, int what_kind, LITTLENUM_TYPE *words); +char *input_scrub_include_file(char *filename, char *position); +char *input_scrub_new_file(char *filename); +char *input_scrub_next_buffer(char **bufp); +char *strstr(const char *s, const char *wanted); +char *xmalloc(int size); +char *xrealloc(char *ptr, long n); +int do_scrub_next_char(int (*get)(), void (*unget)()); +int gen_to_words(LITTLENUM_TYPE *words, int precision, long exponent_bits); +int had_err(void); +int had_errors(void); +int had_warnings(void); +int ignore_input(void); +int scrub_from_file(void); +int scrub_from_file(void); +int scrub_from_string(void); +int seen_at_least_1_file(void); +void app_pop(char *arg); +void as_howmuch(FILE *stream); +void as_perror(char *gripe, char *filename); +void as_where(void); +void bump_line_counters(void); +void do_scrub_begin(void); +void input_scrub_begin(void); +void input_scrub_close(void); +void input_scrub_end(void); +void int_to_gen(long x); +void new_logical_line(char *fname, int line_number); +void scrub_to_file(int ch); +void scrub_to_string(int ch); +void subseg_change(segT seg, int subseg); +void subseg_new(segT seg, subsegT subseg); +void subsegs_begin(void); + +#else /* not __STDC__ */ + +char *app_push(); +char *atof_ieee(); +char *input_scrub_include_file(); +char *input_scrub_new_file(); +char *input_scrub_next_buffer(); +char *strstr(); +char *xmalloc(); +char *xrealloc(); +int do_scrub_next_char(); +int gen_to_words(); +int had_err(); +int had_errors(); +int had_warnings(); +int ignore_input(); +int scrub_from_file(); +int scrub_from_file(); +int scrub_from_string(); +int seen_at_least_1_file(); +void app_pop(); +void as_howmuch(); +void as_perror(); +void as_where(); +void bump_line_counters(); +void do_scrub_begin(); +void input_scrub_begin(); +void input_scrub_close(); +void input_scrub_end(); +void int_to_gen(); +void new_logical_line(); +void scrub_to_file(); +void scrub_to_string(); +void subseg_change(); +void subseg_new(); +void subsegs_begin(); + +#endif /* not __STDC__ */ + +/* this one starts the chain of target dependant headers */ +#include "targ-env.h" + +/* these define types needed by the interfaces */ +#include "struc-symbol.h" +#include "write.h" +#include "expr.h" +#include "frags.h" +#include "hash.h" +#include "read.h" +#include "symbols.h" + +#include "tc.h" +#include "obj.h" + +#include "listing.h" + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of as.h */ diff --git a/gnu/usr.bin/as/atof-generic.c b/gnu/usr.bin/as/atof-generic.c new file mode 100644 index 000000000000..979f14bbd790 --- /dev/null +++ b/gnu/usr.bin/as/atof-generic.c @@ -0,0 +1,526 @@ +/* atof_generic.c - turn a string of digits into a Flonum + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef lint +static char rcsid[] = "$Id: atof-generic.c,v 1.2 1993/11/03 00:51:14 paul Exp $"; +#endif + +#include <ctype.h> +#include <string.h> + +#include "as.h" + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#ifdef sparc +#include <alloca.h> +#endif +#endif + +/* #define FALSE (0) */ +/* #define TRUE (1) */ + +/***********************************************************************\ + * * + * Given a string of decimal digits , with optional decimal * + * mark and optional decimal exponent (place value) of the * + * lowest_order decimal digit: produce a floating point * + * number. The number is 'generic' floating point: our * + * caller will encode it for a specific machine architecture. * + * * + * Assumptions * + * uses base (radix) 2 * + * this machine uses 2's complement binary integers * + * target flonums use " " " " * + * target flonums exponents fit in a long * + * * + \***********************************************************************/ + +/* + + Syntax: + + <flonum> ::= <optional-sign> <decimal-number> <optional-exponent> + <optional-sign> ::= '+' | '-' | {empty} + <decimal-number> ::= <integer> + | <integer> <radix-character> + | <integer> <radix-character> <integer> + | <radix-character> <integer> + + <optional-exponent> ::= {empty} + | <exponent-character> <optional-sign> <integer> + + <integer> ::= <digit> | <digit> <integer> + <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' + <exponent-character> ::= {one character from "string_of_decimal_exponent_marks"} + <radix-character> ::= {one character from "string_of_decimal_marks"} + + */ + +int /* 0 if OK */ + atof_generic ( + address_of_string_pointer, /* return pointer to just + AFTER number we read. */ + string_of_decimal_marks, /* At most one per number. */ + string_of_decimal_exponent_marks, + address_of_generic_floating_point_number) +char **address_of_string_pointer; +const char *string_of_decimal_marks; +const char *string_of_decimal_exponent_marks; +FLONUM_TYPE *address_of_generic_floating_point_number; +{ + int return_value; /* 0 means OK. */ + char * first_digit; + /* char *last_digit; JF unused */ + int number_of_digits_before_decimal; + int number_of_digits_after_decimal; + long decimal_exponent; + int number_of_digits_available; + char digits_sign_char; + + /* + * 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); + } + + /* 99e999 is a "special" token to some older, broken compilers. */ + 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); + } + + if (strncmp(first_digit, "99e999", 6) == 0) { + 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; + *address_of_string_pointer = first_digit + 6; + return(0); + } + + number_of_digits_before_decimal = 0; + number_of_digits_after_decimal = 0; + decimal_exponent = 0; + seen_significant_digit = 0; + for (p = first_digit; (((c = * p) != '\0') + && (!c || ! strchr(string_of_decimal_marks, c)) + && (!c || !strchr(string_of_decimal_exponent_marks, c))); + p++) { + if (isdigit(c)) { + if (seen_significant_digit || c > '0') { + ++number_of_digits_before_decimal; + seen_significant_digit = 1; + } else { + first_digit++; + } + } else { + break; /* p -> char after pre-decimal digits. */ + } + } /* For each digit before decimal mark. */ + +#ifndef OLD_FLOAT_READS + /* Ignore trailing 0's after the decimal point. The original code here + * (ifdef'd out) does not do this, and numbers like + * 4.29496729600000000000e+09 (2**31) + * come out inexact for some reason related to length of the digit + * string. + */ + if (c && strchr(string_of_decimal_marks, c)) { + int zeros = 0; /* Length of current string of zeros */ + + for (p++; (c = *p) && isdigit(c); p++) { + if (c == '0') { + zeros++; + } else { + number_of_digits_after_decimal += 1 + zeros; + zeros = 0; + } + } + } +#else + if (c && strchr(string_of_decimal_marks, c)) { + for (p++; (((c = *p) != '\0') + && (!c || !strchr(string_of_decimal_exponent_marks, c))); + p++) { + if (isdigit(c)) { + number_of_digits_after_decimal++; /* This may be retracted below. */ + if (/* seen_significant_digit || */ c > '0') { + seen_significant_digit = TRUE; + } + } else { + if (!seen_significant_digit) { + number_of_digits_after_decimal = 0; + } + break; + } + } /* For each digit after decimal mark. */ + } + + while (number_of_digits_after_decimal && first_digit[number_of_digits_before_decimal + + number_of_digits_after_decimal] == '0') + --number_of_digits_after_decimal; + /* last_digit = p; JF unused */ +#endif + + if (c && strchr(string_of_decimal_exponent_marks, c) ) { + char digits_exponent_sign_char; + + c = *++p; + if (c && strchr ("+-",c)) { + digits_exponent_sign_char = c; + c = *++p; + } else { + digits_exponent_sign_char = '+'; + } + + for ( ; (c); c = *++p) { + if (isdigit(c)) { + decimal_exponent = decimal_exponent * 10 + c - '0'; + /* + * BUG! If we overflow here, we lose! + */ + } else { + break; + } + } + + if (digits_exponent_sign_char == '-') { + decimal_exponent = -decimal_exponent; + } + } + + *address_of_string_pointer = p; + + + + number_of_digits_available = + number_of_digits_before_decimal + number_of_digits_after_decimal; + return_value = 0; + if (number_of_digits_available == 0) { + address_of_generic_floating_point_number->exponent = 0; /* Not strictly necessary */ + address_of_generic_floating_point_number->leader + = -1 + address_of_generic_floating_point_number->low; + address_of_generic_floating_point_number->sign = digits_sign_char; + /* We have just concocted (+/-)0.0E0 */ + + } else { + int count; /* Number of useful digits left to scan. */ + + LITTLENUM_TYPE *digits_binary_low; + 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); + + memset((char *)digits_binary_low, '\0', size_of_digits_in_chars); + + /* Digits_binary_low[] is allocated and zeroed. */ + + /* + * Parse the decimal digits as if * digits_low was in the units position. + * Emit a binary number into digits_binary_low[]. + * + * Use a large-precision version of: + * (((1st-digit) * 10 + 2nd-digit) * 10 + 3rd-digit ...) * 10 + last-digit + */ + + for (p = first_digit, count = number_of_digits_to_use; count; p++, --count) { + c = *p; + if (isdigit(c)) { + /* + * Multiply by 10. Assume can never overflow. + * Add this digit to digits_binary_low[]. + */ + + long carry; + LITTLENUM_TYPE *littlenum_pointer; + LITTLENUM_TYPE *littlenum_limit; + + littlenum_limit = digits_binary_low + + more_than_enough_littlenums_for_digits + - 1; + + carry = c - '0'; /* char -> binary */ + + for (littlenum_pointer = digits_binary_low; + littlenum_pointer <= littlenum_limit; + littlenum_pointer++) { + long work; + + work = carry + 10 * (long) (*littlenum_pointer); + *littlenum_pointer = work & LITTLENUM_MASK; + carry = work >> LITTLENUM_NUMBER_OF_BITS; + } + + if (carry != 0) { + /* + * We have a GROSS internal error. + * This should never happen. + */ + as_fatal("failed sanity check."); /* 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); + memset((char *)power_binary_low, '\0', size_of_power_in_chars); + * power_binary_low = 1; + power_of_10_flonum.exponent = 0; + power_of_10_flonum.low = power_binary_low; + power_of_10_flonum.leader = power_binary_low; + power_of_10_flonum.high = power_binary_low + size_of_power_in_littlenums - 1; + power_of_10_flonum.sign = '+'; + temporary_flonum.low = temporary_binary_low; + temporary_flonum.high = temporary_binary_low + size_of_power_in_littlenums - 1; + /* + * (power) == 1. + * Space for temporary_flonum allocated. + */ + + /* + * ... + * + * WHILE more bits + * DO find next bit (with place value) + * multiply into power mantissa + * OD + */ + { + int place_number_limit; + /* Any 10^(2^n) whose "n" exceeds this */ + /* value will fall off the end of */ + /* flonum_XXXX_powers_of_ten[]. */ + int place_number; + const FLONUM_TYPE *multiplicand; /* -> 10^(2^n) */ + + place_number_limit = table_size_of_flonum_powers_of_ten; + + multiplicand = (decimal_exponent_is_negative + ? flonum_negative_powers_of_ten + : flonum_positive_powers_of_ten); + + for (place_number = 1; /* Place value of this bit of exponent. */ + decimal_exponent; /* Quit when no more 1 bits in exponent. */ + decimal_exponent >>= 1, place_number++) { + if (decimal_exponent & 1) { + if (place_number > place_number_limit) { + /* + * The decimal exponent has a magnitude so great that + * our tables can't help us fragment it. Although this + * routine is in error because it can't imagine a + * number that big, signal an error as if it is the + * user's fault for presenting such a big number. + */ + return_value = ERROR_EXPONENT_OVERFLOW; + /* + * quit out of loop gracefully + */ + decimal_exponent = 0; + } else { +#ifdef TRACE + printf("before multiply, place_number = %d., power_of_10_flonum:\n", + place_number); + + flonum_print(&power_of_10_flonum); + (void)putchar('\n'); +#endif + 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 of atof_generic.c */ diff --git a/gnu/usr.bin/as/bignum-copy.c b/gnu/usr.bin/as/bignum-copy.c new file mode 100644 index 000000000000..983de6d89623 --- /dev/null +++ b/gnu/usr.bin/as/bignum-copy.c @@ -0,0 +1,76 @@ +/* bignum_copy.c - copy a bignum + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef lint +static char rcsid[] = "$Id: bignum-copy.c,v 1.2 1993/11/03 00:51:16 paul Exp $"; +#endif + +#include "as.h" + +/* + * bignum_copy () + * + * Copy a bignum from in to out. + * If the output is shorter than the input, copy lower-order littlenums. + * Return 0 or the number of significant littlenums dropped. + * Assumes littlenum arrays are densely packed: no unused chars between + * the littlenums. Uses memcpy() to move littlenums, and wants to + * know length (in chars) of the input bignum. + */ + +/* void */ +int + bignum_copy(in, in_length, out, out_length) +register LITTLENUM_TYPE *in; +register int in_length; /* in sizeof(littlenum)s */ +register LITTLENUM_TYPE *out; +register int out_length; /* in sizeof(littlenum)s */ +{ + int significant_littlenums_dropped; + + if (out_length < in_length) { + LITTLENUM_TYPE *p; /* -> most significant (non-zero) input + littlenum. */ + + memcpy((void *) out, (void *) in, + out_length << LITTLENUM_SHIFT); + for (p = in + in_length - 1; p >= in; --p) { + if (* p) break; + } + significant_littlenums_dropped = p - in - in_length + 1; + + if (significant_littlenums_dropped < 0) { + significant_littlenums_dropped = 0; + } + } else { + memcpy((char *) out, (char *) in, + in_length << LITTLENUM_SHIFT); + + if (out_length > in_length) { + memset((char *) (out + out_length), + '\0', (out_length - in_length) << LITTLENUM_SHIFT); + } + + significant_littlenums_dropped = 0; + } + + return(significant_littlenums_dropped); +} /* bignum_copy() */ + +/* end of bignum-copy.c */ diff --git a/gnu/usr.bin/as/bignum.h b/gnu/usr.bin/as/bignum.h new file mode 100644 index 000000000000..11f6884d8a82 --- /dev/null +++ b/gnu/usr.bin/as/bignum.h @@ -0,0 +1,64 @@ +/* bignum.h-arbitrary precision integers + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * $Id: bignum.h,v 1.2 1993/11/03 00:51:18 paul Exp $ + */ + +/***********************************************************************\ + * * + * Arbitrary-precision integer arithmetic. * + * For speed, we work in groups of bits, even though this * + * complicates algorithms. * + * Each group of bits is called a 'littlenum'. * + * A bunch of littlenums representing a (possibly large) * + * integer is called a 'bignum'. * + * Bignums are >= 0. * + * * + \***********************************************************************/ + +#define LITTLENUM_NUMBER_OF_BITS (16) +#define LITTLENUM_RADIX (1 << LITTLENUM_NUMBER_OF_BITS) +#define LITTLENUM_MASK (0xFFFF) +#define LITTLENUM_SHIFT (1) +#define CHARS_PER_LITTLENUM (1 << LITTLENUM_SHIFT) +#ifndef BITS_PER_CHAR +#define BITS_PER_CHAR (8) +#endif + +typedef unsigned short LITTLENUM_TYPE; + +/* JF truncated this to get around a problem with GCC */ +#define LOG_TO_BASE_2_OF_10 (3.3219280948873623478703194294893901758651) +/* WARNING: I haven't checked that the trailing digits are correct! */ + + /* lengths are in sizeof(littlenum)s */ +#if __STDC__ == 1 + +int bignum_copy(LITTLENUM_TYPE *in, int in_length, + LITTLENUM_TYPE *out, int out_length); + +#else + +int bignum_copy(); + +#endif /* __STDC__ */ + + +/* end of bignum.h */ diff --git a/gnu/usr.bin/as/bit_fix.h b/gnu/usr.bin/as/bit_fix.h new file mode 100644 index 000000000000..5322017a4e5f --- /dev/null +++ b/gnu/usr.bin/as/bit_fix.h @@ -0,0 +1,54 @@ +/* write.h + + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: bit_fix.h,v 1.1 1993/11/03 00:51:19 paul Exp $ + */ + + +/* The bit_fix was implemented to support machines that need variables + to be inserted in bitfields other than 1, 2 and 4 bytes. + Furthermore it gives us a possibillity to mask in bits in the symbol + when it's fixed in the objectcode and check the symbols limits. + + The or-mask is used to set the huffman bits in displacements for the + ns32k port. + The acbi, addqi, movqi, cmpqi instruction requires an assembler that + can handle bitfields. Ie handle an expression, evaluate it and insert + the result in an some bitfield. ( ex: 5 bits in a short field of a opcode) + */ + +#ifndef __bit_fix_h__ +#define __bit_fix_h__ + +struct bit_fix { + int fx_bit_size; /* Length of bitfield */ + int fx_bit_offset; /* Bit offset to bitfield */ + long fx_bit_base; /* Where do we apply the bitfix. + If this is zero, default is assumed. */ + long fx_bit_base_adj; /* Adjustment of base */ + long fx_bit_max; /* Signextended max for bitfield */ + long fx_bit_min; /* Signextended min for bitfield */ + long fx_bit_add; /* Or mask, used for huffman prefix */ +}; +typedef struct bit_fix bit_fixS; + +#endif /* __bit_fix_h__ */ + + /* end of bit_fix.h */ diff --git a/gnu/usr.bin/as/cond.c b/gnu/usr.bin/as/cond.c new file mode 100644 index 000000000000..28277514b24c --- /dev/null +++ b/gnu/usr.bin/as/cond.c @@ -0,0 +1,239 @@ +/* cond.c - conditional assembly pseudo-ops, and .include + Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef lint +static char rcsid[] = "$Id: cond.c,v 1.1 1993/11/03 00:51:20 paul Exp $"; +#endif + +#include "as.h" + +#include "obstack.h" + +/* This is allocated to grow and shrink as .ifdef/.endif pairs are scanned. */ +struct obstack cond_obstack; + +struct file_line { + char *logical_file; + int logical_line; + char *physical_file; + int physical_line; +}; /* file_line */ + +/* This is what we push and pop. */ +struct conditional_frame { + struct file_line if_file_line; /* the source file & line number of the "if" */ + struct file_line else_file_line; /* the source file & line of the "else" */ + struct conditional_frame *previous_cframe; + int else_seen; /* have we seen an else yet? */ + int ignoring; /* if we are currently ignoring input. */ + int dead_tree; /* if a conditional at a higher level is ignoring input. */ +}; /* conditional_frame */ + +#if __STDC__ == 1 + +static void get_file_line(struct file_line *into); +static void initialize_cframe(struct conditional_frame *cframe); +static void set_file_line(struct file_line *from); + +#else + +static void get_file_line(); +static void initialize_cframe(); +static void set_file_line(); + +#endif + +static struct conditional_frame *current_cframe = NULL; + +void s_ifdef(arg) +int arg; +{ + register char *name; /* points to name of symbol */ + register struct symbol *symbolP; /* Points to symbol */ + struct conditional_frame cframe; + + SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */ + name = input_line_pointer; + + if (!is_name_beginner(*name)) { + as_bad("invalid identifier for \".ifdef\""); + obstack_1grow(&cond_obstack, 0); + } else { + get_symbol_end(); + ++input_line_pointer; + symbolP = symbol_find(name); + + initialize_cframe(&cframe); + cframe.ignoring = cframe.dead_tree && !((symbolP != 0) ^ arg); + current_cframe = (struct conditional_frame *) obstack_copy(&cond_obstack, &cframe, sizeof(cframe)); + } /* if a valid identifyer name */ + + return; +} /* s_ifdef() */ + +void s_if(arg) +int arg; +{ + expressionS operand; + struct conditional_frame cframe; + + SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */ + expr(0, &operand); + + if (operand.X_add_symbol != NULL + || operand.X_subtract_symbol != NULL) { + as_bad("non-constant expression in \".if\" statement"); + } /* bad condition */ + + /* If the above error is signaled, this will dispatch + using an undefined result. No big deal. */ + initialize_cframe(&cframe); + cframe.ignoring = cframe.dead_tree || !((operand.X_add_number != 0) ^ arg); + current_cframe = (struct conditional_frame *) obstack_copy(&cond_obstack, &cframe, sizeof(cframe)); + return; +} /* s_if() */ + +void s_endif(arg) +int arg; +{ + struct conditional_frame *hold; + + if (current_cframe == NULL) { + as_bad("\".endif\" without \".if\""); + } else { + hold = current_cframe; + current_cframe = current_cframe->previous_cframe; + obstack_free(&cond_obstack, hold); + } /* if one pop too many */ + + return; +} /* s_endif() */ + +void s_else(arg) +int arg; +{ + if (current_cframe == NULL) { + as_bad(".else without matching .if - ignored"); + + } else if (current_cframe->else_seen) { + struct file_line hold; + as_bad("duplicate \"else\" - ignored"); + + get_file_line(&hold); + set_file_line(¤t_cframe->else_file_line); + as_bad("here is the previous \"else\"."); + set_file_line(¤t_cframe->if_file_line); + as_bad("here is the matching \".if\"."); + set_file_line(&hold); + + } else { + get_file_line(¤t_cframe->else_file_line); + + if (!current_cframe->dead_tree) { + current_cframe->ignoring = !current_cframe->ignoring; + } /* if not a dead tree */ + + current_cframe->else_seen = 1; + } /* if error else do it */ + + return; +} /* s_else() */ + +void s_ifeqs(arg) +int arg; +{ + as_bad("ifeqs not implemented."); + + return; +} /* s_ifeqs() */ + +void s_end(arg) +int arg; +{ + return; +} /* s_end() */ + +int ignore_input() { + char *ptr = obstack_next_free (&cond_obstack); + + /* We cannot ignore certain pseudo ops. */ + if (input_line_pointer[-1] == '.' + && ((input_line_pointer[0] == 'i' + && (!strncmp (input_line_pointer, "if", 2) + || !strncmp (input_line_pointer, "ifdef", 5) + || !strncmp (input_line_pointer, "ifndef", 6))) + || (input_line_pointer[0] == 'e' + && (!strncmp (input_line_pointer, "else", 4) + || !strncmp (input_line_pointer, "endif", 5))))) { + return 0; + } + + return((current_cframe != NULL) && (current_cframe->ignoring)); +} /* ignore_input() */ + +static void initialize_cframe(cframe) +struct conditional_frame *cframe; +{ + memset(cframe, 0, sizeof(*cframe)); + get_file_line(&(cframe->if_file_line)); + cframe->previous_cframe = current_cframe; + cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring; + + return; +} /* initialize_cframe() */ + +static void get_file_line(into) +struct file_line *into; +{ + extern char *logical_input_file; + extern char *physical_input_file; + extern int logical_input_line; + extern int physical_input_line; + + into->logical_file = logical_input_file; + into->logical_line = logical_input_line; + into->physical_file = physical_input_file; + into->physical_line = physical_input_line; + + return; +} /* get_file_line() */ + +static void set_file_line(from) +struct file_line *from; +{ + extern char *logical_input_file; + extern char *physical_input_file; + extern int logical_input_line; + extern int physical_input_line; + + logical_input_file = from->logical_file; + logical_input_line = from->logical_line; + physical_input_file = from->physical_file; + physical_input_line = from->physical_line; + return; +} /* set_file_line() */ + +/* + * Local Variables: + * fill-column: 131 + * comment-column: 0 + * End: + */ + +/* end of cond.c */ diff --git a/gnu/usr.bin/as/config-gas.com b/gnu/usr.bin/as/config-gas.com new file mode 100644 index 000000000000..48e2e49dc8db --- /dev/null +++ b/gnu/usr.bin/as/config-gas.com @@ -0,0 +1,76 @@ +$! +$! This file sets things up to build gas on a VMS system to generate object +$! files for a VMS system. We do not use the configure script, since we +$! do not have /bin/sh to execute it. +$! +$! If you are running this file, then obviously the host is vax-dec-vms. +$! +$gas_host="vms" +$! +$cpu_type="vax" +$emulation="generic" +$obj_format="vms" +$atof="vax" +$! +$! host specific information +$call link host.h [.config]ho-'gas_host'.h +$! +$! Target specific information +$call link targ-cpu.c [.config]tc-'cpu_type'.c +$call link targ-cpu.h [.config]tc-'cpu_type'.h +$call link targ-env.h [.config]te-'emulation'.h +$! +$! Code to handle the object file format. +$call link obj-format.h [.config]obj-'obj_format'.h +$call link obj-format.c [.config]obj-'obj_format'.c +$! +$! Code to handle floating point. +$call link atof-targ.c [.config]atof-'atof'.c +$! +$! +$! Create the file version.opt, which helps identify the executalbe. +$! +$search version.c version_string,"="/match=and/output=t.tmp +$open ifile$ t.tmp +$read ifile$ line +$close ifile$ +$delete/nolog t.tmp; +$ijk=f$locate("""",line)+1 +$line=f$extract(ijk,f$length(line)-ijk,line) +$ijk=f$locate("""",line) +$line=f$extract(0,ijk,line) +$ijk=f$locate("\n",line) +$line=f$extract(0,ijk,line) +$! +$i=0 +$loop: +$elm=f$element(i," ",line) +$if elm.eqs."" then goto no_ident +$if (elm.les."9").and.(elm.ges."0") then goto write_ident +$i=i+1 +$goto loop +$! +$no_ident: +$elm="?.??" +$! +$! +$write_ident: +$open ifile$ version.opt/write +$write ifile$ "ident="+""""+elm+"""" +$close ifile$ +$! +$ ! +$ if f$search("config.status") .nes. "" then delete config.status.* +$ open/write file config.status +$ write file "Links are now set up for use with a vax running VMS." +$ close file +$ type config.status +$exit +$! +$! +$link: +$subroutine +$if f$search(p1).nes."" then delete/nolog 'p1'; +$copy 'p2' 'p1' +$write sys$output "Linked ''p2' to ''p1'." +$endsubroutine diff --git a/gnu/usr.bin/as/config/Makefile.hp300 b/gnu/usr.bin/as/config/Makefile.hp300 new file mode 100644 index 000000000000..388501cf8dc8 --- /dev/null +++ b/gnu/usr.bin/as/config/Makefile.hp300 @@ -0,0 +1,7 @@ +# from: @(#)Makefile.hp300 6.1 (Berkeley) 3/3/91 +# $Id: Makefile.hp300,v 1.1 1993/11/03 00:52:56 paul Exp $ + +CFLAGS+= -Dm68851 +SRCS+= tc-m68k.c atof-ieee.c + +gas_target= m68k diff --git a/gnu/usr.bin/as/config/Makefile.i386 b/gnu/usr.bin/as/config/Makefile.i386 new file mode 100644 index 000000000000..7ef19f743d21 --- /dev/null +++ b/gnu/usr.bin/as/config/Makefile.i386 @@ -0,0 +1,5 @@ +# from: @(#)Makefile.i386 6.1 (Berkeley) 3/3/91 +# $Id: Makefile.i386,v 1.2 1993/11/03 00:52:58 paul Exp $ + +CFLAGS+= -DNON_BROKEN_WORDS +SRCS+= tc-i386.c atof-ieee.c diff --git a/gnu/usr.bin/as/config/Makefile.pc532 b/gnu/usr.bin/as/config/Makefile.pc532 new file mode 100644 index 000000000000..5336a25a5eee --- /dev/null +++ b/gnu/usr.bin/as/config/Makefile.pc532 @@ -0,0 +1,7 @@ +# $Id: Makefile.pc532,v 1.1 1993/11/03 00:52:59 paul Exp $ + +SRCS+= tc-ns32k.c atof-ns32k.c + +CFLAGS+= -DNS32532 -DNS32381 + +gas_target= ns32k diff --git a/gnu/usr.bin/as/config/Makefile.sparc b/gnu/usr.bin/as/config/Makefile.sparc new file mode 100644 index 000000000000..eab4c579b719 --- /dev/null +++ b/gnu/usr.bin/as/config/Makefile.sparc @@ -0,0 +1,5 @@ +# from: @(#)Makefile.i386 6.1 (Berkeley) 3/3/91 +# $Id: Makefile.sparc,v 1.1 1993/11/03 00:53:00 paul Exp $ + +CFLAGS+= -DNON_BROKEN_WORDS +SRCS+= tc-sparc.c atof-ieee.c diff --git a/gnu/usr.bin/as/config/Makefile.vax b/gnu/usr.bin/as/config/Makefile.vax new file mode 100644 index 000000000000..060f15d9ddae --- /dev/null +++ b/gnu/usr.bin/as/config/Makefile.vax @@ -0,0 +1,4 @@ +# from: @(#)Makefile.vax 6.1 (Berkeley) 3/3/91 +# $Id: Makefile.vax,v 1.1 1993/11/03 00:53:01 paul Exp $ + +SRCS+= tc-vax.c atof-vax.c diff --git a/gnu/usr.bin/as/config/aout.h b/gnu/usr.bin/as/config/aout.h new file mode 100644 index 000000000000..23b085adaaa1 --- /dev/null +++ b/gnu/usr.bin/as/config/aout.h @@ -0,0 +1,430 @@ +/* This file is aout.h + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef __A_OUT_GNU_H__ +#define __A_OUT_GNU_H__ + +enum reloc_type { + +#ifdef TC_M88K + RELOC_LO16, /* lo16(sym) */ + RELOC_HI16, /* hi16(sym) */ + RELOC_PC16, /* bb0, bb1, bcnd */ + RELOC_PC26, /* br, bsr */ + RELOC_32, /* jump tables, etc */ + RELOC_IW16, /* global access through linker regs 28 */ + NO_RELOC, +#else /* not TC_M88K */ +#ifdef TC_I860 + +/* NOTE: three bits max, see struct reloc_info_i860.r_type */ + NO_RELOC = 0, BRADDR, LOW0, LOW1, LOW2, LOW3, LOW4, SPLIT0, SPLIT1, SPLIT2, RELOC_32, + +#else /* not TC_I860 */ + + RELOC_8, RELOC_16, RELOC_32, /* simple relocations */ + RELOC_DISP8, RELOC_DISP16, RELOC_DISP32, /* pc-rel displacement */ + RELOC_WDISP30, RELOC_WDISP22, + RELOC_HI22, RELOC_22, + RELOC_13, RELOC_LO10, + RELOC_SFA_BASE, RELOC_SFA_OFF13, + RELOC_BASE10, RELOC_BASE13, RELOC_BASE22, /* P.I.C. (base-relative) */ + RELOC_PC10, RELOC_PC22, /* for some sort of pc-rel P.I.C. (?) */ + RELOC_JMP_TBL, /* P.I.C. jump table */ + RELOC_SEGOFF16, /* reputedly for shared libraries somehow */ + RELOC_GLOB_DAT, RELOC_JMP_SLOT, RELOC_RELATIVE, +#ifndef TC_SPARC + RELOC_11, + RELOC_WDISP2_14, + RELOC_WDISP19, + RELOC_HHI22, + RELOC_HLO10, + + /* 29K relocation types */ + RELOC_JUMPTARG, RELOC_CONST, RELOC_CONSTH, + + RELOC_WDISP14, RELOC_WDISP21, +#endif /* not TC_SPARC */ + NO_RELOC, + +#ifdef TC_I386 + /* Used internally by gas */ + RELOC_GOT, + RELOC_GOTOFF, +#endif + +#endif /* not TC_I860 */ +#endif /* not TC_M88K */ +}; + + +#ifdef TC_I860 + /* NOTE: two bits max, see reloc_info_i860.r_type */ +enum highlow_type { + NO_SPEC = 0, PAIR, HIGH, HIGHADJ, +}; +#endif /* TC_I860 */ + + +#define __GNU_EXEC_MACROS__ + +#ifndef __STRUCT_EXEC_OVERRIDE__ + +/* This is the layout on disk of a Unix V7, Berkeley, SunOS, Vax Ultrix + "struct exec". Don't assume that on this machine, the "struct exec" + will lay out the same sizes or alignments. */ + +struct exec_bytes { + unsigned char a_info[4]; + unsigned char a_text[4]; + unsigned char a_data[4]; + unsigned char a_bss[4]; + unsigned char a_syms[4]; + unsigned char a_entry[4]; + unsigned char a_trsize[4]; + unsigned char a_drsize[4]; +}; + +/* How big the "struct exec" is on disk */ +#define EXEC_BYTES_SIZE (8 * 4) + +/* This is the layout in memory of a "struct exec" while we process it. */ + +struct exec +{ + unsigned long a_info; /* Use macros N_MAGIC, etc for access */ + unsigned a_text; /* length of text, in bytes */ + unsigned a_data; /* length of data, in bytes */ + unsigned a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned a_syms; /* length of symbol table data in file, in bytes */ + unsigned a_entry; /* start address */ + unsigned a_trsize; /* length of relocation info for text, in bytes */ + unsigned a_drsize; /* length of relocation info for data, in bytes */ +}; + +#endif /* __STRUCT_EXEC_OVERRIDE__ */ + +/* these go in the N_MACHTYPE field */ +/* These symbols could be defined by code from Suns...punt 'em */ +#undef M_UNKNOWN +#undef M_68010 +#undef M_68020 +#undef M_SPARC +enum machine_type { + M_UNKNOWN = 0, + M_68010 = 1, + M_68020 = 2, + M_SPARC = 3, + /* skip a bunch so we don't run into any of sun's numbers */ + M_386 = 100, + M_29K = 101, + M_RS6000 = 102, /* IBM RS/6000 */ + /* HP/BSD formats */ + M_HP200 = 200, /* hp200 (68010) BSD binary */ + M_HP300 = 300, /* hp300 (68020+68881) BSD binary */ + M_HPUX23 = 0x020C, /* hp200/300 HPUX binary */ +}; + +#define N_MAGIC(exec) ((exec).a_info & 0xffff) +#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff)) +#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff) +#define N_SET_INFO(exec, magic, type, flags) \ + ((exec).a_info = ((magic) & 0xffff) \ + | (((int)(type) & 0xff) << 16) \ + | (((flags) & 0xff) << 24)) +#define N_SET_MAGIC(exec, magic) \ + ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff))) + +#define N_SET_MACHTYPE(exec, machtype) \ + ((exec).a_info = \ + ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16)) + +#define N_SET_FLAGS(exec, flags) \ + ((exec).a_info = \ + ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) + +/* Code indicating object file or impure executable. */ +#define OMAGIC 0407 +/* Code indicating pure executable. */ +#define NMAGIC 0410 +/* Code indicating demand-paged executable. */ +#define ZMAGIC 0413 + +/* Virtual Address of text segment from the a.out file. For OMAGIC, + (almost always "unlinked .o's" these days), should be zero. + For linked files, should reflect reality if we know it. */ + +#ifndef N_TXTADDR +#define N_TXTADDR(x) (N_MAGIC(x) == OMAGIC? 0 : TEXT_START_ADDR) +#endif + +#ifndef N_BADMAG +#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ + && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) +#endif + +/* By default, segment size is constant. But on some machines, it can + be a function of the a.out header (e.g. machine type). */ +#ifndef N_SEGSIZE +#define N_SEGSIZE(x) SEGMENT_SIZE +#endif + + /* This complexity is for encapsulated COFF support */ +#ifndef _N_HDROFF +#define _N_HDROFF(x) (N_SEGSIZE(x) - sizeof (struct exec)) +#endif + +#ifndef N_TXTOFF +#define N_TXTOFF(x) (N_MAGIC(x) == ZMAGIC ? \ + _N_HDROFF((x)) + sizeof (struct exec) : \ + sizeof (struct exec)) +#endif + + +#ifndef N_DATOFF +#define N_DATOFF(x) ( N_TXTOFF(x) + (x).a_text ) +#endif + +#ifndef N_TRELOFF +#define N_TRELOFF(x) ( N_DATOFF(x) + (x).a_data ) +#endif + +#ifndef N_DRELOFF +#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize ) +#endif + +#ifndef N_SYMOFF +#define N_SYMOFF(x) ( N_DRELOFF(x) + (x).a_drsize ) +#endif + +#ifndef N_STROFF +#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms ) +#endif + +/* Address of text segment in memory after it is loaded. */ +#ifndef N_TXTADDR +#define N_TXTADDR(x) 0 +#endif + +#ifndef N_DATADDR +#define N_DATADDR(x) \ + (N_MAGIC(x) == OMAGIC? (N_TXTADDR(x)+(x).a_text) \ + : (N_SEGSIZE(x) + ((N_TXTADDR(x)+(x).a_text-1) & ~(N_SEGSIZE(x)-1)))) +#endif + +/* Address of bss segment in memory after it is loaded. */ +#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) + +struct nlist { + union { + char *n_name; + struct nlist *n_next; + long n_strx; + } n_un; + unsigned char n_type; + char n_other; + short n_desc; + unsigned long n_value; +}; + +#define N_UNDF 0 +#define N_ABS 2 +#define N_TEXT 4 +#define N_DATA 6 +#define N_BSS 8 +#define N_COMM 0x12 /* common (visible in shared lib commons) */ +#define N_FN 0x1F /* File name of a .o file */ + +/* Note: N_EXT can only usefully be OR-ed with N_UNDF, N_ABS, N_TEXT, + N_DATA, or N_BSS. When the low-order bit of other types is set, + (e.g. N_WARNING versus N_FN), they are two different types. */ +#define N_EXT 1 +#define N_TYPE 036 +#define N_STAB 0340 + +/* The following type indicates the definition of a symbol as being + an indirect reference to another symbol. The other symbol + appears as an undefined reference, immediately following this symbol. + + Indirection is asymmetrical. The other symbol's value will be used + to satisfy requests for the indirect symbol, but not vice versa. + If the other symbol does not have a definition, libraries will + be searched to find a definition. */ + +#define N_INDR 0xa + +/* The following type indicates the size of the symbol it refers to */ +#define N_SIZE 0xc + +/* The following symbols refer to set elements. + All the N_SET[ATDB] symbols with the same name form one set. + Space is allocated for the set in the text section, and each set + element's value is stored into one word of the space. + The first word of the space is the length of the set (number of elements). + + The address of the set is made into an N_SETV symbol + whose name is the same as the name of the set. + This symbol acts like a N_DATA global symbol + in that it can satisfy undefined external references. */ + +/* These appear as input to LD, in a .o file. */ +#define N_SETA 0x14 /* Absolute set element symbol */ +#define N_SETT 0x16 /* Text set element symbol */ +#define N_SETD 0x18 /* Data set element symbol */ +#define N_SETB 0x1A /* Bss set element symbol */ + +/* This is output from LD. */ +#define N_SETV 0x1C /* Pointer to set vector in data area. */ + +/* Warning symbol. The text gives a warning message, the next symbol + in the table will be undefined. When the symbol is referenced, the + message is printed. */ + +#define N_WARNING 0x1e + +/* This structure describes a single relocation to be performed. + The text-relocation section of the file is a vector of these structures, + all of which apply to the text section. + Likewise, the data-relocation section applies to the data section. */ + +/* The following enum and struct were borrowed from SunOS's + /usr/include/sun4/a.out.h and extended to handle + other machines. It is currently used on SPARC and AMD 29000. + + reloc_ext_bytes is how it looks on disk. reloc_info_extended is + how we might process it on a native host. */ + +struct reloc_ext_bytes { + unsigned char r_address[4]; + unsigned char r_index[3]; + unsigned char r_bits[1]; + unsigned char r_addend[4]; +}; + +struct reloc_info_i860 +{ + unsigned long r_address; + /* + * Using bit fields here is a bad idea because the order is not portable. :-( + */ + unsigned int r_symbolnum: 24; + unsigned int r_pcrel : 1; + unsigned int r_extern : 1; + /* combining the two field simplifies the argument passing in "new_fix()" */ + /* and is compatible with the existing Sparc #ifdef's */ + /* r_type: highlow_type - bits 5,4; reloc_type - bits 3-0 */ + unsigned int r_type : 6; + long r_addend; +}; + + +#define RELOC_EXT_BITS_EXTERN_BIG 0x80 +#define RELOC_EXT_BITS_EXTERN_LITTLE 0x01 + +#define RELOC_EXT_BITS_TYPE_BIG 0x1F +#define RELOC_EXT_BITS_TYPE_SH_BIG 0 +#define RELOC_EXT_BITS_TYPE_LITTLE 0xF8 +#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3 + +#define RELOC_EXT_SIZE 12 /* Bytes per relocation entry */ + +struct reloc_info_extended +{ + unsigned long r_address; + unsigned int r_index:24; +# define r_symbolnum r_index + unsigned r_extern:1; + unsigned :2; + /* RS/6000 compiler does not support enum bitfield + enum reloc_type r_type:5; */ + enum reloc_type r_type; + long int r_addend; +}; + +/* The standard, old-fashioned, Berkeley compatible relocation struct */ + +struct reloc_std_bytes { + unsigned char r_address[4]; + unsigned char r_index[3]; + unsigned char r_bits[1]; +}; + +#define RELOC_STD_BITS_PCREL_BIG 0x80 +#define RELOC_STD_BITS_PCREL_LITTLE 0x01 + +#define RELOC_STD_BITS_LENGTH_BIG 0x60 +#define RELOC_STD_BITS_LENGTH_SH_BIG 5 /* To shift to units place */ +#define RELOC_STD_BITS_LENGTH_LITTLE 0x06 +#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1 + +#define RELOC_STD_BITS_EXTERN_BIG 0x10 +#define RELOC_STD_BITS_EXTERN_LITTLE 0x08 + +#define RELOC_STD_BITS_BASEREL_BIG 0x08 +#define RELOC_STD_BITS_BASEREL_LITTLE 0x08 + +#define RELOC_STD_BITS_JMPTABLE_BIG 0x04 +#define RELOC_STD_BITS_JMPTABLE_LITTLE 0x04 + +#define RELOC_STD_BITS_RELATIVE_BIG 0x02 +#define RELOC_STD_BITS_RELATIVE_LITTLE 0x02 + +#define RELOC_STD_SIZE 8 /* Bytes per relocation entry */ + +#ifndef CUSTOM_RELOC_FORMAT +struct relocation_info { + /* Address (within segment) to be relocated. */ + int r_address; + /* The meaning of r_symbolnum depends on r_extern. */ + unsigned int r_symbolnum:24; + /* Nonzero means value is a pc-relative offset + and it should be relocated for changes in its own address + as well as for changes in the symbol or section specified. */ + unsigned int r_pcrel:1; + /* Length (as exponent of 2) of the field to be relocated. + Thus, a value of 2 indicates 1<<2 bytes. */ + unsigned int r_length:2; + /* 1 => relocate with value of symbol. + r_symbolnum is the index of the symbol + in file's the symbol table. + 0 => relocate with the address of a segment. + r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS + (the N_EXT bit may be set also, but signifies nothing). */ + unsigned int r_extern:1; + /* The next three bits are for SunOS shared libraries, and seem to + be undocumented. */ + unsigned int r_baserel:1; /* Linkage table relative */ + unsigned int r_jmptable:1; /* pc-relative to jump table */ + +#ifdef TC_NS32K +#define r_bsr r_baserel +#define r_disp r_jmptable +#endif /* TC_NS32K */ + + unsigned int r_relative:1; /* "relative relocation" */ + /* unused */ + unsigned int r_pad:1; /* Padding -- set to zero */ +}; +#endif /* CUSTOM_RELOC_FORMAT */ + +#endif /* __A_OUT_GNU_H__ */ + +/* end of aout.h */ diff --git a/gnu/usr.bin/as/config/atof-ieee.c b/gnu/usr.bin/as/config/atof-ieee.c new file mode 100644 index 000000000000..04d9e1e55f81 --- /dev/null +++ b/gnu/usr.bin/as/config/atof-ieee.c @@ -0,0 +1,524 @@ +/* atof_ieee.c - turn a Flonum into an IEEE floating point number + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef lint +static char rcsid[] = "$Id: atof-ieee.c,v 1.2 1993/11/03 00:53:04 paul Exp $"; +#endif + +#include "as.h" + +extern FLONUM_TYPE generic_floating_point_number; /* Flonums returned here. */ + +#ifndef NULL +#define NULL (0) +#endif + +extern char EXP_CHARS[]; +/* Precision in LittleNums. */ +#define MAX_PRECISION (6) +#define F_PRECISION (2) +#define D_PRECISION (4) +#define X_PRECISION (6) +#define P_PRECISION (6) + +/* Length in LittleNums of guard bits. */ +#define GUARD (2) + +static unsigned long mask[] = { + 0x00000000, + 0x00000001, + 0x00000003, + 0x00000007, + 0x0000000f, + 0x0000001f, + 0x0000003f, + 0x0000007f, + 0x000000ff, + 0x000001ff, + 0x000003ff, + 0x000007ff, + 0x00000fff, + 0x00001fff, + 0x00003fff, + 0x00007fff, + 0x0000ffff, + 0x0001ffff, + 0x0003ffff, + 0x0007ffff, + 0x000fffff, + 0x001fffff, + 0x003fffff, + 0x007fffff, + 0x00ffffff, + 0x01ffffff, + 0x03ffffff, + 0x07ffffff, + 0x0fffffff, + 0x1fffffff, + 0x3fffffff, + 0x7fffffff, + 0xffffffff, +}; + + +static int bits_left_in_littlenum; +static int littlenums_left; +static LITTLENUM_TYPE *littlenum_pointer; + +static int + next_bits (number_of_bits) +int number_of_bits; +{ + int return_value; + + if (!littlenums_left) + return(0); + if (number_of_bits >= bits_left_in_littlenum) { + return_value = mask[bits_left_in_littlenum] & *littlenum_pointer; + number_of_bits -= bits_left_in_littlenum; + return_value <<= number_of_bits; + + if (--littlenums_left) { + bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits; + --littlenum_pointer; + return_value |= (*littlenum_pointer >> bits_left_in_littlenum) & mask[number_of_bits]; + } + } else { + bits_left_in_littlenum -= number_of_bits; + return_value = mask[number_of_bits] & (*littlenum_pointer >> bits_left_in_littlenum); + } + return(return_value); +} + +/* Num had better be less than LITTLENUM_NUMBER_OF_BITS */ +static void + unget_bits(num) +int num; +{ + if (!littlenums_left) { + ++littlenum_pointer; + ++littlenums_left; + bits_left_in_littlenum = num; + } else if (bits_left_in_littlenum + num > LITTLENUM_NUMBER_OF_BITS) { + bits_left_in_littlenum = num - (LITTLENUM_NUMBER_OF_BITS - bits_left_in_littlenum); + ++littlenum_pointer; + ++littlenums_left; + } else + bits_left_in_littlenum += num; +} + +static void + make_invalid_floating_point_number(words) +LITTLENUM_TYPE *words; +{ + as_bad("cannot create floating-point number"); + words[0] = ((unsigned) -1) >> 1; /* Zero the leftmost bit */ + words[1] = -1; + words[2] = -1; + words[3] = -1; + words[4] = -1; + words[5] = -1; +} + +/***********************************************************************\ + * Warning: this returns 16-bit LITTLENUMs. It is up to the caller * + * to figure out any alignment problems and to conspire for the * + * bytes/word to be emitted in the right order. Bigendians beware! * + * * + \***********************************************************************/ + +/* Note that atof-ieee always has X and P precisions enabled. it is up + to md_atof to filter them out if the target machine does not support + them. */ + +char * /* Return pointer past text consumed. */ + atof_ieee(str, what_kind, words) +char *str; /* Text to convert to binary. */ +char what_kind; /* 'd', 'f', 'g', 'h' */ +LITTLENUM_TYPE *words; /* Build the binary here. */ +{ + static LITTLENUM_TYPE bits[MAX_PRECISION + MAX_PRECISION + GUARD]; + /* Extra bits for zeroed low-order bits. */ + /* The 1st MAX_PRECISION are zeroed, */ + /* the last contain flonum bits. */ + char *return_value; + int precision; /* Number of 16-bit words in the format. */ + long exponent_bits; + FLONUM_TYPE save_gen_flonum; + + /* We have to save the generic_floating_point_number because it + contains storage allocation about the array of LITTLENUMs + where the value is actually stored. We will allocate our + own array of littlenums below, but have to restore the global + one on exit. */ + save_gen_flonum = generic_floating_point_number; + + return_value = str; + generic_floating_point_number.low = bits + MAX_PRECISION; + generic_floating_point_number.high = NULL; + generic_floating_point_number.leader = NULL; + generic_floating_point_number.exponent = 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. */ + + memset(bits, '\0', sizeof(LITTLENUM_TYPE) * MAX_PRECISION); + + switch (what_kind) { + case 'f': + case 'F': + case 's': + case 'S': + precision = F_PRECISION; + exponent_bits = 8; + break; + + case 'd': + case 'D': + case 'r': + case 'R': + precision = D_PRECISION; + exponent_bits = 11; + break; + + case 'x': + case 'X': + case 'e': + case 'E': + precision = X_PRECISION; + exponent_bits = 15; + break; + + case 'p': + case 'P': + + precision = P_PRECISION; + exponent_bits = -1; + break; + + default: + make_invalid_floating_point_number(words); + return(NULL); + } + + generic_floating_point_number.high = generic_floating_point_number.low + precision - 1 + GUARD; + + if (atof_generic(&return_value, ".", EXP_CHARS, &generic_floating_point_number)) { + /* as_bad("Error converting floating point number (Exponent overflow?)"); */ + make_invalid_floating_point_number(words); + return(NULL); + } + gen_to_words(words, precision, exponent_bits); + + /* Restore the generic_floating_point_number's storage alloc + (and everything else). */ + generic_floating_point_number = save_gen_flonum; + + return(return_value); +} + +/* Turn generic_floating_point_number into a real float/double/extended */ +int gen_to_words(words, precision, exponent_bits) +LITTLENUM_TYPE *words; +int precision; +long exponent_bits; +{ + int return_value = 0; + + long exponent_1; + long exponent_2; + long exponent_3; + long exponent_4; + int exponent_skippage; + LITTLENUM_TYPE word1; + LITTLENUM_TYPE *lp; + + if (generic_floating_point_number.low > generic_floating_point_number.leader) { + /* 0.0e0 seen. */ + if (generic_floating_point_number.sign == '+') + words[0] = 0x0000; + else + words[0] = 0x8000; + memset(&words[1], '\0', sizeof(LITTLENUM_TYPE) * (precision - 1)); + return(return_value); + } + + /* NaN: Do the right thing */ + if (generic_floating_point_number.sign == 0) { + if (precision == F_PRECISION) { + words[0] = 0x7fff; + words[1] = 0xffff; + } else { + words[0] = 0x7fff; + words[1] = 0xffff; + words[2] = 0xffff; + words[3] = 0xffff; + } + return return_value; + } else if (generic_floating_point_number.sign == 'P') { + /* +INF: Do the right thing */ + if (precision == F_PRECISION) { + words[0] = 0x7f80; + words[1] = 0; + } else { + words[0] = 0x7ff0; + words[1] = 0; + words[2] = 0; + words[3] = 0; + } + return(return_value); + } else if (generic_floating_point_number.sign == 'N') { + /* Negative INF */ + if (precision == F_PRECISION) { + words[0] = 0xff80; + words[1] = 0x0; + } else { + words[0] = 0xfff0; + words[1] = 0x0; + words[2] = 0x0; + words[3] = 0x0; + } + return(return_value); + } + /* + * The floating point formats we support have: + * Bit 15 is sign bit. + * Bits 14:n are excess-whatever exponent. + * Bits n-1:0 (if any) are most significant bits of fraction. + * Bits 15:0 of the next word(s) are the next most significant bits. + * + * So we need: number of bits of exponent, number of bits of + * mantissa. + */ + bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS; + littlenum_pointer = generic_floating_point_number.leader; + littlenums_left = 1 + generic_floating_point_number.leader - generic_floating_point_number.low; + /* Seek (and forget) 1st significant bit */ + for (exponent_skippage = 0; !next_bits(1); ++exponent_skippage) ;; + exponent_1 = generic_floating_point_number.exponent + generic_floating_point_number.leader + + 1 - generic_floating_point_number.low; + /* Radix LITTLENUM_RADIX, point just higher than generic_floating_point_number.leader. */ + exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS; + /* Radix 2. */ + exponent_3 = exponent_2 - exponent_skippage; + /* Forget leading zeros, forget 1st bit. */ + exponent_4 = exponent_3 + ((1 << (exponent_bits - 1)) - 2); + /* Offset exponent. */ + + lp = words; + + /* Word 1. Sign, exponent and perhaps high bits. */ + word1 = (generic_floating_point_number.sign == '+') ? 0 : (1 << (LITTLENUM_NUMBER_OF_BITS - 1)); + + /* Assume 2's complement integers. */ + if (exponent_4 < 1 && exponent_4 >= -62) { + int prec_bits; + int num_bits; + + unget_bits(1); + num_bits = -exponent_4; + prec_bits = LITTLENUM_NUMBER_OF_BITS * precision - (exponent_bits + 1 + num_bits); + if (precision == X_PRECISION && exponent_bits == 15) + prec_bits -= LITTLENUM_NUMBER_OF_BITS + 1; + + if (num_bits >= LITTLENUM_NUMBER_OF_BITS - exponent_bits) { + /* Bigger than one littlenum */ + num_bits -= (LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits; + *lp++ = word1; + if (num_bits + exponent_bits + 1 >= precision * LITTLENUM_NUMBER_OF_BITS) { + /* Exponent overflow */ + make_invalid_floating_point_number(words); + return(return_value); + } + if (precision == X_PRECISION && exponent_bits == 15) { + *lp++ = 0; + *lp++ = 0; + num_bits -= LITTLENUM_NUMBER_OF_BITS - 1; + } + while (num_bits >= LITTLENUM_NUMBER_OF_BITS) { + num_bits -= LITTLENUM_NUMBER_OF_BITS; + *lp++ = 0; + } + if (num_bits) + *lp++ = next_bits(LITTLENUM_NUMBER_OF_BITS - (num_bits)); + } else { + if (precision == X_PRECISION && exponent_bits == 15) { + *lp++ = word1; + *lp++ = 0; + if (num_bits == LITTLENUM_NUMBER_OF_BITS) { + *lp++ = 0; + *lp++ = next_bits(LITTLENUM_NUMBER_OF_BITS - 1); + } else if (num_bits == LITTLENUM_NUMBER_OF_BITS - 1) + *lp++ = 0; + else + *lp++ = next_bits(LITTLENUM_NUMBER_OF_BITS - 1 - num_bits); + num_bits = 0; + } else { + word1 |= next_bits((LITTLENUM_NUMBER_OF_BITS - 1) - (exponent_bits + num_bits)); + *lp++ = word1; + } + } + while (lp < words + precision) + *lp++ = next_bits(LITTLENUM_NUMBER_OF_BITS); + + /* Round the mantissa up, but don't change the number */ + if (next_bits(1)) { + --lp; + if (prec_bits > LITTLENUM_NUMBER_OF_BITS) { + int n = 0; + int tmp_bits; + + n = 0; + tmp_bits = prec_bits; + while (tmp_bits > LITTLENUM_NUMBER_OF_BITS) { + if (lp[n] != (LITTLENUM_TYPE) - 1) + break; + --n; + tmp_bits -= LITTLENUM_NUMBER_OF_BITS; + } + if (tmp_bits > LITTLENUM_NUMBER_OF_BITS || (lp[n] & mask[tmp_bits]) != mask[tmp_bits]) { + unsigned long carry; + + for (carry = 1; carry && (lp >= words); lp --) { + carry = *lp + carry; + *lp = carry; + carry >>= LITTLENUM_NUMBER_OF_BITS; + } + } + } else if ((*lp & mask[prec_bits]) != mask[prec_bits]) + lp++; + } + + return return_value; + } else if (exponent_4 & ~ mask[exponent_bits]) { + /* + * Exponent overflow. Lose immediately. + */ + + /* + * We leave return_value alone: admit we read the + * number, but return a floating exception + * because we can't encode the number. + */ + make_invalid_floating_point_number (words); + return return_value; + } else { + word1 |= (exponent_4 << ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits)) + | next_bits ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits); + } + + *lp++ = word1; + + /* X_PRECISION is special: it has 16 bits of zero in the middle, + followed by a 1 bit. */ + if (exponent_bits == 15 && precision == X_PRECISION) { + *lp++ = 0; + *lp++ = 1 << (LITTLENUM_NUMBER_OF_BITS) | next_bits(LITTLENUM_NUMBER_OF_BITS - 1); + } + + /* The rest of the words are just mantissa bits. */ + while (lp < words + precision) + *lp++ = next_bits(LITTLENUM_NUMBER_OF_BITS); + + if (next_bits(1)) { + unsigned long carry; + /* + * Since the NEXT bit is a 1, round UP the mantissa. + * The cunning design of these hidden-1 floats permits + * us to let the mantissa overflow into the exponent, and + * it 'does the right thing'. However, we lose if the + * highest-order bit of the lowest-order word flips. + * Is that clear? + */ + + /* #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2) + Please allow at least 1 more bit in carry than is in a LITTLENUM. + We need that extra bit to hold a carry during a LITTLENUM carry + propagation. Another extra bit (kept 0) will assure us that we + don't get a sticky sign bit after shifting right, and that + permits us to propagate the carry without any masking of bits. + #endif */ + for (carry = 1, lp--; carry && (lp >= words); lp--) { + carry = *lp + carry; + *lp = carry; + carry >>= LITTLENUM_NUMBER_OF_BITS; + } + if ((word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1))) { + /* We leave return_value alone: admit we read the + * number, but return a floating exception + * because we can't encode the number. + */ + *words &= ~(1 << (LITTLENUM_NUMBER_OF_BITS - 1)); + /* make_invalid_floating_point_number (words); */ + /* return return_value; */ + } + } + return (return_value); +} + +/* This routine is a real kludge. Someone really should do it better, but + I'm too lazy, and I don't understand this stuff all too well anyway + (JF) + */ +void + int_to_gen(x) +long x; +{ + char buf[20]; + char *bufp; + + sprintf(buf,"%ld",x); + bufp = &buf[0]; + if (atof_generic(&bufp, ".", EXP_CHARS, &generic_floating_point_number)) + as_bad("Error converting number to floating point (Exponent overflow?)"); +} + +#ifdef TEST +char * + print_gen(gen) +FLONUM_TYPE *gen; +{ + FLONUM_TYPE f; + LITTLENUM_TYPE arr[10]; + double dv; + float fv; + static char sbuf[40]; + + if (gen) { + f = generic_floating_point_number; + generic_floating_point_number = *gen; + } + gen_to_words(&arr[0], 4, 11); + memcpy(&dv, &arr[0], sizeof(double)); + sprintf(sbuf, "%x %x %x %x %.14G ", arr[0], arr[1], arr[2], arr[3], dv); + gen_to_words(&arr[0], 2, 8); + memcpy(&fv, &arr[0], sizeof(float)); + sprintf(sbuf + strlen(sbuf), "%x %x %.12g\n", arr[0], arr[1], fv); + + if (gen) { + generic_floating_point_number = f; + } + + return(sbuf); +} +#endif + +/* end of atof-ieee.c */ diff --git a/gnu/usr.bin/as/config/atof-ns32k.c b/gnu/usr.bin/as/config/atof-ns32k.c new file mode 100644 index 000000000000..cadeec08af7d --- /dev/null +++ b/gnu/usr.bin/as/config/atof-ns32k.c @@ -0,0 +1,436 @@ +/* atof_ns32k.c - turn a Flonum into a ns32k 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. */ + +/* this is atof-m68k.c hacked for ns32k */ + +#include "as.h" + +extern FLONUM_TYPE generic_floating_point_number; /* Flonums returned here. */ + +extern char EXP_CHARS[]; + /* Precision in LittleNums. */ +#define MAX_PRECISION (4) +#define F_PRECISION (2) +#define D_PRECISION (4) + + /* Length in LittleNums of guard bits. */ +#define GUARD (2) + +int /* Number of chars in flonum type 'letter'. */ +atof_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': + return_value = F_PRECISION; + break; + + case 'd': + return_value = D_PRECISION; + break; + + default: + return_value = 0; + break; + } + return (return_value); +} + +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 --; + --littlenums_left; + 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[0]= ((unsigned)-1)>>1; /* Zero the leftmost bit */ + words[1]= -1; + words[2]= -1; + words[3]= -1; +} + +/***********************************************************************\ +* * +* 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_ns32k (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; + + 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; + + return_value = str; + f.low = bits + MAX_PRECISION; + f.high = NULL; + f.leader = NULL; + f.exponent = NULL; + f.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': + precision = F_PRECISION; + exponent_bits = 8; + break; + + case 'd': + precision = D_PRECISION; + exponent_bits = 11; + break; + + default: + make_invalid_floating_point_number (words); + return NULL; + } + + f.high = f.low + precision - 1 + GUARD; + + if (atof_generic (& return_value, ".", EXP_CHARS, & f)) { + as_warn("Error converting floating point number (Exponent overflow?)"); + make_invalid_floating_point_number (words); + return NULL; + } + + if (f.low > f.leader) { + /* 0.0e0 seen. */ + bzero (words, sizeof(LITTLENUM_TYPE) * precision); + return return_value; + } + + if (f.sign != '+' && f.sign != '-') { + make_invalid_floating_point_number(words); + return NULL; + } + + + /* + * 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. + * + * So we need: number of bits of exponent, number of bits of + * mantissa. + */ + bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS; + littlenum_pointer = f.leader; + littlenums_left = 1 + f.leader-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)) - 2); + /* Offset exponent. */ + + 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. + */ + + as_warn("Exponent overflow in floating-point number"); + make_invalid_floating_point_number (words); + return return_value; + } + 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)) { + 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. + */ + make_invalid_floating_point_number (words); + return return_value; + } + } + return (return_value); +} + +/* This is really identical to atof_ns32k except for some details */ + +gen_to_words(words,precision,exponent_bits) +LITTLENUM_TYPE *words; +long int exponent_bits; +{ + 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. */ + bzero (words, sizeof(LITTLENUM_TYPE) * precision); + 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. + * + * 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. */ + + 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; + } + lp = words; + + /* Word 1. Sign, exponent and perhaps high bits. */ + /* Assume 2's complement integers. */ + word1 = ((exponent_4 & mask[exponent_bits]) << (15 - exponent_bits)) | + ((generic_floating_point_number.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)) { + 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. + */ + 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?)"); +} diff --git a/gnu/usr.bin/as/config/atof-tahoe.c b/gnu/usr.bin/as/config/atof-tahoe.c new file mode 100644 index 000000000000..6425e93e1280 --- /dev/null +++ b/gnu/usr.bin/as/config/atof-tahoe.c @@ -0,0 +1,428 @@ +/* atof_tahoe.c - turn a string into a Tahoe floating point number + Copyright (C) 1987 Free Software Foundation, Inc. + */ + +/* This is really a simplified version of atof_vax.c. I glommed it wholesale + and then shaved it down. I don't even know how it works. (Don't you find + my honesty refreshing? bowen@cs.Buffalo.EDU (Devon E Bowen) + + I don't allow uppercase letters in the precision descrpitors. Ie 'f' and + 'd' are allowed but 'F' and 'D' aren't */ + +#include "as.h" + +/* Precision in LittleNums. */ +#define MAX_PRECISION (4) +#define D_PRECISION (4) +#define F_PRECISION (2) + +/* Precision in chars. */ +#define D_PRECISION_CHARS (8) +#define F_PRECISION_CHARS (4) + + /* Length in LittleNums of guard bits. */ +#define GUARD (2) + +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_gen2tahoe and next_bits */ +static int bits_left_in_littlenum; +static LITTLENUM_TYPE * littlenum_pointer; +static LITTLENUM_TYPE * littlenum_end; + +#if __STDC__ == 1 + +int flonum_gen2tahoe(int format_letter, FLONUM_TYPE *f, LITTLENUM_TYPE *words); + +#else /* not __STDC__ */ + +int flonum_gen2tahoe(); + +#endif /* not __STDC__ */ + + +static int +next_bits (number_of_bits) + int number_of_bits; +{ + int return_value; + + if(littlenum_pointer<littlenum_end) + return 0; + if (number_of_bits >= bits_left_in_littlenum) + { + return_value = mask [bits_left_in_littlenum] & * littlenum_pointer; + number_of_bits -= bits_left_in_littlenum; + return_value <<= number_of_bits; + bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits; + littlenum_pointer --; + if(littlenum_pointer>=littlenum_end) + return_value |= ((*littlenum_pointer) >> (bits_left_in_littlenum)) & + mask [number_of_bits]; + } + else + { + bits_left_in_littlenum -= number_of_bits; + return_value = mask [number_of_bits] & + ((*littlenum_pointer) >> bits_left_in_littlenum); + } + return (return_value); +} + +static void +make_invalid_floating_point_number (words) + LITTLENUM_TYPE * words; +{ + *words = 0x8000; /* Floating Reserved Operand Code */ +} + +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; + + 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_tahoe (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) + { + memset(bits, '\0', 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_gen2tahoe (what_kind, & f, words)) + { + return_value = NULL; + } + } + } + return (return_value); +} + +/* + * In: a flonum, a Tahoe floating point format. + * Out: a Tahoe floating-point bit pattern. + */ + +int /* 0: OK. */ +flonum_gen2tahoe (format_letter, f, words) + char format_letter; /* One of 'd' 'f'. */ + 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. */ + memset(words, '\0', 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 tahoe floating_point formats 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. + * + * So we need: number of bits of exponent, number of bits of + * mantissa. + */ + + 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); +} + +/* + * 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. + */ + +char * +md_atof (what_statement_type, literalP, sizeP) + char what_statement_type; + char * literalP; + int * sizeP; +{ + LITTLENUM_TYPE words [MAX_PRECISION]; + register char kind_of_float; + register int number_of_chars; + register LITTLENUM_TYPE * littlenum_pointer; + + switch (what_statement_type) + { + case 'f': /* .ffloat */ + case 'd': /* .dfloat */ + kind_of_float = what_statement_type; + break; + + default: + kind_of_float = 0; + break; + }; + + if (kind_of_float) + { + register LITTLENUM_TYPE * limit; + + input_line_pointer = atof_tahoe (input_line_pointer, + kind_of_float, + words); + /* + * The atof_tahoe() builds up 16-bit numbers. + * Since the assembler may not be running on + * a different-endian machine, be very careful about + * converting words to chars. + */ + number_of_chars = (kind_of_float == 'f' ? F_PRECISION_CHARS : + (kind_of_float == 'd' ? D_PRECISION_CHARS : 0)); + know(number_of_chars<=MAX_PRECISION*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_tahoe.c */ diff --git a/gnu/usr.bin/as/config/atof-vax.c b/gnu/usr.bin/as/config/atof-vax.c new file mode 100644 index 000000000000..8a6950204f0f --- /dev/null +++ b/gnu/usr.bin/as/config/atof-vax.c @@ -0,0 +1,497 @@ +/* atof_vax.c - turn a Flonum into a VAX floating point number + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* JF added these two for md_atof() */ +#include "as.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) + +#if __STDC__ == 1 + +int flonum_gen2vax(int format_letter, FLONUM_TYPE *f, LITTLENUM_TYPE *words); + +#else /* not __STDC__ */ + +int flonum_gen2vax(); + +#endif /* not __STDC__ */ + +int /* Number of chars in flonum type 'letter'. */ + atof_vax_sizeof (letter) +char letter; +{ + int return_value; + + /* + * Permitting uppercase letters is probably a bad idea. + * Please use only lower-cased letters in case the upper-cased + * ones become unsupported! + */ + switch (letter) + { + case 'f': + case 'F': + return_value = 4; + break; + + case 'd': + case 'D': + case 'g': + case 'G': + return_value = 8; + break; + + case 'h': + case 'H': + return_value = 16; + break; + + default: + return_value = 0; + break; + } + return (return_value); +} /* atof_vax_sizeof */ + +static const long mask[] = { + 0x00000000, + 0x00000001, + 0x00000003, + 0x00000007, + 0x0000000f, + 0x0000001f, + 0x0000003f, + 0x0000007f, + 0x000000ff, + 0x000001ff, + 0x000003ff, + 0x000007ff, + 0x00000fff, + 0x00001fff, + 0x00003fff, + 0x00007fff, + 0x0000ffff, + 0x0001ffff, + 0x0003ffff, + 0x0007ffff, + 0x000fffff, + 0x001fffff, + 0x003fffff, + 0x007fffff, + 0x00ffffff, + 0x01ffffff, + 0x03ffffff, + 0x07ffffff, + 0x0fffffff, + 0x1fffffff, + 0x3fffffff, + 0x7fffffff, + 0xffffffff + }; + + +/* Shared between flonum_gen2vax and next_bits */ +static int bits_left_in_littlenum; +static LITTLENUM_TYPE * littlenum_pointer; +static LITTLENUM_TYPE * littlenum_end; + +static int + next_bits (number_of_bits) +int number_of_bits; +{ + int return_value; + + if (littlenum_pointer<littlenum_end) + return 0; + if (number_of_bits >= bits_left_in_littlenum) + { + return_value = mask[bits_left_in_littlenum] & * littlenum_pointer; + number_of_bits -= bits_left_in_littlenum; + return_value <<= number_of_bits; + bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits; + littlenum_pointer --; + if (littlenum_pointer >= littlenum_end) + return_value |= ( (* littlenum_pointer) >> (bits_left_in_littlenum) ) & mask[number_of_bits]; + } + else + { + bits_left_in_littlenum -= number_of_bits; + return_value = mask[number_of_bits] & ( (* littlenum_pointer) >> bits_left_in_littlenum); + } + return (return_value); +} + +static void + make_invalid_floating_point_number (words) +LITTLENUM_TYPE * words; +{ + * words = 0x8000; /* Floating Reserved Operand Code */ +} + +static int /* 0 means letter is OK. */ + what_kind_of_float (letter, precisionP, exponent_bitsP) +char letter; /* In: lowercase please. What kind of float? */ +int * precisionP; /* Number of 16-bit words in the float. */ +long * exponent_bitsP; /* Number of exponent bits. */ +{ + int retval; /* 0: OK. */ + + retval = 0; + switch (letter) + { + case 'f': + * precisionP = F_PRECISION; + * exponent_bitsP = 8; + break; + + case 'd': + * precisionP = D_PRECISION; + * exponent_bitsP = 8; + break; + + case 'g': + * precisionP = G_PRECISION; + * exponent_bitsP = 11; + break; + + case 'h': + * precisionP = H_PRECISION; + * exponent_bitsP = 15; + break; + + default: + retval = 69; + break; + } + return (retval); +} + +/***********************************************************************\ + * * + * Warning: this returns 16-bit LITTLENUMs, because that is * + * what the VAX thinks in. It is up to the caller to figure * + * out any alignment problems and to conspire for the bytes/word * + * to be emitted in the right order. Bigendians beware! * + * * + \***********************************************************************/ + +char * /* Return pointer past text consumed. */ + atof_vax(str, what_kind, words) +char *str; /* Text to convert to binary. */ +char what_kind; /* 'd', 'f', 'g', 'h' */ +LITTLENUM_TYPE *words; /* Build the binary here. */ +{ + FLONUM_TYPE f; + LITTLENUM_TYPE bits[MAX_PRECISION + MAX_PRECISION + GUARD]; + /* Extra bits for zeroed low-order bits. */ + /* The 1st MAX_PRECISION are zeroed, */ + /* the last contain flonum bits. */ + char *return_value; + int precision; /* Number of 16-bit words in the format. */ + long exponent_bits; + + return_value = str; + f.low = bits + MAX_PRECISION; + f.high = NULL; + f.leader = NULL; + f.exponent = NULL; + f.sign = '\0'; + + if (what_kind_of_float (what_kind, & precision, & exponent_bits)) { + return_value = NULL; /* We lost. */ + make_invalid_floating_point_number (words); + } + + if (return_value) { + memset(bits, '\0', 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); +} /* atof_vax() */ + +/* + * In: a flonum, a vax floating point format. + * Out: a vax floating-point bit pattern. + */ + +int /* 0: OK. */ + flonum_gen2vax (format_letter, f, words) +char format_letter; /* One of 'd' 'f' 'g' 'h'. */ +FLONUM_TYPE *f; +LITTLENUM_TYPE *words; /* Deliver answer here. */ +{ + LITTLENUM_TYPE *lp; + int precision; + long exponent_bits; + int return_value; /* 0 == OK. */ + + return_value = what_kind_of_float(format_letter, &precision, &exponent_bits); + + if (return_value != 0) { + make_invalid_floating_point_number (words); + } else { + if (f->low > f->leader) { + /* 0.0e0 seen. */ +memset(words, '\0', sizeof(LITTLENUM_TYPE) * precision); + } else { + long exponent_1; + long exponent_2; + long exponent_3; + long exponent_4; + int exponent_skippage; + LITTLENUM_TYPE word1; + + /* JF: Deal with new Nan, +Inf and -Inf codes */ + if (f->sign != '-' && f->sign != '+') { + make_invalid_floating_point_number(words); + return return_value; + } + /* + * All vaxen floating_point formats (so far) have: + * Bit 15 is sign bit. + * Bits 14:n are excess-whatever exponent. + * Bits n-1:0 (if any) are most significant bits of fraction. + * Bits 15:0 of the next word are the next most significant bits. + * And so on for each other word. + * + * All this to be compatible with a KF11?? (Which is still faster + * than lots of vaxen I can think of, but it also has higher + * maintenance costs ... sigh). + * + * So we need: number of bits of exponent, number of bits of + * mantissa. + */ + +#ifdef NEVER /******* This zeroing seems redundant - Dean 3may86 **********/ + /* + * No matter how few bits we got back from the atof() + * routine, add enough zero littlenums so the rest of the + * code won't run out of "significant" bits in the mantissa. + */ + { + LITTLENUM_TYPE *ltp; + for (ltp = f->leader + 1; + ltp <= f->low + precision; + ltp++) { + *ltp = 0; + } + } +#endif + + bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS; + littlenum_pointer = f->leader; + littlenum_end = f->low; + /* Seek (and forget) 1st significant bit */ + for (exponent_skippage = 0; + ! next_bits(1); + exponent_skippage ++) ;; + + exponent_1 = f->exponent + f->leader + 1 - f->low; + /* Radix LITTLENUM_RADIX, point just higher than f->leader. */ + exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS; + /* Radix 2. */ + exponent_3 = exponent_2 - exponent_skippage; + /* Forget leading zeros, forget 1st bit. */ + exponent_4 = exponent_3 + (1 << (exponent_bits - 1)); + /* Offset exponent. */ + + if (exponent_4 & ~mask[exponent_bits]) { + /* + * Exponent overflow. Lose immediately. + */ + + make_invalid_floating_point_number (words); + + /* + * We leave return_value alone: admit we read the + * number, but return a floating exception + * because we can't encode the number. + */ + } else { + lp = words; + + /* Word 1. Sign, exponent and perhaps high bits. */ + /* Assume 2's complement integers. */ + word1 = (((exponent_4 &mask[exponent_bits]) << (15 - exponent_bits)) + | ((f->sign == '+') ? 0 : 0x8000) + | next_bits(15 - exponent_bits)); + *lp++ = word1; + + /* The rest of the words are just mantissa bits. */ + for (; lp < words + precision; lp++) { + *lp = next_bits(LITTLENUM_NUMBER_OF_BITS); + } + + if (next_bits (1)) { + /* + * Since the NEXT bit is a 1, round UP the mantissa. + * The cunning design of these hidden-1 floats permits + * us to let the mantissa overflow into the exponent, and + * it 'does the right thing'. However, we lose if the + * highest-order bit of the lowest-order word flips. + * Is that clear? + */ + + unsigned long carry; + + /* + #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2) + Please allow at least 1 more bit in carry than is in a LITTLENUM. + We need that extra bit to hold a carry during a LITTLENUM carry + propagation. Another extra bit (kept 0) will assure us that we + don't get a sticky sign bit after shifting right, and that + permits us to propagate the carry without any masking of bits. + #endif + */ + for (carry = 1, lp--; + carry && (lp >= words); + lp--) { + carry = *lp + carry; + *lp = carry; + carry >>= LITTLENUM_NUMBER_OF_BITS; + } + + if ((word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1))) { + make_invalid_floating_point_number(words); + /* + * We leave return_value alone: admit we read the + * number, but return a floating exception + * because we can't encode the number. + */ + } + } /* if (we needed to round up) */ + } /* if (exponent overflow) */ + } /* if (0.0e0) */ + } /* if (float_type was OK) */ + return(return_value); +} /* flonum_gen2vax() */ + + +/* JF this used to be in vax.c but this looks like a better place for it */ + +/* + * md_atof() + * + * In: input_line_pointer->the 1st character of a floating-point + * number. + * 1 letter denoting the type of statement that wants a + * binary floating point number returned. + * Address of where to build floating point literal. + * Assumed to be 'big enough'. + * Address of where to return size of literal (in chars). + * + * Out: Input_line_pointer->of next char after floating number. + * Error message, or "". + * Floating point literal. + * Number of chars we used for the literal. + */ + +#define MAXIMUM_NUMBER_OF_LITTLENUMS (8) /* For .hfloats. */ + +char * + md_atof (what_statement_type, literalP, sizeP) +char what_statement_type; +char * literalP; +int * sizeP; +{ + LITTLENUM_TYPE words[MAXIMUM_NUMBER_OF_LITTLENUMS]; + register char kind_of_float; + register int number_of_chars; + register LITTLENUM_TYPE * littlenum_pointer; + + switch (what_statement_type) + { + case 'F': /* .float */ + case 'f': /* .ffloat */ + kind_of_float = 'f'; + break; + + case 'D': /* .double */ + case 'd': /* .dfloat */ + kind_of_float = 'd'; + break; + + case 'g': /* .gfloat */ + kind_of_float = 'g'; + break; + + case 'h': /* .hfloat */ + kind_of_float = 'h'; + break; + + default: + kind_of_float = 0; + break; + }; + + if (kind_of_float) + { + register LITTLENUM_TYPE * limit; + + input_line_pointer = atof_vax (input_line_pointer, + kind_of_float, + words); + /* + * The atof_vax() builds up 16-bit numbers. + * Since the assembler may not be running on + * a little-endian machine, be very careful about + * converting words to chars. + */ + number_of_chars = atof_vax_sizeof (kind_of_float); + know( number_of_chars <= MAXIMUM_NUMBER_OF_LITTLENUMS * sizeof(LITTLENUM_TYPE) ); + limit = words + (number_of_chars / sizeof(LITTLENUM_TYPE)); + for (littlenum_pointer = words; + littlenum_pointer < limit; + littlenum_pointer ++) + { + md_number_to_chars (literalP, * littlenum_pointer, sizeof(LITTLENUM_TYPE)); + literalP += sizeof(LITTLENUM_TYPE); + }; + } + else + { + number_of_chars = 0; + }; + + * sizeP = number_of_chars; + return (kind_of_float ? "" : "Bad call to md_atof()"); +} /* md_atof() */ + +/* end of atof-vax.c */ diff --git a/gnu/usr.bin/as/config/coff.h b/gnu/usr.bin/as/config/coff.h new file mode 100644 index 000000000000..bcbb343695bc --- /dev/null +++ b/gnu/usr.bin/as/config/coff.h @@ -0,0 +1,783 @@ +/* coff.h + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * At this point I'm sure this file is right for i960 and I'm pretty sure it's + * right for a29k, although it hasn't been tested rigorously. Please feel free + * to add your own machine's description here. Without that info, it isn't + * possible to build cross development tools from elsewhere nor is it easy to + * continue to support your machines format. + * + * The TC_foo ifdef's are mine. They are what gas uses. The other ifdef's + * remain for documentation from other scavenged files. xoxorich. + */ + +/********************** FILE HEADER **********************/ + +struct filehdr { + unsigned short f_magic; /* magic number */ + unsigned short f_nscns; /* number of sections */ + long f_timdat; /* time & date stamp */ + long f_symptr; /* file pointer to symtab */ + long f_nsyms; /* number of symtab entries */ + unsigned short f_opthdr; /* sizeof(optional hdr) */ + unsigned short f_flags; /* flags */ +}; + +/* Bits for f_flags: + * F_RELFLG relocation info stripped from file + * F_EXEC file is executable (no unresolved externel references) + * F_LNNO line nunbers stripped from file + * F_LSYMS local symbols stripped from file + * F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax) + */ +#define F_RELFLG (0x0001) +#define F_EXEC (0x0002) +#define F_LNNO (0x0004) +#define F_LSYMS (0x0008) + +#ifdef TC_I960 +#define F_AR32WR (0x0010) /* File has 32 bits per word, least + significant byte first. */ +#else /* TC_I960 */ +#define F_AR32WR (0x0100) +#endif /* TC_I960 */ + +#define F_MINMAL (0x0010) /* ??? */ +#define F_UPDATE (0x0020) /* ??? */ +#define F_SWABD (0x0040) /* ??? */ +#define F_AR16WR (0x0080) /* File has the byte ordering used by + the PDP*-11/70 processor. */ +#define F_AR32W (0x0200) /* File has 32 bits per word, most + significant byte first. */ + +/* + * Intel 80960 (I960) processor flags. + * F_I960TYPE == mask for processor type field. + */ + +#define F_I960TYPE (0xf000) +#define F_I960CORE (0x1000) +#define F_I960KB (0x2000) +#define F_I960SB (0x2000) +#define F_I960MC (0x3000) +#define F_I960XA (0x4000) +#define F_I960CA (0x5000) +#define F_I960KA (0x6000) +#define F_I960SA (0x6000) + +/* + * i80960 Magic Numbers + */ + +#define I960ROMAGIC (0x160) /* read-only text segments */ +#define I960RWMAGIC (0x161) /* read-write text segments */ + +#define I960BADMAG(x) (((x).f_magic != I960ROMAGIC) && ((x).f_magic != I960RWMAGIC)) + +#define SIPFBOMAGIC (0x17a) /* Am29000 (Byte 0 is MSB - Big Endian) */ +#define SIPRBOMAGIC (0x17b) /* Am29000 (Byte 0 is LSB - Little Endian) */ + +#define A29KBADMAG(x) (((x).f_magic != SIPFBOMAGIC) && ((x).f_magic != SIPRBOMAGIC)) + +#ifdef TE_I386AIX +# define I386MAGIC (0x175) /* Danbury AIX C compiler */ +# define I386SVMAGIC (0x14c) /* System V C Compiler */ +# define I386BADMAG(x) (((x).f_magic != I386MAGIC) && \ + ((x).f_magic != I386SVMAGIC)) +#else /* not TE_I386AIX */ +# define I386MAGIC 0x14c +# define I386BADMAG(x) (((x).f_magic != I386MAGIC)) +#endif /* not TE_I386AIX */ + + +#define FILHDR struct filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + +typedef struct { + unsigned long phys_addr; + unsigned long bitarray; +} TAGBITS; + +/* These appear to be used only by exec(2). I don't know who cares + about them in a cross development environment. In any case, this + is my collection after researching the issue for a few hours. + Apparently, most have these have remained essentially unchanged + since v7 days, although a few new ones have been added. xoxorich. */ + +#define BAD0MAGIC (0401) /* (?) "lpd (UNIX/RT)" */ +#define BAD1MAGIC (0405) /* (?) overlay */ +#define OMAGIC (0407) /* old impure format. data immediately + follows text. both sections are rw. */ +#define NMAGIC (0410) /* split i&d, read-only text */ +#define A_MAGIC3 (0411) /* (?) "separated I&D" */ +#define ZMAGIC (0413) /* like NMAGIC, but demand loaded */ +#define PAGEMAGIC2 (0414) /* (?) like ZMAGIC, but address zero + explicitly unmapped. */ +#define REGMAGIC (0414) /* (?) a PAGEMAGIC2 alias? */ +#define PAGEMAGIC3 (0415) /* (?) like ZMAGIC, but address zero mapped. */ +#define A_MAGIC5 (0437) /* (?) "system overlay, separated I&D" */ +/* intended for non-unix cross development */ +#define SASMAGIC (010000) /* Single Address Space */ +#define MASMAGIC (020000) /* (?) "Multiple (separate I & D) Address Spaces" */ + +typedef struct aouthdr { + short magic; /* type of file */ + short vstamp; /* version stamp */ + unsigned long tsize; /* text size in bytes, padded to FW bdry*/ + unsigned long dsize; /* initialized data " " */ + unsigned long bsize; /* uninitialized data " " */ +#if U3B + unsigned long dum1; + unsigned long dum2; /* pad to entry point */ +#endif + unsigned long entry; /* entry pt. */ + unsigned long text_start; /* base of text used for this file */ + unsigned long data_start; /* base of data used for this file */ + /* CAREFUL: some formats omit the tagentries member. */ + unsigned long tagentries; /* number of tag entries to + follow (always zero for i960) */ +} AOUTHDR; + +/* return a pointer to the tag bits array */ + +#define TAGPTR(aout) ((TAGBITS *) (&(aout.tagentries)+1)) + +/* compute size of a header */ + +/*#define AOUTSZ(aout) (sizeof(AOUTHDR)+(aout.tagentries*sizeof(TAGBITS)))*/ +#define AOUTSZ (sizeof(AOUTHDR)) + + +/********************** STORAGE CLASSES **********************/ + +#define C_EFCN -1 /* physical end of function */ +#define C_NULL 0 +#define C_AUTO 1 /* automatic variable */ +#define C_EXT 2 /* external symbol */ +#define C_STAT 3 /* static */ +#define C_REG 4 /* register variable */ +#define C_EXTDEF 5 /* external definition */ +#define C_LABEL 6 /* label */ +#define C_ULABEL 7 /* undefined label */ +#define C_MOS 8 /* member of structure */ +#define C_ARG 9 /* function argument */ +#define C_STRTAG 10 /* structure tag */ +#define C_MOU 11 /* member of union */ +#define C_UNTAG 12 /* union tag */ +#define C_TPDEF 13 /* type definition */ +#define C_USTATIC 14 /* undefined static */ +#define C_ENTAG 15 /* enumeration tag */ +#define C_MOE 16 /* member of enumeration */ +#define C_REGPARM 17 /* register parameter */ +#define C_FIELD 18 /* bit field */ + +#ifdef TC_I960 +#define C_AUTOARG 19 /* auto argument */ +#define C_LASTENT 20 /* dummy entry (end of block) */ +#endif /* TC_I960 */ + +#ifdef TC_A29K +#define C_GLBLREG 19 /* global register */ +#define C_EXTREG 20 /* external global register */ +#define C_DEFREG 21 /* ext. def. of global register */ +#define C_STARTOF 22 /* as29 $SIZEOF and $STARTOF symbols */ +#endif /* TC_A29K */ + +#define C_BLOCK 100 /* ".bb" or ".eb" */ +#define C_FCN 101 /* ".bf" or ".ef" */ +#define C_EOS 102 /* end of structure */ +#define C_FILE 103 /* file name */ +#define C_LINE 104 /* line # reformatted as symbol table entry */ +#define C_ALIAS 105 /* duplicate tag */ +#define C_HIDDEN 106 /* ext symbol in dmert public lib. like static, + used to avoid name conflicts. */ + +#ifdef TC_I960 +/* New storage classes for 80960 */ +#define C_SCALL 107 /* Procedure reachable via system call */ +/* C_LEAFPROC is obsolete. Use C_LEAFEXT or C_LEAFSTAT */ +#define C_LEAFPROC 108 /* Leaf procedure, "call" via BAL */ +#define C_LEAFEXT 108 +#define C_OPTVAR 109 /* Optimized variable */ +#define C_DEFINE 110 /* Preprocessor #define */ +#define C_PRAGMA 111 /* Advice to compiler or linker */ +#define C_SEGMENT 112 /* 80960 segment name */ +#define C_LEAFSTAT 113 /* Static leaf */ +#endif /* TC_I960 */ + +#ifdef TC_A29K +#define C_SHADOW 107 /* shadow symbol */ +#endif /* TC_A29K */ + +/********************** SECTION HEADER **********************/ + +struct scnhdr { + char s_name[8]; /* section name */ + long s_paddr; /* physical address, aliased s_nlib */ + long s_vaddr; /* virtual address */ + long s_size; /* section size */ + long s_scnptr; /* file ptr to raw data for section */ + long s_relptr; /* file ptr to relocation */ + long s_lnnoptr; /* file ptr to line numbers */ + unsigned short s_nreloc; /* number of relocation entries */ + unsigned short s_nlnno; /* number of line number entries */ + long s_flags; /* flags */ + +#ifdef TC_I960 + unsigned long s_align; /* section alignment */ +#endif /* TC_I960 */ +}; + +#define SCNHDR struct scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/* + * names of "special" sections + */ +#define _TEXT ".text" /* executable code section */ +#define _DATA ".data" /* initialized data */ +#define _BSS ".bss" /* un-initialized data */ +#define _DEBUG ".debug" /* special section used by dbx */ +#define _COMMENT ".comment" /* version info */ +#define _LIB ".lib" /* shared lib info section */ +#define _TV ".tv" + +/* + * s_flags "type" + */ + +/* + * In instances where it is necessary for a linker to + * produce an output file which contains text or data not + * based at virtual address 0, e.g. for a ROM, then the + * linker should accept address base information as command + * input and use PAD sections to skip over unused addresses. + * (at least for a29k. Maybe others.) + */ + +#define STYP_REG (0x0000) /* "regular" section: allocated, relocated, loaded */ +#define STYP_DSECT (0x0001) /* "dummy" section: not allocated, relocated, not loaded */ +#define STYP_NOLOAD (0x0002) /* "noload" section: allocated, relocated, not loaded */ +#define STYP_GROUP (0x0004) /* "grouped" section: formed of input sections */ +#define STYP_PAD (0x0008) /* "padding" section: not allocated, not relocated, loaded */ +#define STYP_COPY (0x0010) /* "copy" section: for decision function used by field update; not allocated, not relocated, + loaded; reloc & lineno entries processed normally */ +#define STYP_TEXT (0x0020) /* section contains text only */ +#define S_SHRSEG (0x0020) /* In 3b Update files (output of ogen), sections which appear in SHARED segments of the Pfile + will have the S_SHRSEG flag set by ogen, to inform dufr that updating 1 copy of the proc. will + update all process invocations. */ +#define STYP_DATA (0x0040) /* section contains data only */ +#define STYP_BSS (0x0080) /* section contains bss only */ +#define S_NEWFCN (0x0100) /* In a minimal file or an update file, a new function (as compared with a replaced function) */ +#define STYP_INFO (0x0200) /* comment section : not allocated not relocated, not loaded */ +#define STYP_OVER (0x0400) /* overlay section : relocated not allocated or loaded */ +#define STYP_LIB (0x0800) /* for .lib section : same as INFO */ +#define STYP_MERGE (0x2000) /* merge section -- combines with text, data or bss sections only */ +#define STYP_REVERSE_PAD (0x4000) /* section will be padded with no-op instructions wherever padding is necessary and there is a + word of contiguous bytes beginning on a word boundary. */ + +#ifdef TC_A29K +/* NOTE: The use of STYP_BSSREG for relocation is not yet defined. */ +#define STYP_BSSREG 0x1200 /* Global register area (like STYP_INFO) */ +#define STYP_ENVIR 0x2200 /* Environment (like STYP_INFO) */ +#define STYP_ABS 0x4000 /* Absolute (allocated, not reloc, loaded) */ +#define STYP_LIT 0x8020 /* Literal data (like STYP_TEXT) */ +#endif /* TC_A29K */ + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct lineno { + union { + long l_symndx; /* symbol index of function name, iff l_lnno == 0*/ + long l_paddr; /* (physical) address of line number */ + } l_addr; + unsigned short l_lnno; /* line number */ +#ifdef TC_I960 + /* not used on a29k */ + char padding[2]; /* force alignment */ +#endif /* TC_I960 */ +}; + +#define LINENO struct lineno +#define LINESZ sizeof(LINENO) + + +/********************** SYMBOLS **********************/ + +#define SYMNMLEN 8 /* # characters in a symbol name */ +#define FILNMLEN 14 /* # characters in a file name */ +#define DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct syment { + union { + char _n_name[SYMNMLEN]; /* old COFF version */ + struct { + long _n_zeroes; /* new == 0 */ + long _n_offset; /* offset into string table */ + } _n_n; + char *_n_nptr[2]; /* allows for overlaying */ + } _n; + long n_value; /* value of symbol */ + short n_scnum; /* section number */ + +#ifdef TC_I960 + /* This isn't yet used on the i960. In some formats this + is two bytes of padding. In others, it is missing entirely. */ + unsigned short n_flags; /* copy of flags from filhdr */ +#endif /* TC_I960 */ + +#ifdef TC_A29K + unsigned short n_type; /* type and derived type */ +#else /* TC_A29K */ + /* at least i960 uses long */ + unsigned long n_type; /* type and derived type */ +#endif /* TC_A29K */ + + char n_sclass; /* storage class */ + char n_numaux; /* number of aux. entries */ + +#ifndef TC_A29K + char pad2[2]; /* force alignment */ +#endif /* TC_A29K */ +}; + +#define SYMENT struct syment +#define SYMESZ sizeof(SYMENT) /* This had better also be sizeof(AUXENT) */ + +#define n_name _n._n_name +#define n_ptr _n._n_nptr[1] +#define n_zeroes _n._n_n._n_zeroes +#define n_offset _n._n_n._n_offset + + /* + * Relocatable symbols have number of the section in which they are defined, + * or one of the following: + */ + +#define N_SCNUM ((short) 1-65535) /* section num where symbol defined */ +#define N_UNDEF ((short)0) /* undefined symbol */ +#define N_ABS ((short)-1) /* value of symbol is absolute */ +#define N_DEBUG ((short)-2) /* debugging symbol -- symbol value is meaningless */ +#define N_TV ((short)-3) /* indicates symbol needs preload transfer vector */ +#define P_TV ((short)-4) /* indicates symbol needs transfer vector (postload) */ + +/* + * Type of a symbol, in low 4 bits of the word + */ +#define T_NULL 0 /* type not assigned */ +#define T_VOID 1 /* function argument (only used by compiler) (but now real void). */ +#define T_CHAR 2 /* character */ +#define T_SHORT 3 /* short integer */ +#define T_INT 4 /* integer */ +#define T_LONG 5 /* long integer */ +#define T_FLOAT 6 /* floating point */ +#define T_DOUBLE 7 /* double word */ +#define T_STRUCT 8 /* structure */ +#define T_UNION 9 /* union */ +#define T_ENUM 10 /* enumeration */ +#define T_MOE 11 /* member of enumeration */ +#define T_UCHAR 12 /* unsigned character */ +#define T_USHORT 13 /* unsigned short */ +#define T_UINT 14 /* unsigned integer */ +#define T_ULONG 15 /* unsigned long */ + +#ifdef TC_I960 +#define T_LNGDBL 16 /* long double */ +#endif /* TC_I960 */ + +/* + * derived types, in n_type + */ +#define DT_NON (0) /* no derived type */ +#define DT_PTR (1) /* pointer */ +#define DT_FCN (2) /* function */ +#define DT_ARY (3) /* array */ + +#ifndef TC_I960 + +#define N_BTMASK (0x0f) +#define N_TMASK (0x30) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + +#else /* TC_I960 */ + +#define N_BTMASK (0x1f) +#define N_TMASK (0x60) +#define N_BTSHFT (5) +#define N_TSHIFT (2) + +#endif /* TC_I960 */ + +#define BTYPE(x) ((x) & N_BTMASK) + +#define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT)) +#define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT)) +#define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT)) + +#define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) + +union auxent { + struct { + long x_tagndx; /* str, un, or enum tag indx */ + union { + struct { + unsigned short x_lnno; /* declaration line number */ + unsigned short x_size; /* str/union/array size */ + } x_lnsz; + long x_fsize; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + long x_lnnoptr; /* ptr to fcn line # */ + long x_endndx; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + unsigned short x_dimen[DIMNUM]; + } x_ary; + } x_fcnary; + unsigned short x_tvndx; /* tv index */ + } x_sym; + + /* This was just a struct x_file with x_fname only in a29k. xoxorich. */ + union { + char x_fname[FILNMLEN]; + struct { + long x_zeroes; + long x_offset; + } x_n; + } x_file; + + struct { + long x_scnlen; /* section length */ + unsigned short x_nreloc; /* # relocation entries */ + unsigned short x_nlinno; /* # line numbers */ + } x_scn; + + struct { + long x_tvfill; /* tv fill value */ + unsigned short x_tvlen; /* length of .tv */ + + /* This field was typo'd x_tvrna on a29k. xoxorich. */ + unsigned short x_tvran[2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + +#ifdef TC_I960 + /****************************************** + * I960-specific *2nd* aux. entry formats + ******************************************/ + struct { + /* This is a very old typo that keeps getting propogated. */ +#define x_stdindx x_stindx + long x_stindx; /* sys. table entry */ + } x_sc; /* system call entry */ + + struct { + unsigned long x_balntry; /* BAL entry point */ + } x_bal; /* BAL-callable function */ + + struct { + unsigned long x_timestamp; /* time stamp */ + char x_idstring[20]; /* producer identity string */ + } x_ident; /* Producer ident info */ + + char a[sizeof(struct syment)]; /* force auxent/syment sizes to match */ +#endif /* TC_I960 */ +}; + +#define AUXENT union auxent +#define AUXESZ sizeof(AUXENT) /* This had better also be sizeof(SYMENT) */ + +#if VAX || I960 +# define _ETEXT "_etext" +#else +# define _ETEXT "etext" +#endif + +/********************** RELOCATION DIRECTIVES **********************/ + +struct reloc { + long r_vaddr; /* Virtual address of reference */ + long r_symndx; /* Index into symbol table */ + unsigned short r_type; /* Relocation type */ +#ifdef TC_I960 + /* not used for a29k */ + char pad[2]; /* Unused */ +#endif /* TC_I960 */ +}; + +#define RELOC struct reloc +#define RELSZ sizeof(RELOC) + +#define R_ABS (0x00) /* reference is absolute */ + +#ifdef TC_I960 +#define R_RELLONG (0x11) /* Direct 32-bit relocation */ +#define R_IPRSHORT (0x18) +#define R_IPRMED (0x19) /* 24-bit ip-relative relocation */ +#define R_IPRLONG (0x1a) +#define R_OPTCALL (0x1b) /* 32-bit optimizable call (leafproc/sysproc) */ +#define R_OPTCALLX (0x1c) /* 64-bit optimizable call (leafproc/sysproc) */ +#define R_GETSEG (0x1d) +#define R_GETPA (0x1e) +#define R_TAGWORD (0x1f) +#endif /* TC_I960 */ + +#ifdef TC_A29K +/* + * NOTE: All the "I" forms refer to Am29000 instruction + * formats. The linker is expected to know how the numeric + * information is split and/or aligned within the + * instruction word(s). R_BYTE works for instructions, too. + * + * If the parameter to a CONSTH instruction is a relocatable + * type, two relocation records are written. The first has + * an r_type of R_IHIHALF (33 octal) and a normal r_vaddr + * and r_symndx. The second relocation record has an r_type + * of R_IHCONST (34 octal), a normal r_vaddr (which is + * redundant), and an r_symndx containing the 32-bit + * constant offset to the relocation instead of the actual + * symbol table index. This second record is always + * written, even if the constant offset is zero. The + * constant fields of the instruction are set to zero. + */ + +#define R_IREL (0x18) /* instruction relative (jmp/call) */ +#define R_IABS (0x19) /* instruction absolute (jmp/call) */ +#define R_ILOHALF (0x1a) /* instruction low half (const) */ +#define R_IHIHALF (0x1b) /* instruction high half (consth) part 1 */ +#define R_IHCONST (0x1c) /* instruction high half (consth) part 2 + constant offset of R_IHIHALF relocation */ +#define R_BYTE (0x1d) /* relocatable byte value */ +#define R_HWORD (0x1e) /* relocatable halfword value */ +#define R_WORD (0x1f) /* relocatable word value */ +#define R_IGLBLRC (0x20) /* instruction global register RC */ +#define R_IGLBLRA (0x21) /* instruction global register RA */ +#define R_IGLBLRB (0x22) /* instruction global register RB */ +#endif /* TC_A29K */ + + +#define DEFAULT_DATA_SECTION_ALIGNMENT 4 +#define DEFAULT_BSS_SECTION_ALIGNMENT 4 +#define DEFAULT_TEXT_SECTION_ALIGNMENT 16 +/* For new sections we haven't heard of before */ +#define DEFAULT_SECTION_ALIGNMENT 4 + +#if defined(TC_I386) +/* + * X86 generic + * 8-bit offset reference in 8-bits + * 8-bit offset reference in 16-bits + * 12-bit segment reference + * auxiliary relocation entry + */ +#define R_OFF8 07 +#define R_OFF16 010 +#define R_SEG12 011 +#define R_AUX 013 + +/* + * B16 and X86 generics + * 16-bit direct reference + * 16-bit "relative" reference + * 16-bit "indirect" (TV) reference + */ +#define R_DIR16 01 +#define R_REL16 02 +#define R_IND16 03 + +/* + * 3B generic + * 24-bit direct reference + * 24-bit "relative" reference + * 16-bit optimized "indirect" TV reference + * 24-bit "indirect" TV reference + * 32-bit "indirect" TV reference + */ +#define R_DIR24 04 +#define R_REL24 05 +#define R_OPT16 014 +#define R_IND24 015 +#define R_IND32 016 + +/* + * XL generics + * 10-bit direct reference + * 10-bit "relative" reference + * 32-bit "relative" reference + */ +#define R_DIR10 025 +#define R_REL10 026 +#define R_REL32 027 + +/* + * 3B and M32 generics + * 32-bit direct reference + */ +#define R_DIR32 06 + +/* + * M32 generic + * 32-bit direct reference with bytes swapped + */ +#define R_DIR32S 012 + +#endif /* TC_I386 */ + +#if defined(TE_I386AIX) + +#define UINFOSIZ 64 /* size of user info buffer */ +typedef char uinfo_t[UINFOSIZ]; + +struct env387 { + unsigned short control; + unsigned short r0; + unsigned short status; + unsigned short r1; + unsigned short tag; + unsigned short r2; + unsigned long eip; + unsigned short code_seg; + unsigned short opcode; + unsigned long operand; + unsigned short operand_seg; + unsigned short r3; + unsigned char regs[8][10]; +}; + +#define CD_NAMELEN 16 /* length of most names in this header */ +#define CORHDRSIZ 2048 /* size to which header is padded out */ +#define MAX_CORE_SEGS 32 /* maximum segments in a core dump */ +#define NUM_FREGS 1 /* # of saved FP regs */ + +/* + * These are defined such that 286 and 386 kernels can produce + * compatible dumps. + */ +#define CD_AX 0 +#define CD_BX 1 +#define CD_CX 2 +#define CD_DX 3 +#define CD_SI 4 +#define CD_DI 5 +#define CD_BP 6 +#define CD_SP 7 +#define CD_FL 8 +#define CD_IP 9 +#define CD_CS 10 +#define CD_DS 11 +#define CD_ES 12 +#define CD_FS 13 +#define CD_GS 14 +#define CD_SS 15 +#define NUM_REGS 16 + +#ifndef SPATHLEN +# define SPATHLEN 16 /* sys/param.h */ +#endif +#ifndef NSIG +# define NSIG 63 /* sys/signal.h */ +# define SIGSETSZ ((NSIG+31)/32) +typedef struct ksigmask { + unsigned long sigs[SIGSETSZ]; +} ksigmask_t; +#endif + +struct corehdr { + char cd_magic[4]; /* COR_MAGIC = "core" */ + + /* general information about the dump itself */ + struct dumpseg { /* table of contents for dump */ + long cs_type; /* seg. type; see below */ + long cs_len; /* length (in bytes) of segment */ + long cs_offset; /* offset (in dump) of segment */ + long cs_address; /* address segment had in mem */ + } cd_segs[MAX_CORE_SEGS]; + + /* general information about the process */ + char cd_comm[CD_NAMELEN]; /* command being run */ + char cd_mach[CD_NAMELEN]; /* type of machine it ran on */ + char cd_site[CD_NAMELEN]; /* name of site it ran on */ + long cd_ldtype; /* type of load module running */ + char cd_intsize; /* sizeof(int) */ + char cd_dptrsize; /* sizeof(char *) */ + char cd_tptrsize; /* sizeof(int (*)()) */ + char cd_unused; + + /* user-mode program state */ + long cd_regs[NUM_REGS]; /* user-mode general registers */ + struct env387 cd_fpregs; /* user-mode floating-point state */ + + /* kernel-mode program state */ + int (*cd_sig[NSIG])(); /* disposition of signals */ + ksigmask_t cd_sigmask; /* signals to be blocked */ + ksigmask_t cd_sigpend; /* signals currently pending */ + long cd_cursig; /* signal that caused the dump */ + + long cd_pid; /* process ID of the corpse */ + long cd_ppid; /* parent process ID of corpse */ + short cd_uid; /* process effective user ID */ + short cd_ruid; /* process real user ID */ + short cd_gid; /* process effective group ID */ + short cd_rgid; /* process real group ID */ + + uinfo_t cd_uinfo; /* buffer of user information */ + char cd_locname[32]; /* name of /local */ + char cd_uvers[CD_NAMELEN]; /* user version string */ + unsigned short cd_spath[SPATHLEN]; /* sitepath */ +}; + +#ifndef NOCHECKS +/* this will generate an error if sizeof(struct corehdr) > CORHDRSIZ */ +struct { char xxcdxx[CORHDRSIZ+1-sizeof(struct corehdr)]; }; +#endif /* ! NOCHECKS */ + +/* + * segment types (in cs_type) + * each segment in the address space appears here, whether or not it + * is actually dumped. Read/only segments will not actually be dumped. + * A segment that is not in the dump will have a cs_offset of zero. + */ +#define COR_TYPE_CODE 'x' /* process code - NOT IN DUMP */ +#define COR_TYPE_DATA 'd' /* process data segment */ +#define COR_TYPE_STACK 's' /* process stack segment */ +#define COR_TYPE_LIBCODE 'X' /* shared lib code - NOT IN DUMP*/ +#define COR_TYPE_LIBDATA 'D' /* shared lib data */ +#define COR_TYPE_READ 'r' /* other read/only - NOT IN DUMP*/ +#define COR_TYPE_WRITE 'w' /* other writeable */ +#define COR_TYPE_MSC '?' /* other, mapped in segment */ + +#endif /* TE_I386AIX */ + +/* + * Local Variables: + * comment-column: 0 + * End: + */ + +/* end of coff.h */ diff --git a/gnu/usr.bin/as/config/cplus-dem.c b/gnu/usr.bin/as/config/cplus-dem.c new file mode 100644 index 000000000000..e3819bc098d8 --- /dev/null +++ b/gnu/usr.bin/as/config/cplus-dem.c @@ -0,0 +1,927 @@ +/* Demangler for GNU C++ + Copyright (C) 1989, 1992 Free Software Foundation, Inc. + written by James Clark (jjc@jclark.uucp) + + 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 2, 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. */ + +/* This is for g++ 1.36.1 (November 6 version). It will probably + require changes for any other version. */ + +/* This file exports one function + + char *cplus_demangle (const char *name) + + If `name' is a mangled function name produced by g++, then + a pointer to a malloced string giving a C++ representation + of the name will be returned; otherwise NULL will be returned. + It is the caller's responsibility to free the string which + is returned. + + For example, + + cplus_demangle ("_foo__1Ai") + + returns + + "A::foo(int)" + + This file imports xmalloc and xrealloc, which are like malloc and + realloc except that they generate a fatal error if there is no + available memory. */ + +/* #define nounderscore 1 /* define this is names don't start with _ */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#if !defined(sequent) && !defined(NeXT) +#include <memory.h> +#else +#define memcpy(s1, s2, n) strncpy(s1, s2, n) +#define memcmp(s1, s2, n) strncmp(s1, s2, n) +#define strchr(s, c) index(s, c) +#endif + +#if __STDC__ != 1 +#define const +#endif + +#if __STDC__ == 1 +extern char *cplus_demangle (const char *type); +#else +extern char *cplus_demangle (); +#endif + +#if __STDC__ == 1 +extern char *xmalloc (int); +extern char *xrealloc (char *, int); +#else +extern char *xmalloc (); +extern char *xrealloc (); +#endif + +static char **typevec = 0; +static int ntypes = 0; +static int typevec_size = 0; + +static struct { + const char *in; + const char *out; +} optable[] = { + "new", " new", + "delete", " delete", + "ne", "!=", + "eq", "==", + "ge", ">=", + "gt", ">", + "le", "<=", + "lt", "<", + "plus", "+", + "minus", "-", + "mult", "*", + "negate", "-", + "trunc_mod", "%", + "trunc_div", "/", + "truth_andif", "&&", + "truth_orif", "||", + "postincrement", "++", + "postdecrement", "--", + "bit_ior", "|", + "bit_xor", "^", + "bit_and", "&", + "bit_not", "~", + "call", "()", + "cond", "?:", + "alshift", "<<", + "arshift", ">>", + "component", "->", + "nop", "", /* for operator= */ +}; + +/* Beware: these aren't '\0' terminated. */ + +typedef struct { + char *b; /* pointer to start of string */ + char *p; /* pointer after last character */ + char *e; /* pointer after end of allocated space */ +} string; + +#if __STDC__ == 1 +static void string_need (string *s, int n); +static void string_delete (string *s); +static void string_init (string *s); +static void string_clear (string *s); +static int string_empty (string *s); +static void string_append (string *p, const char *s); +static void string_appends (string *p, string *s); +static void string_appendn (string *p, const char *s, int n); +static void string_prepend (string *p, const char *s); +#if 0 +static void string_prepends (string *p, string *s); +#endif +static void string_prependn (string *p, const char *s, int n); +static int get_count (const char **type, int *count); +static int do_args (const char **type, string *decl); +static int do_type (const char **type, string *result); +static int do_arg (const char **type, string *result); +static int do_args (const char **type, string *decl); +static void munge_function_name (string *name); +#else +static void string_need (); +static void string_delete (); +static void string_init (); +static void string_clear (); +static int string_empty (); +static void string_append (); +static void string_appends (); +static void string_appendn (); +static void string_prepend (); +static void string_prepends (); +static void string_prependn (); +static int get_count (); +static int do_args (); +static int do_type (); +static int do_arg (); +static int do_args (); +static void munge_function_name (); +#endif + +char * + cplus_demangle (type) +const char *type; +{ + string decl; + int n; + int success = 0; + int constructor = 0; + int const_flag = 0; + int i; + const char *p; + + if (type == NULL || *type == '\0') + return NULL; +#ifndef nounderscore + if (*type++ != '_') + return NULL; +#endif + p = type; + while (*p != '\0' && !(*p == '_' && p[1] == '_')) + p++; + if (*p == '\0') + { + /* destructor */ + if (type[0] == '_' && type[1] == '$' && type[2] == '_') + { + int n = (strlen (type) - 3)*2 + 3 + 2 + 1; + char *tem = (char *) xmalloc (n); + strcpy (tem, type + 3); + strcat (tem, "::~"); + strcat (tem, type + 3); + strcat (tem, "()"); + return tem; + } + /* static data member */ + if (*type != '_' && (p = strchr (type, '$')) != '\0') + { + int n = strlen (type) + 2; + char *tem = (char *) xmalloc (n); + memcpy (tem, type, p - type); + strcpy (tem + (p - type), "::"); + strcpy (tem + (p - type) + 2, p + 1); + return tem; + } + return NULL; + } + + string_init (&decl); + + if (p == type) + { + if (!isdigit (p[2])) + { + string_delete (&decl); + return NULL; + } + constructor = 1; + } + else + { + string_appendn (&decl, type, p - type); + munge_function_name (&decl); + } + p += 2; + + switch (*p) + { + case 'C': + /* a const member function */ + if (!isdigit (p[1])) + { + string_delete (&decl); + return NULL; + } + p += 1; + const_flag = 1; + /* fall through */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = 0; + do + { + n *= 10; + n += *p - '0'; + p += 1; + } + while (isdigit (*p)); + if (strlen (p) < n) + { + string_delete (&decl); + return NULL; + } + if (constructor) + { + string_appendn (&decl, p, n); + string_append (&decl, "::"); + string_appendn (&decl, p, n); + } + else + { + string_prepend (&decl, "::"); + string_prependn (&decl, p, n); + } + p += n; + success = do_args (&p, &decl); + if (const_flag) + string_append (&decl, " const"); + break; + case 'F': + p += 1; + success = do_args (&p, &decl); + break; + } + + for (i = 0; i < ntypes; i++) + if (typevec[i] != NULL) + free (typevec[i]); + ntypes = 0; + if (typevec != NULL) + { + free ((char *)typevec); + typevec = NULL; + typevec_size = 0; + } + + if (success) + { + string_appendn (&decl, "", 1); + return decl.b; + } + else + { + string_delete (&decl); + return NULL; + } +} + +static int + get_count (type, count) +const char **type; +int *count; +{ + if (!isdigit (**type)) + return 0; + *count = **type - '0'; + *type += 1; + /* see flush_repeats in cplus-method.c */ + if (isdigit (**type)) + { + const char *p = *type; + int n = *count; + do + { + n *= 10; + n += *p - '0'; + p += 1; + } + while (isdigit (*p)); + if (*p == '_') + { + *type = p + 1; + *count = n; + } + } + return 1; +} + +/* result will be initialised here; it will be freed on failure */ + +static int + do_type (type, result) +const char **type; +string *result; +{ + int n; + int done; + int non_empty; + int success; + string decl; + const char *remembered_type; + + string_init (&decl); + string_init (result); + + done = 0; + success = 1; + while (success && !done) + { + int member; + switch (**type) + { + case 'P': + *type += 1; + string_prepend (&decl, "*"); + break; + + case 'R': + *type += 1; + string_prepend (&decl, "&"); + break; + + case 'T': + *type += 1; + if (!get_count (type, &n) || n >= ntypes) + success = 0; + else + { + remembered_type = typevec[n]; + type = &remembered_type; + } + break; + + case 'F': + *type += 1; + if (!string_empty (&decl) && decl.b[0] == '*') + { + string_prepend (&decl, "("); + string_append (&decl, ")"); + } + if (!do_args (type, &decl) || **type != '_') + success = 0; + else + *type += 1; + break; + + case 'M': + case 'O': + { + int constp = 0; + int volatilep = 0; + + member = **type == 'M'; + *type += 1; + if (!isdigit (**type)) + { + success = 0; + break; + } + n = 0; + do + { + n *= 10; + n += **type - '0'; + *type += 1; + } + while (isdigit (**type)); + if (strlen (*type) < n) + { + success = 0; + break; + } + string_append (&decl, ")"); + string_prepend (&decl, "::"); + string_prependn (&decl, *type, n); + string_prepend (&decl, "("); + *type += n; + if (member) + { + if (**type == 'C') + { + *type += 1; + constp = 1; + } + if (**type == 'V') + { + *type += 1; + volatilep = 1; + } + if (*(*type)++ != 'F') + { + success = 0; + break; + } + } + if ((member && !do_args (type, &decl)) || **type != '_') + { + success = 0; + break; + } + *type += 1; + if (constp) + { + if (non_empty) + string_append (&decl, " "); + else + non_empty = 1; + string_append (&decl, "const"); + } + if (volatilep) + { + if (non_empty) + string_append (&decl, " "); + else + non_empty = 1; + string_append (&decl, "volatilep"); + } + break; + } + + case 'C': + if ((*type)[1] == 'P') + { + *type += 1; + if (!string_empty (&decl)) + string_prepend (&decl, " "); + string_prepend (&decl, "const"); + break; + } + + /* fall through */ + default: + done = 1; + break; + } + } + + done = 0; + non_empty = 0; + while (success && !done) + { + switch (**type) + { + case 'C': + *type += 1; + if (non_empty) + string_append (result, " "); + else + non_empty = 1; + string_append (result, "const"); + break; + case 'U': + *type += 1; + if (non_empty) + string_append (result, " "); + else + non_empty = 1; + string_append (result, "unsigned"); + break; + case 'V': + *type += 1; + if (non_empty) + string_append (result, " "); + else + non_empty = 1; + string_append (result, "volatile"); + break; + default: + done = 1; + break; + } + } + + if (success) + switch (**type) + { + case '\0': + case '_': + break; + case 'v': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "void"); + break; + case 'l': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "long"); + break; + case 'i': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "int"); + break; + case 's': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "short"); + break; + case 'c': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "char"); + break; + case 'r': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "long double"); + break; + case 'd': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "double"); + break; + case 'f': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "float"); + break; + case 'G': + *type += 1; + if (!isdigit (**type)) + { + success = 0; + break; + } + /* fall through */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = 0; + do + { + n *= 10; + n += **type - '0'; + *type += 1; + } + while (isdigit (**type)); + if (strlen (*type) < n) + { + success = 0; + break; + } + if (non_empty) + string_append (result, " "); + string_appendn (result, *type, n); + *type += n; + break; + default: + success = 0; + break; + } + + if (success) + { + if (!string_empty (&decl)) + { + string_append (result, " "); + string_appends (result, &decl); + } + string_delete (&decl); + return 1; + } + else + { + string_delete (&decl); + string_delete (result); + return 0; + } +} + +/* `result' will be initialised in do_type; it will be freed on failure */ + +static int + do_arg (type, result) +const char **type; +string *result; +{ + char *tem; + int len; + const char *start; + const char *end; + + start = *type; + if (!do_type (type, result)) + return 0; + end = *type; + if (ntypes >= typevec_size) + { + if (typevec_size == 0) + { + typevec_size = 3; + typevec = (char **) xmalloc (sizeof (char*)*typevec_size); + } + else + { + typevec_size *= 2; + typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size); + } + } + len = end - start; + tem = (char *) xmalloc (len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + typevec[ntypes++] = tem; + return 1; +} + +/* `decl' must be already initialised, usually non-empty; + it won't be freed on failure */ + +static int + do_args (type, decl) +const char **type; +string *decl; +{ + string arg; + int need_comma = 0; + + string_append (decl, "("); + + while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v') + { + if (**type == 'N') + { + int r; + int t; + *type += 1; + if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes) + return 0; + while (--r >= 0) + { + const char *tem = typevec[t]; + if (need_comma) + string_append (decl, ", "); + if (!do_arg (&tem, &arg)) + return 0; + string_appends (decl, &arg); + string_delete (&arg); + need_comma = 1; + } + } + else + { + if (need_comma) + string_append (decl, ", "); + if (!do_arg (type, &arg)) + return 0; + string_appends (decl, &arg); + string_delete (&arg); + need_comma = 1; + } + } + + if (**type == 'v') + *type += 1; + else if (**type == 'e') + { + *type += 1; + if (need_comma) + string_append (decl, ","); + string_append (decl, "..."); + } + + string_append (decl, ")"); + return 1; +} + +static void + munge_function_name (name) +string *name; +{ + if (!string_empty (name) && name->p - name->b >= 3 + && name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$') + { + int i; + /* see if it's an assignment expression */ + if (name->p - name->b >= 10 /* op$assign_ */ + && memcmp (name->b + 3, "assign_", 7) == 0) + { + for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++) + { + int len = name->p - name->b - 10; + if (strlen (optable[i].in) == len + && memcmp (optable[i].in, name->b + 10, len) == 0) + { + string_clear (name); + string_append (name, "operator"); + string_append (name, optable[i].out); + string_append (name, "="); + return; + } + } + } + else + { + for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++) + { + int len = name->p - name->b - 3; + if (strlen (optable[i].in) == len + && memcmp (optable[i].in, name->b + 3, len) == 0) + { + string_clear (name); + string_append (name, "operator"); + string_append (name, optable[i].out); + return; + } + } + } + return; + } + else if (!string_empty (name) && name->p - name->b >= 5 + && memcmp (name->b, "type$", 5) == 0) + { + /* type conversion operator */ + string type; + const char *tem = name->b + 5; + if (do_type (&tem, &type)) + { + string_clear (name); + string_append (name, "operator "); + string_appends (name, &type); + string_delete (&type); + return; + } + } +} + +/* a mini string-handling package */ + +static void + string_need (s, n) +string *s; +int n; +{ + if (s->b == NULL) + { + if (n < 32) + n = 32; + s->p = s->b = (char *) xmalloc (n); + s->e = s->b + n; + } + else if (s->e - s->p < n) + { + int tem = s->p - s->b; + n += tem; + n *= 2; + s->b = (char *) xrealloc (s->b, n); + s->p = s->b + tem; + s->e = s->b + n; + } +} + +static void + string_delete (s) +string *s; +{ + if (s->b != NULL) + { + free (s->b); + s->b = s->e = s->p = NULL; + } +} + +static void + string_init (s) +string *s; +{ + s->b = s->p = s->e = NULL; +} + +static void + string_clear (s) +string *s; +{ + s->p = s->b; +} + +static int + string_empty (s) +string *s; +{ + return s->b == s->p; +} + +static void + string_append (p, s) +string *p; +const char *s; +{ + int n; + if (s == NULL || *s == '\0') + return; + n = strlen (s); + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; +} + +static void + string_appends (p, s) +string *p, *s; +{ + int n; + if (s->b == s->p) + return; + n = s->p - s->b; + string_need (p, n); + memcpy (p->p, s->b, n); + p->p += n; +} + +static void + string_appendn (p, s, n) +string *p; +const char *s; +int n; +{ + if (n == 0) + return; + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; +} + +static void + string_prepend (p, s) +string *p; +const char *s; +{ + if (s == NULL || *s == '\0') + return; + string_prependn (p, s, strlen (s)); +} + +#if 0 +static void + string_prepends (p, s) +string *p, *s; +{ + if (s->b == s->p) + return; + string_prependn (p, s->b, s->p - s->b); +} +#endif + +static void + string_prependn (p, s, n) +string *p; +const char *s; +int n; +{ + char *q; + + if (n == 0) + return; + string_need (p, n); + for (q = p->p - 1; q >= p->b; q--) + q[n] = q[0]; + memcpy (p->b, s, n); + p->p += n; +} + +/* end of cplus-dem.c */ diff --git a/gnu/usr.bin/as/config/ho-ansi.h b/gnu/usr.bin/as/config/ho-ansi.h new file mode 100644 index 000000000000..2af034118eee --- /dev/null +++ b/gnu/usr.bin/as/config/ho-ansi.h @@ -0,0 +1,29 @@ +/* ho-ansi.h Host-specific header file for generic ansi environments. + Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define M_ANSI 1 + +#include <stdlib.h> +#include <string.h> +#include <memory.h> + +#define sys_nerr _sys_nerr +#define sys_errlist _sys_errlist + +/* end of ho-ansi.h */ diff --git a/gnu/usr.bin/as/config/ho-decstation.h b/gnu/usr.bin/as/config/ho-decstation.h new file mode 100644 index 000000000000..1cab4d516e05 --- /dev/null +++ b/gnu/usr.bin/as/config/ho-decstation.h @@ -0,0 +1,29 @@ +/* ho-pmax.h Host-specific header file for decstation 3100. + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <string.h> + +extern char *malloc(); +extern int free(); + +#if !defined(__GNUC__) +#define know(x) +#endif /* not gcc */ + +/* end of ho-decstation.h */ diff --git a/gnu/usr.bin/as/config/ho-generic.h b/gnu/usr.bin/as/config/ho-generic.h new file mode 100644 index 000000000000..493cfc691924 --- /dev/null +++ b/gnu/usr.bin/as/config/ho-generic.h @@ -0,0 +1,30 @@ +/* ho-generic.h Generic host-specific header file. + Copyright 1987, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* It is my intent that this become a file capable of config'ing and + compiling for nearly any host as aid for testing and porting. + xoxorich. */ + +#define M_GENERIC 1 + +#define HAVE_STRERROR + +extern int free(); + +/* end of ho-generic.h */ diff --git a/gnu/usr.bin/as/config/ho-hpux.h b/gnu/usr.bin/as/config/ho-hpux.h new file mode 100644 index 000000000000..d5ff31a83364 --- /dev/null +++ b/gnu/usr.bin/as/config/ho-hpux.h @@ -0,0 +1,34 @@ +/* ho-hpux.h -- Header to compile the assembler under HP-UX + Copyright (C) 1988, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "ho-sysv.h" + +/* This header file contains the #defines specific + to HPUX changes sent me by cph@zurich.ai.mit.edu */ +#ifndef hpux +#define hpux +#endif + +#ifdef setbuffer +#undef setbuffer +#endif /* setbuffer */ + +#define setbuffer(stream, buf, size) + +/* end of ho-hpux.h */ diff --git a/gnu/usr.bin/as/config/ho-i386.h b/gnu/usr.bin/as/config/ho-i386.h new file mode 100644 index 000000000000..154f2e420169 --- /dev/null +++ b/gnu/usr.bin/as/config/ho-i386.h @@ -0,0 +1,30 @@ +/* ho-i386.h i386 specific header file. + Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: ho-i386.h,v 1.1 1993/11/03 00:53:21 paul Exp $ + */ + + +#define HO_I386 1 + +#define NO_STDARG + +#include "ho-sysv.h" + +/* end of ho-i386.h */ diff --git a/gnu/usr.bin/as/config/ho-i386aix.h b/gnu/usr.bin/as/config/ho-i386aix.h new file mode 100644 index 000000000000..d31b51ad57e8 --- /dev/null +++ b/gnu/usr.bin/as/config/ho-i386aix.h @@ -0,0 +1,24 @@ +/* ho-386aix.h AIX PS/2 i386 specific header file. + Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HO_I386 1 + +#include "ho-sysv.h" + +/* end of ho-i386aix.h */ diff --git a/gnu/usr.bin/as/config/ho-rs6000.h b/gnu/usr.bin/as/config/ho-rs6000.h new file mode 100644 index 000000000000..fe57e8e3cd9e --- /dev/null +++ b/gnu/usr.bin/as/config/ho-rs6000.h @@ -0,0 +1,22 @@ +/* ho-rs6000.h Rs6000 host-specific header file. + Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define M_RS6000 1 + +/* end of ho-rs6000.h */ diff --git a/gnu/usr.bin/as/config/ho-sun3.h b/gnu/usr.bin/as/config/ho-sun3.h new file mode 100644 index 000000000000..0d68e6fd358b --- /dev/null +++ b/gnu/usr.bin/as/config/ho-sun3.h @@ -0,0 +1,3 @@ +#include <ho-sunos.h> + +/* end of ho-sun3.h */ diff --git a/gnu/usr.bin/as/config/ho-sun386.h b/gnu/usr.bin/as/config/ho-sun386.h new file mode 100644 index 000000000000..6c74df475988 --- /dev/null +++ b/gnu/usr.bin/as/config/ho-sun386.h @@ -0,0 +1,5 @@ +#include <ho-sunos.h> + +extern int sprintf(); + +/* end of ho-sun386.h */ diff --git a/gnu/usr.bin/as/config/ho-sun4.h b/gnu/usr.bin/as/config/ho-sun4.h new file mode 100644 index 000000000000..cf619e83271c --- /dev/null +++ b/gnu/usr.bin/as/config/ho-sun4.h @@ -0,0 +1,3 @@ +#include <ho-sunos.h> + +/* end of ho-sun4.h */ diff --git a/gnu/usr.bin/as/config/ho-sunos.h b/gnu/usr.bin/as/config/ho-sunos.h new file mode 100644 index 000000000000..1193b1bf5150 --- /dev/null +++ b/gnu/usr.bin/as/config/ho-sunos.h @@ -0,0 +1,81 @@ +/* This file is ho-sunos.h + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if __STDC__ != 1 +#define NO_STDARG +#endif /* not __STDC__ */ + +#if !defined(__GNUC__) && (__STDC__ != 1) +#include <memory.h> +#else +extern int memset(); +#endif + +/* #include <sys/stdtypes.h> before <stddef.h> when compiling by GCC. */ +#include <sys/stdtypes.h> +#include <stddef.h> +#include <ctype.h> +#include <string.h> + +/* externs for system libraries. */ + +/*extern int abort();*/ +/*extern int exit();*/ +extern char *malloc(); +extern char *realloc(); +extern char *strchr(); +extern char *strrchr(); +extern int _filbuf(); +extern int _flsbuf(); +extern int fclose(); +extern int fgetc(); +extern int fprintf(); +extern int fread(); +extern int free(); +extern int perror(); +extern int printf(); +extern int rewind(); +extern int setvbuf(); +extern int sscanf(); +extern int strcmp(); +extern int strlen(); +extern int strncmp(); +extern int time(); +extern int ungetc(); +extern int vfprintf(); +extern int vprintf(); +extern int vsprintf(); +extern long atol(); + +#ifndef tolower +extern int tolower(); +#endif /* tolower */ + +#ifndef toupper +extern int toupper(); +#endif /* toupper */ + +/* + * Local Variables: + * fill-column: 80 + * comment-column: 0 + * End: + */ + +/* end of ho-sunos.h */ diff --git a/gnu/usr.bin/as/config/ho-sysv.h b/gnu/usr.bin/as/config/ho-sysv.h new file mode 100644 index 000000000000..443fe3bf104d --- /dev/null +++ b/gnu/usr.bin/as/config/ho-sysv.h @@ -0,0 +1,27 @@ +/* ho-sysv.h System V specific header file. + Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HO_USG + +#define setbuffer(stream, buf, size) setvbuf((stream), (buf), _IOLBF, (size)) + +extern int free(); +extern char *malloc(); + +/* end of ho-sysv.h */ diff --git a/gnu/usr.bin/as/config/ho-vax.h b/gnu/usr.bin/as/config/ho-vax.h new file mode 100644 index 000000000000..eee0553b2d32 --- /dev/null +++ b/gnu/usr.bin/as/config/ho-vax.h @@ -0,0 +1,27 @@ +/* ho-vax.h Intended for vax ultrix + Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if __STDC__ != 1 +#define NO_STDARG +#endif /* not ansi */ + +extern char *malloc(); +extern int free(); + +/* end of ho-vax.h */ diff --git a/gnu/usr.bin/as/config/ho-vms.h b/gnu/usr.bin/as/config/ho-vms.h new file mode 100644 index 000000000000..4b6680e919ed --- /dev/null +++ b/gnu/usr.bin/as/config/ho-vms.h @@ -0,0 +1,30 @@ +/* ho-vax.h Intended for vax vms + Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define HO_VAX 1 + +#include "ho-vax.h" + +/* We get better performance if we use the macros rather than the functions.*/ +#include <ctype.h> + +/* We need this to make sure that sys_nerr has the right Psect hack. */ +#include <perror.h> + +/* end of ho-vms.h */ diff --git a/gnu/usr.bin/as/config/mh-i386 b/gnu/usr.bin/as/config/mh-i386 new file mode 100644 index 000000000000..3375d4218495 --- /dev/null +++ b/gnu/usr.bin/as/config/mh-i386 @@ -0,0 +1 @@ +ALLOCA=alloca.o diff --git a/gnu/usr.bin/as/config/mh-i386aix b/gnu/usr.bin/as/config/mh-i386aix new file mode 100644 index 000000000000..a1e5d77e95a2 --- /dev/null +++ b/gnu/usr.bin/as/config/mh-i386aix @@ -0,0 +1,5 @@ +# Define SYSV as -DSYSV if you are using a System V operating system. +SYSV = -DSYSV +RANLIB = /bin/true +CC = gcc +MINUS_G = -O diff --git a/gnu/usr.bin/as/config/mh-i386v4 b/gnu/usr.bin/as/config/mh-i386v4 new file mode 100644 index 000000000000..5bfcd28e1e0d --- /dev/null +++ b/gnu/usr.bin/as/config/mh-i386v4 @@ -0,0 +1 @@ +HLIBS=-lucb diff --git a/gnu/usr.bin/as/config/mt-ebmon29k b/gnu/usr.bin/as/config/mt-ebmon29k new file mode 100644 index 000000000000..528e6fc0fa61 --- /dev/null +++ b/gnu/usr.bin/as/config/mt-ebmon29k @@ -0,0 +1,6 @@ +TARG_CPU_DEPENDENTS= +LOCAL_LOADLIBES=../bfd$(subdir)/libbfd.a +TDEFINES=-DBFD_HEADERS -DMANY_SEGMENTS -DBFD + + + diff --git a/gnu/usr.bin/as/config/mt-h8300 b/gnu/usr.bin/as/config/mt-h8300 new file mode 100644 index 000000000000..d968db2fe67e --- /dev/null +++ b/gnu/usr.bin/as/config/mt-h8300 @@ -0,0 +1,5 @@ +TARG_CPU_DEPENDENTS=$(srcdir)/../include/opcode/h8300.h +LOCAL_LOADLIBES=$(srcdir)/../bfd/$(srcdir)/libbfd.a +TDEFINES=-DBFD_HEADERS -DMANY_SEGMENTS -DBFD + +CC=gcc diff --git a/gnu/usr.bin/as/config/mt-h8300hds b/gnu/usr.bin/as/config/mt-h8300hds new file mode 100644 index 000000000000..1e6eb3c8dc96 --- /dev/null +++ b/gnu/usr.bin/as/config/mt-h8300hds @@ -0,0 +1,4 @@ +TARG_CPU_DEPENDENTS=$(srcdir)/../include/h8300-opcode.h +LOCAL_LOADLIBES=$(srcdir)/../bfd/$(srcdir)/libbfd.a +TDEFINES=-DBFD -DMANY_SEGMENTS + diff --git a/gnu/usr.bin/as/config/mt-i386aix b/gnu/usr.bin/as/config/mt-i386aix new file mode 100644 index 000000000000..225fc364b778 --- /dev/null +++ b/gnu/usr.bin/as/config/mt-i386aix @@ -0,0 +1,3 @@ +# TDEFINES = -DBFD_HEADERS +CC = gcc +MINUS_G = -O diff --git a/gnu/usr.bin/as/config/mt-mips b/gnu/usr.bin/as/config/mt-mips new file mode 100644 index 000000000000..f40f51d2bfa3 --- /dev/null +++ b/gnu/usr.bin/as/config/mt-mips @@ -0,0 +1 @@ +ALL=fake-as diff --git a/gnu/usr.bin/as/config/mt-rs6000 b/gnu/usr.bin/as/config/mt-rs6000 new file mode 100644 index 000000000000..f40f51d2bfa3 --- /dev/null +++ b/gnu/usr.bin/as/config/mt-rs6000 @@ -0,0 +1 @@ +ALL=fake-as diff --git a/gnu/usr.bin/as/config/obj-aout.c b/gnu/usr.bin/as/config/obj-aout.c new file mode 100644 index 000000000000..30eb2d150036 --- /dev/null +++ b/gnu/usr.bin/as/config/obj-aout.c @@ -0,0 +1,648 @@ +/* a.out object file format + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, + or (at your option) any later version. + + GAS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with GAS; see the file COPYING. If not, write + to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "as.h" +#include "obstack.h" + + +#ifndef NO_LISTING +#include "aout/stab_gnu.h" +#endif /* NO_LISTING */ + +/* in: segT out: N_TYPE bits */ +const short seg_N_TYPE[] = { + N_ABS, + N_TEXT, + N_DATA, + N_BSS, + N_UNDF, /* unknown */ + N_UNDF, /* absent */ + N_UNDF, /* pass1 */ + N_UNDF, /* error */ + N_UNDF, /* bignum/flonum */ + N_UNDF, /* difference */ + N_UNDF, /* debug */ + N_UNDF, /* ntv */ + N_UNDF, /* ptv */ + N_REGISTER, /* register */ +}; + +const segT N_TYPE_seg[N_TYPE+2] = { /* N_TYPE == 0x1E = 32-2 */ + SEG_UNKNOWN, /* N_UNDF == 0 */ + SEG_GOOF, + SEG_ABSOLUTE, /* N_ABS == 2 */ + SEG_GOOF, + SEG_TEXT, /* N_TEXT == 4 */ + SEG_GOOF, + SEG_DATA, /* N_DATA == 6 */ + SEG_GOOF, + SEG_BSS, /* N_BSS == 8 */ + SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_REGISTER, /* dummy N_REGISTER for regs = 30 */ + SEG_GOOF, +}; + +#if __STDC__ == 1 +static void obj_aout_stab(int what); +static void obj_aout_line(void); +static void obj_aout_desc(void); +#else /* not __STDC__ */ +static void obj_aout_desc(); +static void obj_aout_stab(); +static void obj_aout_line(); +#endif /* not __STDC__ */ + +const pseudo_typeS obj_pseudo_table[] = { +#ifndef IGNORE_DEBUG + /* stabs debug info */ + { "line", obj_aout_line, 0 }, /* source code line number */ + { "ln", obj_aout_line, 0 }, /* coff line number that we use anyway */ + { "desc", obj_aout_desc, 0 }, /* desc */ + { "stabd", obj_aout_stab, 'd' }, /* stabs */ + { "stabn", obj_aout_stab, 'n' }, /* stabs */ + { "stabs", obj_aout_stab, 's' }, /* stabs */ +#else /* IGNORE_DEBUG */ + { "line", obj_aout_line, 0 }, /* source code line number */ + { "ln", obj_aout_line, 0 }, /* coff line number that we use anyway */ + { "desc", obj_aout_desc, 0 }, /* desc */ + { "stabd", obj_aout_stab, 'd' }, /* stabs */ + { "stabn", obj_aout_stab, 'n' }, /* stabs */ + { "stabs", obj_aout_stab, 's' }, /* stabs */ +#endif /* IGNORE_DEBUG */ + + /* coff debug pseudos (ignored) */ + { "def", s_ignore, 0 }, + { "dim", s_ignore, 0 }, + { "endef", s_ignore, 0 }, + { "ident", s_ignore, 0 }, + { "line", s_ignore, 0 }, + { "ln", s_ignore, 0 }, + { "scl", s_ignore, 0 }, + { "size", s_size, 0 }, + { "tag", s_ignore, 0 }, + { "type", s_type, 0 }, + { "val", s_ignore, 0 }, + { "version", s_ignore, 0 }, + + /* stabs-in-coff (?) debug pseudos (ignored) */ + { "optim", s_ignore, 0 }, /* For sun386i cc (?) */ + + /* other stuff */ + { "ABORT", s_abort, 0 }, + + { NULL} /* end sentinel */ +}; /* obj_pseudo_table */ + + +/* Relocation. */ + +/* + * emit_relocations() + * + * Crawl along a fixS chain. Emit the segment's relocations. + */ +void obj_emit_relocations(where, fixP, segment_address_in_file) +char **where; +fixS *fixP; /* Fixup chain for this segment. */ +relax_addressT segment_address_in_file; +{ + for (; fixP; fixP = fixP->fx_next) { + if (fixP->fx_addsy != NULL) { + tc_aout_fix_to_chars(*where, fixP, segment_address_in_file); + *where += md_reloc_size; + } /* if there is an add symbol */ + } /* for each fix */ + + return; +} /* obj_emit_relocations() */ + +/* Aout file generation & utilities */ +void obj_header_append(where, headers) +char **where; +object_headers *headers; +{ + tc_headers_hook(headers); + +#if defined(OLD_GAS) && defined(TC_I386) + /* I think that this old behaviour was wrong, but this lets me compare to the + previous gas. xoxorich. */ + md_number_to_chars(*where, headers->header.a_info, 2); + *where += 2; + md_number_to_chars(*where, 0, 2); + *where += 2; +#else /* not (TC_I386 && OLD_GAS) */ + md_number_to_chars(*where, headers->header.a_info, sizeof(headers->header.a_info)); + *where += sizeof(headers->header.a_info); +#endif /* not (TC_I386 && OLD_GAS) */ + +#ifdef TE_HPUX + md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare1 */ + md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare2 */ +#endif /* TE_HPUX */ + + md_number_to_chars(*where, headers->header.a_text, 4); *where += 4; + md_number_to_chars(*where, headers->header.a_data, 4); *where += 4; + md_number_to_chars(*where, headers->header.a_bss, 4); *where += 4; + +#ifndef TE_HPUX + md_number_to_chars(*where, headers->header.a_syms, 4); *where += 4; + md_number_to_chars(*where, headers->header.a_entry, 4); *where += 4; +#endif /* not TE_HPUX */ + + md_number_to_chars(*where, headers->header.a_trsize, 4); *where += 4; + md_number_to_chars(*where, headers->header.a_drsize, 4); *where += 4; + +#ifdef TE_SEQUENT + memset(*where, '\0', 3 * 2 * 4); *where += 3 * 2 * 4; /* global descriptor table? */ + md_number_to_chars(*where, 0, 4); *where += 4; /* shdata - length of initialized shared data */ + md_number_to_chars(*where, 0, 4); *where += 4; /* shbss - length of uninitialized shared data */ + md_number_to_chars(*where, 0, 4); *where += 4; /* shdrsize - length of shared data relocation */ + + memset(*where, '\0', 11 * 4); *where += 11 * 4; /* boostrap for standalone */ + memset(*where, '\0', 3 * 4); *where += 3 * 4; /* reserved */ + md_number_to_chars(*where, 0, 4); *where += 4; /* version */ +#endif /* TE_SEQUENT */ + +#ifdef TE_HPUX + md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare3 - HP = pascal interface size */ + md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare4 - HP = symbol table size */ + md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare5 - HP = debug name table size */ + + md_number_to_chars(*where, headers->header.a_entry, 4); *where += 4; + + md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare6 - HP = source line table size */ + md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare7 - HP = value table size */ + + md_number_to_chars(*where, headers->header.a_syms, 4); *where += 4; + + md_number_to_chars(*where, 0, 4); *where += 4; /* a_spare8 */ +#endif /* TE_HPUX */ + + return; +} /* obj_append_header() */ + +void obj_symbol_to_chars(where, symbolP) +char **where; +symbolS *symbolP; +{ + md_number_to_chars((char *)&(S_GET_OFFSET(symbolP)), S_GET_OFFSET(symbolP), sizeof(S_GET_OFFSET(symbolP))); + md_number_to_chars((char *)&(S_GET_DESC(symbolP)), S_GET_DESC(symbolP), sizeof(S_GET_DESC(symbolP))); + md_number_to_chars((char *)&(S_GET_VALUE(symbolP)), S_GET_VALUE(symbolP), sizeof(S_GET_VALUE(symbolP))); + + append(where, (char *)&symbolP->sy_symbol, sizeof(obj_symbol_type)); +} /* obj_symbol_to_chars() */ + +void obj_emit_symbols(where, symbol_rootP) +char **where; +symbolS *symbol_rootP; +{ + symbolS * symbolP; + + /* + * Emit all symbols left in the symbol chain. + */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + /* Used to save the offset of the name. It is used to point + to the string in memory but must be a file offset. */ + register char *temp; + + temp = S_GET_NAME(symbolP); + S_SET_OFFSET(symbolP, symbolP->sy_name_offset); + + /* + * Put aux info in lower four bits of `n_other' field + * Do this only now, because things like S_IS_DEFINED() + * depend on S_GET_OTHER() for some unspecified reason. + */ + if (symbolP->sy_aux) + S_SET_OTHER(symbolP, (symbolP->sy_aux & 0xf)); + + /* Any symbol still undefined and is not a dbg symbol is made N_EXT. */ + if (!S_IS_DEBUG(symbolP) && !S_IS_DEFINED(symbolP)) + S_SET_EXTERNAL(symbolP); + + if (S_GET_TYPE(symbolP) == N_SIZE) { + expressionS *exp = (expressionS*)symbolP->sy_sizexp; + long size = 0; + + if (exp == NULL) { + as_bad("Internal error: no size expression"); + return; + } + + switch (exp->X_seg) { + case SEG_ABSOLUTE: + size = exp->X_add_number; + break; + case SEG_DIFFERENCE: + size = S_GET_VALUE(exp->X_add_symbol) - + S_GET_VALUE(exp->X_subtract_symbol) + + exp->X_add_number; + break; + default: + as_bad("Unsupported .size expression"); + break; + } + S_SET_VALUE(symbolP, size); + } + + obj_symbol_to_chars(where, symbolP); + S_SET_NAME(symbolP,temp); + } +} /* emit_symbols() */ + +#if comment +/* uneeded if symbol is born zeroed. */ +void obj_symbol_new_hook(symbolP) +symbolS *symbolP; +{ + S_SET_OTHER(symbolP, 0); + S_SET_DESC(symbolP, 0); + return; +} /* obj_symbol_new_hook() */ +#endif /* comment */ + +static void obj_aout_line() { + /* Assume delimiter is part of expression. */ + /* BSD4.2 as fails with delightful bug, so we */ + /* are not being incompatible here. */ + new_logical_line((char *)NULL, (int)(get_absolute_expression())); + demand_empty_rest_of_line(); +} /* obj_aout_line() */ + +/* + * stab() + * + * Handle .stabX directives, which used to be open-coded. + * So much creeping featurism overloaded the semantics that we decided + * to put all .stabX thinking in one place. Here. + * + * We try to make any .stabX directive legal. Other people's AS will often + * do assembly-time consistency checks: eg assigning meaning to n_type bits + * and "protecting" you from setting them to certain values. (They also zero + * certain bits before emitting symbols. Tut tut.) + * + * If an expression is not absolute we either gripe or use the relocation + * information. Other people's assemblers silently forget information they + * don't need and invent information they need that you didn't supply. + * + * .stabX directives always make a symbol table entry. It may be junk if + * the rest of your .stabX directive is malformed. + */ +static void obj_aout_stab(what) +int what; +{ +#ifndef NO_LISTING + extern int listing; +#endif /* NO_LISTING */ + + register symbolS *symbolP = 0; + register char *string; + int saved_type = 0; + int length; + int goof; /* TRUE if we have aborted. */ + long longint; + + /* + * Enter with input_line_pointer pointing past .stabX and any following + * whitespace. + */ + goof = 0; /* JF who forgot this?? */ + if (what == 's') { + string = demand_copy_C_string(& length); + SKIP_WHITESPACE(); + if (* input_line_pointer == ',') + input_line_pointer ++; + else { + as_bad("I need a comma after symbol's name"); + goof = 1; + } + } else + string = ""; + + /* + * Input_line_pointer->after ','. String->symbol name. + */ + if (! goof) { + symbolP = symbol_new(string, + SEG_UNKNOWN, + 0, + (struct frag *)0); + switch (what) { + case 'd': + S_SET_NAME(symbolP, NULL); /* .stabd feature. */ + S_SET_VALUE(symbolP, obstack_next_free(&frags) - frag_now->fr_literal); + symbolP->sy_frag = frag_now; + break; + + case 'n': + symbolP->sy_frag = &zero_address_frag; + break; + + case 's': + symbolP->sy_frag = & zero_address_frag; + break; + + default: + BAD_CASE(what); + break; + } + + if (get_absolute_expression_and_terminator(&longint) == ',') + symbolP->sy_symbol.n_type = saved_type = longint; + else { + as_bad("I want a comma after the n_type expression"); + goof = 1; + input_line_pointer --; /* Backup over a non-',' char. */ + } + } + + if (!goof) { + if (get_absolute_expression_and_terminator(&longint) == ',') + S_SET_OTHER(symbolP, longint); + else { + as_bad("I want a comma after the n_other expression"); + goof = 1; + input_line_pointer--; /* Backup over a non-',' char. */ + } + } + + if (!goof) { + S_SET_DESC(symbolP, get_absolute_expression()); + if (what == 's' || what == 'n') { + if (*input_line_pointer != ',') { + as_bad("I want a comma after the n_desc expression"); + goof = 1; + } else { + input_line_pointer++; + } + } + } + + if ((!goof) && (what == 's' || what == 'n')) { + pseudo_set(symbolP); + symbolP->sy_symbol.n_type = saved_type; + } +#ifndef NO_LISTING + if (listing && !goof) + { + if (symbolP->sy_symbol.n_type == N_SLINE) + { + + listing_source_line(symbolP->sy_symbol.n_desc); + } + else if (symbolP->sy_symbol.n_type == N_SO + || symbolP->sy_symbol.n_type == N_SOL) + { + listing_source_file(string); + } + } +#endif + + if (goof) + ignore_rest_of_line(); + else + demand_empty_rest_of_line (); +} /* obj_aout_stab() */ + +static void obj_aout_desc() { + register char *name; + register char c; + register char *p; + register symbolS *symbolP; + register int temp; + + /* + * Frob invented at RMS' request. Set the n_desc of a symbol. + */ + name = input_line_pointer; + c = get_symbol_end(); + p = input_line_pointer; + * p = c; + SKIP_WHITESPACE(); + if (*input_line_pointer != ',') { + *p = 0; + as_bad("Expected comma after name \"%s\"", name); + *p = c; + ignore_rest_of_line(); + } else { + input_line_pointer ++; + temp = get_absolute_expression(); + *p = 0; + symbolP = symbol_find_or_make(name); + *p = c; + S_SET_DESC(symbolP,temp); + } + demand_empty_rest_of_line(); +} /* obj_aout_desc() */ + +void obj_read_begin_hook() { + return; +} /* obj_read_begin_hook() */ + +void obj_crawl_symbol_chain(headers) +object_headers *headers; +{ + symbolS *symbolP; + symbolS **symbolPP; + int symbol_number = 0; + + /* JF deal with forward references first... */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + if (symbolP->sy_forward) { + S_SET_VALUE(symbolP, S_GET_VALUE(symbolP) + + S_GET_VALUE(symbolP->sy_forward) + + symbolP->sy_forward->sy_frag->fr_address); + + symbolP->sy_forward=0; + } /* if it has a forward reference */ + } /* walk the symbol chain */ + + tc_crawl_symbol_chain(headers); + + symbolPP = &symbol_rootP; /*->last symbol chain link. */ + while ((symbolP = *symbolPP) != NULL) { + if (flagseen['R'] && (S_GET_SEGMENT(symbolP) == SEG_DATA)) { + S_SET_SEGMENT(symbolP, SEG_TEXT); + } /* if pusing data into text */ + + S_SET_VALUE(symbolP, S_GET_VALUE(symbolP) + symbolP->sy_frag->fr_address); + + /* OK, here is how we decide which symbols go out into the + brave new symtab. Symbols that do are: + + * symbols with no name (stabd's?) + * symbols with debug info in their N_TYPE + * symbols marked "forceout" (to force out local `L' + symbols in PIC code) + + Symbols that don't are: + * symbols that are registers + * symbols with \1 as their 3rd character (numeric labels) + * "local labels" as defined by S_LOCAL_NAME(name) + if the -L switch was passed to gas. + + All other symbols are output. We complain if a deleted + symbol was marked external. */ + + + if (!S_IS_REGISTER(symbolP) + && (!S_GET_NAME(symbolP) + || S_IS_DEBUG(symbolP) +#ifdef TC_I960 + /* FIXME-SOON this ifdef seems highly dubious to me. xoxorich. */ + || !S_IS_DEFINED(symbolP) + || S_IS_EXTERNAL(symbolP) +#endif /* TC_I960 */ + || (S_GET_NAME(symbolP)[0] != '\001' && + (flagseen['L'] || ! S_LOCAL_NAME(symbolP) +#ifdef PIC + || flagseen['k'] && symbolP->sy_forceout +#endif + ) + ) + ) +#ifdef PIC + && (!flagseen['k'] || + symbolP != GOT_symbol || got_referenced != 0 + ) +#endif + ) { + symbolP->sy_number = symbol_number++; + + /* The + 1 after strlen account for the \0 at the + end of each string */ + if (!S_IS_STABD(symbolP)) { + /* Ordinary case. */ + symbolP->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(symbolP)) + 1; + } + else /* .Stabd case. */ + symbolP->sy_name_offset = 0; + + /* + * If symbol has a known size, output an extra symbol + * of type N_SIZE and with the same name. + * We cannot evaluate the size expression just yet, as + * some its terms may not have had their final values + * set. We defer this until `obj_emit_symbols()' + */ + if (flagseen['k'] && + S_GET_TYPE(symbolP) != N_SIZE && +#ifndef GRACE_PERIOD_EXPIRED + /*Can be enabled when no more old ld's around*/ + (symbolP->sy_aux == AUX_OBJECT) && +#endif + symbolP->sy_sizexp) { + + symbolS *addme; + + /* Put a new symbol on the chain */ +#ifdef NSIZE_PREFIX /*XXX*/ + char buf[BUFSIZ]; + + buf[0] = NSIZE_PREFIX; + strncpy(buf+1, S_GET_NAME(symbolP), BUFSIZ-2); + addme = symbol_make(buf); +#else + addme = symbol_make(S_GET_NAME(symbolP)); +#endif + /* Set type and transfer size expression */ + addme->sy_symbol.n_type = N_SIZE; + addme->sy_sizexp = symbolP->sy_sizexp; + symbolP->sy_sizexp = NULL; + + /* Set external if symbolP is */ + if (S_IS_EXTERN(symbolP)) + S_SET_EXTERNAL(addme); + + } + symbolPP = &(symbol_next(symbolP)); + } else { + if ((S_IS_EXTERNAL(symbolP) || !S_IS_DEFINED(symbolP)) +#ifdef PIC + && (!flagseen['k'] || + symbolP != GOT_symbol || got_referenced != 0 + ) +#endif + ) { + as_bad("Local symbol %s never defined.", decode_local_label_name(S_GET_NAME(symbolP))); + } /* oops. */ + + /* Unhook it from the chain */ + *symbolPP = symbol_next(symbolP); + } /* if this symbol should be in the output */ + } /* for each symbol */ + + H_SET_SYMBOL_TABLE_SIZE(headers, symbol_number); + + return; +} /* obj_crawl_symbol_chain() */ + +/* + * Find strings by crawling along symbol table chain. + */ + +void obj_emit_strings(where) +char **where; +{ + symbolS *symbolP; + +#ifdef CROSS_COMPILE + /* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */ + md_number_to_chars(*where, string_byte_count, sizeof(string_byte_count)); + *where += sizeof(string_byte_count); +#else /* CROSS_COMPILE */ + append (where, (char *)&string_byte_count, (unsigned long)sizeof(string_byte_count)); +#endif /* CROSS_COMPILE */ + + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + if (S_GET_NAME(symbolP)) + append(&next_object_file_charP, S_GET_NAME(symbolP), + (unsigned long)(strlen (S_GET_NAME(symbolP)) + 1)); + } /* walk symbol chain */ + + return; +} /* obj_emit_strings() */ + +void obj_pre_write_hook(headers) +object_headers *headers; +{ + H_SET_DYNAMIC(headers, 0); + H_SET_VERSION(headers, 0); + H_SET_MACHTYPE(headers, AOUT_MACHTYPE); + + H_SET_MAGIC_NUMBER(headers, DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE); + H_SET_ENTRY_POINT(headers, 0); + + tc_aout_pre_write_hook(headers); + return; +} /* obj_pre_write_hook() */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-aout.c */ diff --git a/gnu/usr.bin/as/config/obj-aout.h b/gnu/usr.bin/as/config/obj-aout.h new file mode 100644 index 000000000000..298c1bc1b68b --- /dev/null +++ b/gnu/usr.bin/as/config/obj-aout.h @@ -0,0 +1,210 @@ +/* obj-aout.h, a.out object file format for gas, the assembler. + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, + or (at your option) any later version. + + GAS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with GAS; see the file COPYING. If not, write + to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: obj-aout.h,v 1.2 1993/11/30 20:57:40 jkh Exp $ + */ + + +/* Tag to validate a.out object file format processing */ +#define OBJ_AOUT 1 + +#include "targ-cpu.h" + +#include "aout.h" /* Needed to define struct nlist. Sigh. */ + +#ifndef AOUT_MACHTYPE +#define AOUT_MACHTYPE 0 +#endif /* AOUT_MACHTYPE */ + +extern const short seg_N_TYPE[]; +extern const segT N_TYPE_seg[]; + +#ifndef DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (OMAGIC) +#endif /* DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE */ + +/* First character of operand in `.type' directives */ +#define TYPE_OPERAND_FMT '@' + +/* SYMBOL TABLE */ +/* Symbol table entry data type */ + +typedef struct nlist obj_symbol_type; /* Symbol table entry */ + +/* Symbol table macros and constants */ + +/* + * Macros to extract information from a symbol table entry. + * This syntaxic indirection allows independence regarding a.out or coff. + * The argument (s) of all these macros is a pointer to a symbol table entry. + */ + +/* True if the symbol is external */ +#define S_IS_EXTERNAL(s) ((s)->sy_symbol.n_type & N_EXT) + +/* True if symbol has been defined, ie is in N_{TEXT,DATA,BSS,ABS} or N_EXT */ +#define S_IS_DEFINED(s) ((S_GET_TYPE(s) != N_UNDF) || (S_GET_OTHER(s) != 0) || (S_GET_DESC(s) != 0)) + +#define S_IS_REGISTER(s) ((s)->sy_symbol.n_type == N_REGISTER) + +/* True if a debug special symbol entry */ +#define S_IS_DEBUG(s) ((s)->sy_symbol.n_type & N_STAB) +/* True if a symbol is local symbol name */ +/* A symbol name whose name begin with ^A is a gas internal pseudo symbol + nameless symbols come from .stab directives. */ +#define S_IS_LOCAL(s) (S_GET_NAME(s) && \ + !S_IS_DEBUG(s) && \ + (S_GET_NAME(s)[0] == '\001' || \ + (S_LOCAL_NAME(s) && !flagseen['L']))) +/* True if a symbol is not defined in this file */ +#define S_IS_EXTERN(s) ((s)->sy_symbol.n_type & N_EXT) +/* True if the symbol has been generated because of a .stabd directive */ +#define S_IS_STABD(s) (S_GET_NAME(s) == (char *)0) + +/* Accessors */ +/* The value of the symbol */ +#define S_GET_VALUE(s) (((s)->sy_symbol.n_value)) +/* The name of the symbol */ +#define S_GET_NAME(s) ((s)->sy_symbol.n_un.n_name) +/* The pointer to the string table */ +#define S_GET_OFFSET(s) ((s)->sy_symbol.n_un.n_strx) +/* The type of the symbol */ +#define S_GET_TYPE(s) ((s)->sy_symbol.n_type & N_TYPE) +/* The numeric value of the segment */ +#define S_GET_SEGMENT(s) (N_TYPE_seg[S_GET_TYPE(s)]) +/* The n_other expression value */ +#define S_GET_OTHER(s) ((s)->sy_symbol.n_other) +/* The n_desc expression value */ +#define S_GET_DESC(s) ((s)->sy_symbol.n_desc) + +/* Modifiers */ +/* Set the value of the symbol */ +#define S_SET_VALUE(s,v) ((s)->sy_symbol.n_value = (unsigned long) (v)) +/* Assume that a symbol cannot be simultaneously in more than on segment */ +/* set segment */ +#define S_SET_SEGMENT(s,seg) ((s)->sy_symbol.n_type &= ~N_TYPE,(s)->sy_symbol.n_type|=SEGMENT_TO_SYMBOL_TYPE(seg)) +/* The symbol is external */ +#define S_SET_EXTERNAL(s) ((s)->sy_symbol.n_type |= N_EXT) +/* The symbol is not external */ +#define S_CLEAR_EXTERNAL(s) ((s)->sy_symbol.n_type &= ~N_EXT) +/* Set the name of the symbol */ +#define S_SET_NAME(s,v) ((s)->sy_symbol.n_un.n_name = (v)) +/* Set the offset in the string table */ +#define S_SET_OFFSET(s,v) ((s)->sy_symbol.n_un.n_strx = (v)) +/* Set the n_other expression value */ +#define S_SET_OTHER(s,v) ((s)->sy_symbol.n_other = (v)) +/* Set the n_desc expression value */ +#define S_SET_DESC(s,v) ((s)->sy_symbol.n_desc = (v)) + +/* File header macro and type definition */ + +#define H_GET_FILE_SIZE(h) (H_GET_HEADER_SIZE(h) \ + + H_GET_TEXT_SIZE(h) \ + + H_GET_DATA_SIZE(h) \ + + H_GET_SYMBOL_TABLE_SIZE(h) \ + + H_GET_TEXT_RELOCATION_SIZE(h) \ + + H_GET_DATA_RELOCATION_SIZE(h) \ + + H_GET_STRING_SIZE(h)) + +#ifndef H_GET_HEADER_SIZE +#define H_GET_HEADER_SIZE(h) (sizeof(struct exec)) +#endif /* not H_GET_HEADER_SIZE */ + +#define H_GET_TEXT_SIZE(h) ((h)->header.a_text) +#define H_GET_DATA_SIZE(h) ((h)->header.a_data) +#define H_GET_BSS_SIZE(h) ((h)->header.a_bss) +#define H_GET_TEXT_RELOCATION_SIZE(h) ((h)->header.a_trsize) +#define H_GET_DATA_RELOCATION_SIZE(h) ((h)->header.a_drsize) +#define H_GET_SYMBOL_TABLE_SIZE(h) ((h)->header.a_syms) +#define H_GET_ENTRY_POINT(h) ((h)->header.a_entry) +#define H_GET_STRING_SIZE(h) ((h)->string_table_size) +#define H_GET_LINENO_SIZE(h) (0) + +#define H_GET_DYNAMIC(h) ((h)->header.a_info >> 31) +#define H_GET_VERSION(h) (((h)->header.a_info >> 24) & 0x7f) +#define H_GET_MACHTYPE(h) (((h)->header.a_info >> 16) & 0xff) +#define H_GET_MAGIC_NUMBER(h) ((h)->header.a_info & 0xffff) + +#define H_SET_DYNAMIC(h,v) ((h)->header.a_info = (((v) << 31) \ + | (H_GET_VERSION(h) << 24) \ + | (H_GET_MACHTYPE(h) << 16) \ + | (H_GET_MAGIC_NUMBER(h)))) + +#define H_SET_VERSION(h,v) ((h)->header.a_info = ((H_GET_DYNAMIC(h) << 31) \ + | ((v) << 24) \ + | (H_GET_MACHTYPE(h) << 16) \ + | (H_GET_MAGIC_NUMBER(h)))) + +#define H_SET_MACHTYPE(h,v) ((h)->header.a_info = ((H_GET_DYNAMIC(h) << 31) \ + | (H_GET_VERSION(h) << 24) \ + | ((v) << 16) \ + | (H_GET_MAGIC_NUMBER(h)))) + +#define H_SET_MAGIC_NUMBER(h,v) ((h)->header.a_info = ((H_GET_DYNAMIC(h) << 31) \ + | (H_GET_VERSION(h) << 24) \ + | (H_GET_MACHTYPE(h) << 16) \ + | ((v)))) + +#define H_SET_TEXT_SIZE(h,v) ((h)->header.a_text = md_section_align(SEG_TEXT, (v))) +#define H_SET_DATA_SIZE(h,v) ((h)->header.a_data = md_section_align(SEG_DATA, (v))) +#define H_SET_BSS_SIZE(h,v) ((h)->header.a_bss = md_section_align(SEG_BSS, (v))) + +#define H_SET_RELOCATION_SIZE(h,t,d) (H_SET_TEXT_RELOCATION_SIZE((h),(t)),\ + H_SET_DATA_RELOCATION_SIZE((h),(d))) + +#define H_SET_TEXT_RELOCATION_SIZE(h,v) ((h)->header.a_trsize = (v)) +#define H_SET_DATA_RELOCATION_SIZE(h,v) ((h)->header.a_drsize = (v)) +#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->header.a_syms = (v) * \ + sizeof(struct nlist)) + +#define H_SET_ENTRY_POINT(h,v) ((h)->header.a_entry = (v)) +#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v)) + +/* + * Current means for getting the name of a segment. + * This will change for infinite-segments support (e.g. COFF). + */ +#define segment_name(seg) (seg_name[(int)(seg)]) +extern char *const seg_name[]; + +typedef struct { + struct exec header; /* a.out header */ + long string_table_size; /* names + '\0' + sizeof(int) */ +} object_headers; + +/* line numbering stuff. */ +#define OBJ_EMIT_LINENO(a, b, c) {;} + +#define obj_symbol_new_hook(s) {;} + +#if __STDC__ == 1 +struct fix; +void tc_aout_fix_to_chars(char *where, struct fix *fixP, relax_addressT segment_address); +#else /* not __STDC__ */ +void tc_aout_fix_to_chars(); +#endif /* not __STDC__ */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-aout.h */ diff --git a/gnu/usr.bin/as/config/obj-bfd-sunos.c b/gnu/usr.bin/as/config/obj-bfd-sunos.c new file mode 100644 index 000000000000..626516bdc8a1 --- /dev/null +++ b/gnu/usr.bin/as/config/obj-bfd-sunos.c @@ -0,0 +1,71 @@ +/* obj-bfd-sunos.c + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "as.h" + +static + + const short seg_N_TYPE[] = { + N_ABS, + N_TEXT, + N_DATA, + N_BSS, + N_UNDF, /* unknown */ + N_UNDF, /* absent */ + N_UNDF, /* pass1 */ + N_UNDF, /* error */ + N_UNDF, /* bignum/flonum */ + N_UNDF, /* difference */ + N_REGISTER, /* register */ + }; + +const segT N_TYPE_seg[N_TYPE+2] = { /* N_TYPE == 0x1E = 32-2 */ + SEG_UNKNOWN, /* N_UNDF == 0 */ + SEG_GOOF, + SEG_ABSOLUTE, /* N_ABS == 2 */ + SEG_GOOF, + SEG_TEXT, /* N_TEXT == 4 */ + SEG_GOOF, + SEG_DATA, /* N_DATA == 6 */ + SEG_GOOF, + SEG_BSS, /* N_BSS == 8 */ + SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_REGISTER, /* dummy N_REGISTER for regs = 30 */ + SEG_GOOF, +}; + + +void obj_symbol_new_hook(symbolP) +symbolS *symbolP; +{ + return; +} /* obj_symbol_new_hook() */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-bfd-sunos.c */ diff --git a/gnu/usr.bin/as/config/obj-bfd-sunos.h b/gnu/usr.bin/as/config/obj-bfd-sunos.h new file mode 100644 index 000000000000..958d8a9365b2 --- /dev/null +++ b/gnu/usr.bin/as/config/obj-bfd-sunos.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * This file is obj-bfd-sunos.h. + */ + +/* define an obj specific macro off which target cpu back ends may key. */ +#define OBJ_BFD +#define OBJ_BFD_SUNOS + +#include "bfd.h" + +/* include whatever target cpu is appropriate. */ +#include "targ-cpu.h" + +/* + * SYMBOLS + */ + +/* + * If your object format needs to reorder symbols, define this. When + * defined, symbols are kept on a doubly linked list and functions are + * made available for push, insert, append, and delete. If not defined, + * symbols are kept on a singly linked list, only the append and clear + * facilities are available, and they are macros. + */ + +/* #define SYMBOLS_NEED_PACKPOINTERS */ + +typedef asymbol obj_symbol_type; +typedef void *object_headers; + +#define S_SET_NAME(s, v) ((s)->sy_symbol.name = (v)) +#define S_GET_NAME(s) ((s)->sy_symbol.name) +#define S_SET_SEGMENT(s,v) ((s)->sy_symbol.udata = (v)) +#define S_GET_SEGMENT(s) ((s)->sy_symbol.udata) +#define S_SET_EXTERNAL(s) ((s)->sy_symbol.flags |= BSF_GLOBAL) +#define S_SET_VALUE(s,v) ((s)->sy_symbol.value = (v)) +#define S_GET_VALUE(s) ((s)->sy_symbol.value) +#define S_IS_DEFINED(s) (!((s)->sy_symbol.flags & BSF_UNDEFINED)) + +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (0) /* your magic number */ +#define OBJ_EMIT_LINENO(a,b,c) /* must be *something*. This no-op's it out. */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-bfd-sunos.h */ diff --git a/gnu/usr.bin/as/config/obj-bout.c b/gnu/usr.bin/as/config/obj-bout.c new file mode 100644 index 000000000000..f6d930291f1f --- /dev/null +++ b/gnu/usr.bin/as/config/obj-bout.c @@ -0,0 +1,476 @@ +/* b.out object file format + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, + or (at your option) any later version. + + GAS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with GAS; see the file COPYING. If not, write + to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "as.h" +#include "obstack.h" + +#ifndef NO_LISTING +#include "aout/stab_gnu.h" +#endif /* NO_LISTING */ + +const short /* in: segT out: N_TYPE bits */ + seg_N_TYPE[] = { + N_ABS, + N_TEXT, + N_DATA, + N_BSS, + N_UNDF, /* unknown */ + N_UNDF, /* absent */ + N_UNDF, /* pass1 */ + N_UNDF, /* error */ + N_UNDF, /* bignum/flonum */ + N_UNDF, /* difference */ + N_REGISTER, /* register */ + }; + +const segT N_TYPE_seg[N_TYPE+2] = { /* N_TYPE == 0x1E = 32-2 */ + SEG_UNKNOWN, /* N_UNDF == 0 */ + SEG_GOOF, + SEG_ABSOLUTE, /* N_ABS == 2 */ + SEG_GOOF, + SEG_TEXT, /* N_TEXT == 4 */ + SEG_GOOF, + SEG_DATA, /* N_DATA == 6 */ + SEG_GOOF, + SEG_BSS, /* N_BSS == 8 */ + SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_REGISTER, /* dummy N_REGISTER for regs = 30 */ + SEG_GOOF, +}; + +#if __STDC__ == 1 +static void obj_bout_stab(int what); +static void obj_bout_line(void); +static void obj_bout_desc(void); +#else /* not __STDC__ */ +static void obj_bout_desc(); +static void obj_bout_stab(); +static void obj_bout_line(); +#endif /* not __STDC__ */ + +const pseudo_typeS obj_pseudo_table[] = { + /* stabs (aka a.out aka b.out directives for debug symbols) */ + { "desc", obj_bout_desc, 0 }, /* def */ + { "line", obj_bout_line, 0 }, /* source code line number */ + { "stabd", obj_bout_stab, 'd' }, /* stabs */ + { "stabn", obj_bout_stab, 'n' }, /* stabs */ + { "stabs", obj_bout_stab, 's' }, /* stabs */ + + /* coff debugging directives. Currently ignored silently */ + { "def", s_ignore, 0 }, + { "dim", s_ignore, 0 }, + { "endef", s_ignore, 0 }, + { "ln", s_ignore, 0 }, + { "scl", s_ignore, 0 }, + { "size", s_ignore, 0 }, + { "tag", s_ignore, 0 }, + { "type", s_ignore, 0 }, + { "val", s_ignore, 0 }, + + /* other stuff we don't handle */ + { "ABORT", s_ignore, 0 }, + { "ident", s_ignore, 0 }, + + { NULL} /* end sentinel */ +}; /* obj_pseudo_table */ + +/* Relocation. */ + +/* + * emit_relocations() + * + * Crawl along a fixS chain. Emit the segment's relocations. + */ +void obj_emit_relocations(where, fixP, segment_address_in_file) +char **where; +fixS *fixP; /* Fixup chain for this segment. */ +relax_addressT segment_address_in_file; +{ + for (; fixP; fixP = fixP->fx_next) { + if (fixP->fx_addsy != NULL) { + tc_bout_fix_to_chars(*where, fixP, segment_address_in_file); + *where += sizeof(struct relocation_info); + } /* if there's a symbol */ + } /* for each fixup */ + +} /* emit_relocations() */ + +/* Aout file generation & utilities */ + +/* Convert a lvalue to machine dependent data */ +void obj_header_append(where, headers) +char **where; +object_headers *headers; +{ + /* Always leave in host byte order */ + + headers->header.a_talign = section_alignment[SEG_TEXT]; + + if (headers->header.a_talign < 2){ + headers->header.a_talign = 2; + } /* force to at least 2 */ + + headers->header.a_dalign = section_alignment[SEG_DATA]; + headers->header.a_balign = section_alignment[SEG_BSS]; + + headers->header.a_tload = 0; + headers->header.a_dload = md_section_align(SEG_DATA, H_GET_TEXT_SIZE(headers)); + + append(where, (char *) &headers->header, sizeof(headers->header)); +} /* a_header_append() */ + +void obj_symbol_to_chars(where, symbolP) +char **where; +symbolS *symbolP; +{ + /* leave in host byte order */ + append(where, (char *)&symbolP->sy_symbol, sizeof(obj_symbol_type)); +} /* obj_symbol_to_chars() */ + +void obj_emit_symbols(where, symbol_rootP) +char **where; +symbolS *symbol_rootP; +{ + symbolS * symbolP; + + /* + * Emit all symbols left in the symbol chain. + */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + /* Used to save the offset of the name. It is used to point + to the string in memory but must be a file offset. */ + char *temp; + + temp = S_GET_NAME(symbolP); + S_SET_OFFSET(symbolP, symbolP->sy_name_offset); + + /* Any symbol still undefined and is not a dbg symbol is made N_EXT. */ + if (!S_IS_DEBUG(symbolP) && !S_IS_DEFINED(symbolP)) S_SET_EXTERNAL(symbolP); + + obj_symbol_to_chars(where, symbolP); + S_SET_NAME(symbolP,temp); + } +} /* emit_symbols() */ + +void obj_symbol_new_hook(symbolP) +symbolS *symbolP; +{ + S_SET_OTHER(symbolP, 0); + S_SET_DESC(symbolP, 0); + return; +} /* obj_symbol_new_hook() */ + +static void obj_bout_line() { + /* Assume delimiter is part of expression. */ + /* BSD4.2 as fails with delightful bug, so we */ + /* are not being incompatible here. */ + new_logical_line ((char *)NULL, (int)(get_absolute_expression ())); + demand_empty_rest_of_line(); +} /* obj_bout_line() */ + +/* + * stab() + * + * Handle .stabX directives, which used to be open-coded. + * So much creeping featurism overloaded the semantics that we decided + * to put all .stabX thinking in one place. Here. + * + * We try to make any .stabX directive legal. Other people's AS will often + * do assembly-time consistency checks: eg assigning meaning to n_type bits + * and "protecting" you from setting them to certain values. (They also zero + * certain bits before emitting symbols. Tut tut.) + * + * If an expression is not absolute we either gripe or use the relocation + * information. Other people's assemblers silently forget information they + * don't need and invent information they need that you didn't supply. + * + * .stabX directives always make a symbol table entry. It may be junk if + * the rest of your .stabX directive is malformed. + */ +static void obj_bout_stab(what) +int what; +{ + register symbolS * symbolP = 0; + register char * string; + int saved_type = 0; + int length; + int goof; /* TRUE if we have aborted. */ + long longint; + + /* + * Enter with input_line_pointer pointing past .stabX and any following + * whitespace. + */ + goof = 0; /* JF who forgot this?? */ + if (what == 's') { + string = demand_copy_C_string(& length); + SKIP_WHITESPACE(); + if (*input_line_pointer == ',') + input_line_pointer ++; + else { + as_bad("I need a comma after symbol's name"); + goof = 1; + } + } else + string = ""; + + /* + * Input_line_pointer->after ','. String->symbol name. + */ + if (!goof) { + symbolP = symbol_new(string, + SEG_UNKNOWN, + 0, + (struct frag *)0); + switch (what) { + case 'd': + S_SET_NAME(symbolP,NULL); /* .stabd feature. */ + S_SET_VALUE(symbolP,obstack_next_free(&frags) - + frag_now->fr_literal); + symbolP->sy_frag = frag_now; + break; + + case 'n': + symbolP->sy_frag = &zero_address_frag; + break; + + case 's': + symbolP->sy_frag = & zero_address_frag; + break; + + default: + BAD_CASE(what); + break; + } + if (get_absolute_expression_and_terminator(& longint) == ',') + symbolP->sy_symbol.n_type = saved_type = longint; + else { + as_bad("I want a comma after the n_type expression"); + goof = 1; + input_line_pointer--; /* Backup over a non-',' char. */ + } + } + if (! goof) { + if (get_absolute_expression_and_terminator (& longint) == ',') + S_SET_OTHER(symbolP,longint); + else { + as_bad("I want a comma after the n_other expression"); + goof = 1; + input_line_pointer--; /* Backup over a non-',' char. */ + } + } + if (! goof) { + S_SET_DESC(symbolP, get_absolute_expression ()); + if (what == 's' || what == 'n') { + if (* input_line_pointer != ',') { + as_bad("I want a comma after the n_desc expression"); + goof = 1; + } else { + input_line_pointer ++; + } + } + } + if ((!goof) && (what == 's' || what == 'n')) { + pseudo_set(symbolP); + symbolP->sy_symbol.n_type = saved_type; + } +#ifndef NO_LISTING + { + extern int listing; + + if (listing && !goof) { + if (symbolP->sy_symbol.n_type == N_SLINE) { + + listing_source_line(symbolP->sy_symbol.n_desc); + } else if (symbolP->sy_symbol.n_type == N_SO + || symbolP->sy_symbol.n_type == N_SOL) { + listing_source_file(string); + } + } + } + +#endif + + if (goof) + ignore_rest_of_line (); + else + demand_empty_rest_of_line (); +} /* obj_bout_stab() */ + +static void obj_bout_desc() { + register char *name; + register char c; + register char *p; + register symbolS * symbolP; + register int temp; + + /* + * Frob invented at RMS' request. Set the n_desc of a symbol. + */ + name = input_line_pointer; + c = get_symbol_end(); + p = input_line_pointer; + * p = c; + SKIP_WHITESPACE(); + if (*input_line_pointer != ',') { + *p = 0; + as_bad("Expected comma after name \"%s\"", name); + *p = c; + ignore_rest_of_line(); + } else { + input_line_pointer ++; + temp = get_absolute_expression (); + *p = 0; + symbolP = symbol_find_or_make(name); + *p = c; + S_SET_DESC(symbolP,temp); + } + demand_empty_rest_of_line(); +} /* obj_bout_desc() */ + +void obj_read_begin_hook() { + return; +} /* obj_read_begin_hook() */ + +void obj_crawl_symbol_chain(headers) +object_headers *headers; +{ + symbolS **symbolPP; + symbolS *symbolP; + int symbol_number = 0; + + /* JF deal with forward references first... */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + if (symbolP->sy_forward) { + S_SET_VALUE(symbolP, S_GET_VALUE(symbolP) + + S_GET_VALUE(symbolP->sy_forward) + + symbolP->sy_forward->sy_frag->fr_address); + + symbolP->sy_forward=0; + } /* if it has a forward reference */ + } /* walk the symbol chain */ + + tc_crawl_symbol_chain(headers); + + symbolPP = & symbol_rootP; /*->last symbol chain link. */ + while ((symbolP = *symbolPP) != NULL) { + if (flagseen['R'] && (S_GET_SEGMENT(symbolP) == SEG_DATA)) { + S_SET_SEGMENT(symbolP, SEG_TEXT); + } /* if pusing data into text */ + + S_SET_VALUE(symbolP, S_GET_VALUE(symbolP) + symbolP->sy_frag->fr_address); + + /* OK, here is how we decide which symbols go out into the + brave new symtab. Symbols that do are: + + * symbols with no name (stabd's?) + * symbols with debug info in their N_TYPE + + Symbols that don't are: + * symbols that are registers + * symbols with \1 as their 3rd character (numeric labels) + * "local labels" as defined by S_LOCAL_NAME(name) + if the -L switch was passed to gas. + + All other symbols are output. We complain if a deleted + symbol was marked external. */ + + + if (1 + && !S_IS_REGISTER(symbolP) + && (!S_GET_NAME(symbolP) + || S_IS_DEBUG(symbolP) +#ifdef TC_I960 + /* FIXME-SOON this ifdef seems highly dubious to me. xoxorich. */ + || !S_IS_DEFINED(symbolP) + || S_IS_EXTERNAL(symbolP) +#endif /* TC_I960 */ + || (S_GET_NAME(symbolP)[0] != '\001' && (flagseen['L'] || ! S_LOCAL_NAME(symbolP))))) { + symbolP->sy_number = symbol_number++; + + /* The + 1 after strlen account for the \0 at the + end of each string */ + if (!S_IS_STABD(symbolP)) { + /* Ordinary case. */ + symbolP->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(symbolP)) + 1; + } + else /* .Stabd case. */ + symbolP->sy_name_offset = 0; + symbolPP = &(symbol_next(symbolP)); + } else { + if (S_IS_EXTERNAL(symbolP) || !S_IS_DEFINED(symbolP)) { + as_bad("Local symbol %s never defined", S_GET_NAME(symbolP)); + } /* oops. */ + + /* Unhook it from the chain */ + *symbolPP = symbol_next(symbolP); + } /* if this symbol should be in the output */ + } /* for each symbol */ + + H_SET_SYMBOL_TABLE_SIZE(headers, symbol_number); + + return; +} /* obj_crawl_symbol_chain() */ + +/* + * Find strings by crawling along symbol table chain. + */ + +void obj_emit_strings(where) +char **where; +{ + symbolS *symbolP; + +#ifdef CROSS_COMPILE + /* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */ + md_number_to_chars(*where, string_byte_count, sizeof(string_byte_count)); + *where += sizeof(string_byte_count); +#else /* CROSS_COMPILE */ + append(where, (char *) &string_byte_count, (unsigned long) sizeof(string_byte_count)); +#endif /* CROSS_COMPILE */ + + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + if (S_GET_NAME(symbolP)) + append(where, S_GET_NAME(symbolP), (unsigned long)(strlen (S_GET_NAME(symbolP)) + 1)); + } /* walk symbol chain */ + + return; +} /* obj_emit_strings() */ + +void obj_pre_write_hook(headers) +object_headers *headers; +{ + H_SET_MAGIC_NUMBER(headers, BMAGIC); + H_SET_ENTRY_POINT(headers, 0); + + return; +} /* obj_pre_write_hook() */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-bout.c */ diff --git a/gnu/usr.bin/as/config/obj-bout.h b/gnu/usr.bin/as/config/obj-bout.h new file mode 100644 index 000000000000..e28d435a97c5 --- /dev/null +++ b/gnu/usr.bin/as/config/obj-bout.h @@ -0,0 +1,313 @@ +/* b.out object file format + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, + or (at your option) any later version. + + GAS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with GAS; see the file COPYING. If not, write + to the Free Software Foundation, 675 Mass Ave, Cambridge, MA + 02139, USA. */ + +/* + * This file is a modified version of 'a.out.h'. It is to be used in all GNU + * tools modified to support the i80960 b.out format (or tools that operate on + * object files created by such tools). + * + * All i80960 development is done in a CROSS-DEVELOPMENT environment. I.e., + * object code is generated on, and executed under the direction of a symbolic + * debugger running on, a host system. We do not want to be subject to the + * vagaries of which host it is or whether it supports COFF or a.out format, or + * anything else. We DO want to: + * + * o always generate the same format object files, regardless of host. + * + * o have an 'a.out' header that we can modify for our own purposes + * (the 80960 is typically an embedded processor and may require + * enhanced linker support that the normal a.out.h header can't + * accommodate). + * + * As for byte-ordering, the following rules apply: + * + * o Text and data that is actually downloaded to the target is always + * in i80960 (little-endian) order. + * + * o All other numbers (in the header, symbols, relocation directives) + * are in host byte-order: object files CANNOT be lifted from a + * little-end host and used on a big-endian (or vice versa) without + * modification. + * + * o The downloader ('comm960') takes care to generate a pseudo-header + * with correct (i80960) byte-ordering before shipping text and data + * off to the NINDY monitor in the target systems. Symbols and + * relocation info are never sent to the target. + */ + + +#define OBJ_BOUT 1 + +#include "targ-cpu.h" + +/* bout uses host byte order for headers */ +#ifdef CROSS_COMPILE +#undef CROSS_COMPILE +#endif /* CROSS_COMPILE */ + +/* We want \v. */ +#define BACKSLASH_V 1 + +#define OBJ_DEFAULT_OUTPUT_FILE_NAME "b.out" + +extern const short seg_N_TYPE[]; +extern const segT N_TYPE_seg[]; + +#define BMAGIC 0415 +/* We don't accept the following (see N_BADMAG macro). + * They're just here so GNU code will compile. + */ +#define OMAGIC 0407 /* old impure format */ +#define NMAGIC 0410 /* read-only text */ +#define ZMAGIC 0413 /* demand load format */ + +/* FILE HEADER + * All 'lengths' are given as a number of bytes. + * All 'alignments' are for relinkable files only; an alignment of + * 'n' indicates the corresponding segment must begin at an + * address that is a multiple of (2**n). + */ +struct exec { + /* Standard stuff */ + unsigned long a_magic; /* Identifies this as a b.out file */ + unsigned long a_text; /* Length of text */ + unsigned long a_data; /* Length of data */ + unsigned long a_bss; /* Length of runtime uninitialized data area */ + unsigned long a_syms; /* Length of symbol table */ + unsigned long a_entry; /* Runtime start address */ + unsigned long a_trsize; /* Length of text relocation info */ + unsigned long a_drsize; /* Length of data relocation info */ + + /* Added for i960 */ + unsigned long a_tload; /* Text runtime load address */ + unsigned long a_dload; /* Data runtime load address */ + unsigned char a_talign; /* Alignment of text segment */ + unsigned char a_dalign; /* Alignment of data segment */ + unsigned char a_balign; /* Alignment of bss segment */ + unsigned char unused; /* (Just to make struct size a multiple of 4) */ +}; + +#define N_BADMAG(x) (((x).a_magic) != BMAGIC) +#define N_TXTOFF(x) ( sizeof(struct exec) ) +#define N_DATOFF(x) ( N_TXTOFF(x) + (x).a_text ) +#define N_TROFF(x) ( N_DATOFF(x) + (x).a_data ) +#define N_DROFF(x) ( N_TROFF(x) + (x).a_trsize ) +#define N_SYMOFF(x) ( N_DROFF(x) + (x).a_drsize ) +#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms ) + +/* A single entry in the symbol table + */ +struct nlist { + union { + char *n_name; + struct nlist *n_next; + long n_strx; /* Index into string table */ + } n_un; + unsigned char n_type; /* See below */ + char n_other; /* Used in i80960 support -- see below */ + short n_desc; + unsigned long n_value; +}; + +typedef struct nlist obj_symbol_type; + +/* Legal values of n_type + */ +#define N_UNDF 0 /* Undefined symbol */ +#define N_ABS 2 /* Absolute symbol */ +#define N_TEXT 4 /* Text symbol */ +#define N_DATA 6 /* Data symbol */ +#define N_BSS 8 /* BSS symbol */ +#define N_FN 31 /* Filename symbol */ + +#define N_EXT 1 /* External symbol (OR'd in with one of above) */ +#define N_TYPE 036 /* Mask for all the type bits */ +#define N_STAB 0340 /* Mask for all bits used for SDB entries */ + +#ifndef CUSTOM_RELOC_FORMAT +struct relocation_info { + int r_address; /* File address of item to be relocated */ + unsigned + r_index:24,/* Index of symbol on which relocation is based*/ + r_pcrel:1, /* 1 => relocate PC-relative; else absolute + * On i960, pc-relative implies 24-bit + * address, absolute implies 32-bit. + */ + r_length:2, /* Number of bytes to relocate: + * 0 => 1 byte + * 1 => 2 bytes + * 2 => 4 bytes -- only value used for i960 + */ + r_extern:1, + r_bsr:1, /* Something for the GNU NS32K assembler */ + r_disp:1, /* Something for the GNU NS32K assembler */ + r_callj:1, /* 1 if relocation target is an i960 'callj' */ + nuthin:1; /* Unused */ +}; +#endif /* CUSTOM_RELOC_FORMAT */ + +/* + * Macros to extract information from a symbol table entry. + * This syntaxic indirection allows independence regarding a.out or coff. + * The argument (s) of all these macros is a pointer to a symbol table entry. + */ + +/* Predicates */ +/* True if the symbol is external */ +#define S_IS_EXTERNAL(s) ((s)->sy_symbol.n_type & N_EXT) + +/* True if symbol has been defined, ie is in N_{TEXT,DATA,BSS,ABS} or N_EXT */ +#define S_IS_DEFINED(s) ((S_GET_TYPE(s) != N_UNDF) || (S_GET_DESC(s) != 0)) +#define S_IS_REGISTER(s) ((s)->sy_symbol.n_type == N_REGISTER) + +/* True if a debug special symbol entry */ +#define S_IS_DEBUG(s) ((s)->sy_symbol.n_type & N_STAB) +/* True if a symbol is local symbol name */ +/* A symbol name whose name begin with ^A is a gas internal pseudo symbol + nameless symbols come from .stab directives. */ +#define S_IS_LOCAL(s) (S_GET_NAME(s) && \ + !S_IS_DEBUG(s) && \ + (S_GET_NAME(s)[0] == '\001' || \ + (S_LOCAL_NAME(s) && !flagseen['L']))) +/* True if a symbol is not defined in this file */ +#define S_IS_EXTERN(s) ((s)->sy_symbol.n_type & N_EXT) +/* True if the symbol has been generated because of a .stabd directive */ +#define S_IS_STABD(s) (S_GET_NAME(s) == NULL) + +/* Accessors */ +/* The value of the symbol */ +#define S_GET_VALUE(s) ((unsigned long) ((s)->sy_symbol.n_value)) +/* The name of the symbol */ +#define S_GET_NAME(s) ((s)->sy_symbol.n_un.n_name) +/* The pointer to the string table */ +#define S_GET_OFFSET(s) ((s)->sy_symbol.n_un.n_strx) +/* The type of the symbol */ +#define S_GET_TYPE(s) ((s)->sy_symbol.n_type & N_TYPE) +/* The numeric value of the segment */ +#define S_GET_SEGMENT(s) (N_TYPE_seg[S_GET_TYPE(s)]) +/* The n_other expression value */ +#define S_GET_OTHER(s) ((s)->sy_symbol.n_other) +/* The n_desc expression value */ +#define S_GET_DESC(s) ((s)->sy_symbol.n_desc) + +/* Modifiers */ +/* Set the value of the symbol */ +#define S_SET_VALUE(s,v) ((s)->sy_symbol.n_value = (unsigned long) (v)) +/* Assume that a symbol cannot be simultaneously in more than on segment */ +/* set segment */ +#define S_SET_SEGMENT(s,seg) ((s)->sy_symbol.n_type &= ~N_TYPE,(s)->sy_symbol.n_type|=SEGMENT_TO_SYMBOL_TYPE(seg)) +/* The symbol is external */ +#define S_SET_EXTERNAL(s) ((s)->sy_symbol.n_type |= N_EXT) +/* The symbol is not external */ +#define S_CLEAR_EXTERNAL(s) ((s)->sy_symbol.n_type &= ~N_EXT) +/* Set the name of the symbol */ +#define S_SET_NAME(s,v) ((s)->sy_symbol.n_un.n_name = (v)) +/* Set the offset in the string table */ +#define S_SET_OFFSET(s,v) ((s)->sy_symbol.n_un.n_strx = (v)) +/* Set the n_other expression value */ +#define S_SET_OTHER(s,v) ((s)->sy_symbol.n_other = (v)) +/* Set the n_desc expression value */ +#define S_SET_DESC(s,v) ((s)->sy_symbol.n_desc = (v)) + +/* File header macro and type definition */ + +#define H_GET_FILE_SIZE(h) (sizeof(struct exec) + \ + H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ + H_GET_SYMBOL_TABLE_SIZE(h) + \ + H_GET_TEXT_RELOCATION_SIZE(h) + \ + H_GET_DATA_RELOCATION_SIZE(h) + \ + (h)->string_table_size) + +#define H_GET_HEADER_SIZE(h) (sizeof(struct exec)) +#define H_GET_TEXT_SIZE(h) ((h)->header.a_text) +#define H_GET_DATA_SIZE(h) ((h)->header.a_data) +#define H_GET_BSS_SIZE(h) ((h)->header.a_bss) +#define H_GET_TEXT_RELOCATION_SIZE(h) ((h)->header.a_trsize) +#define H_GET_DATA_RELOCATION_SIZE(h) ((h)->header.a_drsize) +#define H_GET_SYMBOL_TABLE_SIZE(h) ((h)->header.a_syms) +#define H_GET_MAGIC_NUMBER(h) ((h)->header.a_info) +#define H_GET_ENTRY_POINT(h) ((h)->header.a_entry) +#define H_GET_STRING_SIZE(h) ((h)->string_table_size) +#define H_GET_LINENO_SIZE(h) (0) + +#ifdef EXEC_MACHINE_TYPE +#define H_GET_MACHINE_TYPE(h) ((h)->header.a_machtype) +#endif /* EXEC_MACHINE_TYPE */ +#ifdef EXEC_VERSION +#define H_GET_VERSION(h) ((h)->header.a_version) +#endif /* EXEC_VERSION */ + +#define H_SET_TEXT_SIZE(h,v) ((h)->header.a_text = (v)) +#define H_SET_DATA_SIZE(h,v) ((h)->header.a_data = (v)) +#define H_SET_BSS_SIZE(h,v) ((h)->header.a_bss = (v)) + +#define H_SET_RELOCATION_SIZE(h,t,d) (H_SET_TEXT_RELOCATION_SIZE((h),(t)),\ + H_SET_DATA_RELOCATION_SIZE((h),(d))) + +#define H_SET_TEXT_RELOCATION_SIZE(h,v) ((h)->header.a_trsize = (v)) +#define H_SET_DATA_RELOCATION_SIZE(h,v) ((h)->header.a_drsize = (v)) +#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->header.a_syms = (v) * \ + sizeof(struct nlist)) + +#define H_SET_MAGIC_NUMBER(h,v) ((h)->header.a_magic = (v)) + +#define H_SET_ENTRY_POINT(h,v) ((h)->header.a_entry = (v)) +#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v)) +#ifdef EXEC_MACHINE_TYPE +#define H_SET_MACHINE_TYPE(h,v) ((h)->header.a_machtype = (v)) +#endif /* EXEC_MACHINE_TYPE */ +#ifdef EXEC_VERSION +#define H_SET_VERSION(h,v) ((h)->header.a_version = (v)) +#endif /* EXEC_VERSION */ + +/* + * Current means for getting the name of a segment. + * This will change for infinite-segments support (e.g. COFF). + */ +#define segment_name(seg) ( seg_name[(int)(seg)] ) +extern char *const seg_name[]; + +typedef struct { + struct exec header; /* a.out header */ + long string_table_size; /* names + '\0' + sizeof(int) */ +} object_headers; + +/* unused hooks. */ +#define OBJ_EMIT_LINENO(a, b, c) {;} + +#if __STDC__ +struct fix; +void tc_aout_fix_to_chars(char *where, struct fix *fixP, relax_addressT segment_address); +#else /* not __STDC__ */ +void tc_aout_fix_to_chars(); +#endif /* not __STDC__ */ + +enum reloc_type { + NO_RELOC, RELOC_32, +}; + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-bout.h */ diff --git a/gnu/usr.bin/as/config/obj-coff.c b/gnu/usr.bin/as/config/obj-coff.c new file mode 100644 index 000000000000..238e6c5c011c --- /dev/null +++ b/gnu/usr.bin/as/config/obj-coff.c @@ -0,0 +1,1978 @@ +/* coff object file format + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "as.h" + +#include "obstack.h" + +lineno* lineno_rootP; + +const short seg_N_TYPE[] = { /* in: segT out: N_TYPE bits */ + C_ABS_SECTION, + C_TEXT_SECTION, + C_DATA_SECTION, + C_BSS_SECTION, + C_UNDEF_SECTION, /* SEG_UNKNOWN */ + C_UNDEF_SECTION, /* SEG_ABSENT */ + C_UNDEF_SECTION, /* SEG_PASS1 */ + C_UNDEF_SECTION, /* SEG_GOOF */ + C_UNDEF_SECTION, /* SEG_BIG */ + C_UNDEF_SECTION, /* SEG_DIFFERENCE */ + C_DEBUG_SECTION, /* SEG_DEBUG */ + C_NTV_SECTION, /* SEG_NTV */ + C_PTV_SECTION, /* SEG_PTV */ + C_REGISTER_SECTION, /* SEG_REGISTER */ +}; + + +/* Add 4 to the real value to get the index and compensate the negatives */ + +const segT N_TYPE_seg[32] = +{ + SEG_PTV, /* C_PTV_SECTION == -4 */ + SEG_NTV, /* C_NTV_SECTION == -3 */ + SEG_DEBUG, /* C_DEBUG_SECTION == -2 */ + SEG_ABSOLUTE, /* C_ABS_SECTION == -1 */ + SEG_UNKNOWN, /* C_UNDEF_SECTION == 0 */ + SEG_TEXT, /* C_TEXT_SECTION == 1 */ + SEG_DATA, /* C_DATA_SECTION == 2 */ + SEG_BSS, /* C_BSS_SECTION == 3 */ + SEG_REGISTER, /* C_REGISTER_SECTION == 4 */ + 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 + }; + +#if __STDC__ == 1 + +char *s_get_name(symbolS *s); +static symbolS *tag_find_or_make(char *name); +static symbolS* tag_find(char *name); +#ifdef BFD_HEADERS +static void obj_coff_section_header_append(char **where, struct internal_scnhdr *header); +#else +static void obj_coff_section_header_append(char **where, SCNHDR *header); +#endif +static void obj_coff_def(int what); +static void obj_coff_dim(void); +static void obj_coff_endef(void); +static void obj_coff_line(void); +static void obj_coff_ln(void); +static void obj_coff_scl(void); +static void obj_coff_size(void); +static void obj_coff_stab(int what); +static void obj_coff_tag(void); +static void obj_coff_type(void); +static void obj_coff_val(void); +static void tag_init(void); +static void tag_insert(char *name, symbolS *symbolP); + +#else /* not __STDC__ */ + +char *s_get_name(); +static symbolS *tag_find(); +static symbolS *tag_find_or_make(); +static void obj_coff_section_header_append(); +static void obj_coff_def(); +static void obj_coff_dim(); +static void obj_coff_endef(); +static void obj_coff_line(); +static void obj_coff_ln(); +static void obj_coff_scl(); +static void obj_coff_size(); +static void obj_coff_stab(); +static void obj_coff_tag(); +static void obj_coff_type(); +static void obj_coff_val(); +static void tag_init(); +static void tag_insert(); + +#endif /* not __STDC__ */ + +static struct hash_control *tag_hash; +static symbolS *def_symbol_in_progress = NULL; + +const pseudo_typeS obj_pseudo_table[] = { +#ifndef IGNORE_DEBUG + { "def", obj_coff_def, 0 }, + { "dim", obj_coff_dim, 0 }, + { "endef", obj_coff_endef, 0 }, + { "line", obj_coff_line, 0 }, + { "ln", obj_coff_ln, 0 }, + { "scl", obj_coff_scl, 0 }, + { "size", obj_coff_size, 0 }, + { "tag", obj_coff_tag, 0 }, + { "type", obj_coff_type, 0 }, + { "val", obj_coff_val, 0 }, +#else + { "def", s_ignore, 0 }, + { "dim", s_ignore, 0 }, + { "endef", s_ignore, 0 }, + { "line", s_ignore, 0 }, + { "ln", s_ignore, 0 }, + { "scl", s_ignore, 0 }, + { "size", s_ignore, 0 }, + { "tag", s_ignore, 0 }, + { "type", s_ignore, 0 }, + { "val", s_ignore, 0 }, +#endif /* ignore debug */ + + { "ident", s_ignore, 0 }, /* we don't yet handle this. */ + + + /* stabs aka a.out aka b.out directives for debug symbols. + Currently ignored silently. Except for .line at which + we guess from context. */ + { "desc", s_ignore, 0 }, /* def */ + /* { "line", s_ignore, 0 }, */ /* source code line number */ + { "stabd", obj_coff_stab, 'd' }, /* stabs */ + { "stabn", obj_coff_stab, 'n' }, /* stabs */ + { "stabs", obj_coff_stab, 's' }, /* stabs */ + + /* stabs-in-coff (?) debug pseudos (ignored) */ + { "optim", s_ignore, 0 }, /* For sun386i cc (?) */ + /* other stuff */ + { "ABORT", s_abort, 0 }, + + { NULL} /* end sentinel */ +}; /* obj_pseudo_table */ + + +/* obj dependant output values */ +#ifdef BFD_HEADERS +static struct internal_scnhdr bss_section_header; +struct internal_scnhdr data_section_header; +struct internal_scnhdr text_section_header; +#else +static SCNHDR bss_section_header; +SCNHDR data_section_header; +SCNHDR text_section_header; +#endif +/* Relocation. */ + +static int reloc_compare(p1, p2) +#ifdef BFD_HEADERS +struct internal_reloc *p1, *p2; +#else +RELOC *p1, *p2; +#endif +{ + return (int)(p1->r_vaddr - p2->r_vaddr); +} + +/* + * emit_relocations() + * + * Crawl along a fixS chain. Emit the segment's relocations. + */ + +void obj_emit_relocations(where, fixP, segment_address_in_file) +char **where; +fixS *fixP; /* Fixup chain for this segment. */ +relax_addressT segment_address_in_file; +{ +#ifdef BFD_HEADERS + struct internal_reloc *ri_table; +#else + RELOC *ri_table; +#endif + symbolS *symbolP; + int i, count; + fixS *p; + + for (count = 0, p = fixP; p ; p = p->fx_next) + if (p->fx_addsy) count++; + if (!count) + return; + +#ifdef BFD_HEADERS + ri_table = (struct internal_reloc *) calloc(sizeof(*ri_table),count); +#else + ri_table = (RELOC *) calloc(sizeof(*ri_table),count); +#endif + if (!ri_table) + as_fatal ("obj_emit_relocations: Could not malloc relocation table"); + +#ifdef TC_I960 + callj_table = (char *)malloc (sizeof(char)*count); + if (!callj_table) + as_fatal ("obj_emit_relocations: Could not malloc callj table"); +#endif + + for (i = 0; fixP; fixP = fixP->fx_next) { + if (symbolP = fixP->fx_addsy) { +#if defined(TC_M68K) + ri_table[i].r_type = (fixP->fx_pcrel ? + (fixP->fx_size == 1 ? R_PCRBYTE : + fixP->fx_size == 2 ? R_PCRWORD : + R_PCRLONG): + (fixP->fx_size == 1 ? R_RELBYTE : + fixP->fx_size == 2 ? R_RELWORD : + R_RELLONG)); +#elif defined(TC_I386) + /* FIXME-SOON R_OFF8 & R_DIR16 are a vague guess, completly + untested. */ + ri_table[i].r_type = (fixP->fx_pcrel ? + (fixP->fx_size == 1 ? R_PCRBYTE : + fixP->fx_size == 2 ? R_PCRWORD : + R_PCRLONG): + (fixP->fx_size == 1 ? R_OFF8 : + fixP->fx_size == 2 ? R_DIR16 : + R_DIR32)); +#elif defined(TC_I960) + ri_table[i].r_type = (fixP->fx_pcrel + ? R_IPRMED + : R_RELLONG); + callj_table[i] = fixP->fx_callj ? 1 : 0; +#elif defined(TC_A29K) + ri_table[i].r_type = tc_coff_fix2rtype(fixP); + +#else +#error you lose +#endif /* TC_M68K || TC_I386 */ + ri_table[i].r_vaddr = (fixP->fx_frag->fr_address + + fixP->fx_where); + /* If symbol associated to relocation entry is a bss symbol + or undefined symbol just remember the index of the symbol. + Otherwise store the index of the symbol describing the + section the symbol belong to. This heuristic speeds up ld. + */ + /* Local symbols can generate relocation information. In case + of structure return for instance. But they have no symbol + number because they won't be emitted in the final object. + In the case where they are in the BSS section, this leads + to an incorrect r_symndx. + Under bsd the loader do not care if the symbol reference + is incorrect. But the SYS V ld complains about this. To + avoid this we associate the symbol to the associated + section, *even* if it is the BSS section. */ + /* If someone can tell me why the other symbols of the bss + section are not associated with the .bss section entry, + I'd be gratefull. I guess that it has to do with the special + nature of the .bss section. Or maybe this is because the + bss symbols are declared in the common section and can + be resized later. Can it break code some where ? */ + ri_table[i].r_symndx = (S_GET_SEGMENT(symbolP) == SEG_TEXT + ? dot_text_symbol->sy_number + : (S_GET_SEGMENT(symbolP) == SEG_DATA + ? dot_data_symbol->sy_number + : ((SF_GET_LOCAL(symbolP) + ? dot_bss_symbol->sy_number + : symbolP->sy_number)))); /* bss or undefined */ + + /* md_ri_to_chars((char *) &ri, ri); */ /* Last step : write md f */ + + i++; + } /* if there's a symbol */ + } /* for each fixP */ + + /* + * AIX ld prefer to have the reloc table with r_vaddr sorted. + * But sorting it should not hurt any other ld. + */ + qsort (ri_table, count, sizeof(*ri_table), reloc_compare); + + for (i = 0; i < count; i++) + { +#ifdef BFD_HEADERS + *where += bfd_coff_swap_reloc_out(stdoutput, &ri_table[i], *where); +# ifdef TC_A29K + /* The 29k has a special kludge for the high 16 bit reloc. + Two relocations are emmited, R_IHIHALF, and R_IHCONST. + The second one doesn't contain a symbol, but uses the + value for offset */ + if (ri_table[i].r_type == R_IHIHALF) + { + /* now emit the second bit */ + ri_table[i].r_type = R_IHCONST; + ri_table[i].r_symndx = fixP->fx_addnumber; + *where += bfd_coff_swap_reloc_out(stdoutput, &ri_table[i], + *where); + } +# endif /* TC_A29K */ + +#else /* not BFD_HEADERS */ + append(where, (char *) &ri_table[i], RELSZ); +#endif /* not BFD_HEADERS */ + +#ifdef TC_I960 + if (callj_table[i]) + { + ri_table[i].r_type = R_OPTCALL; +# ifdef BFD_HEADERS + *where += bfd_coff_swap_reloc_out(stdoutput, &ri_table[i], + *where); +# else + append(where, (char *) &ri_table[i], (unsigned long)RELSZ); +# endif /* BFD_HEADERS */ + } /* if it's a callj, do it again for the opcode */ +#endif /* TC_I960 */ + } + + free (ri_table); +#ifdef TC_I960 + free (callj_table); +#endif + + return; +} /* obj_emit_relocations() */ + +/* Coff file generation & utilities */ + +#ifdef BFD_HEADERS +void obj_header_append(where, headers) +char **where; +object_headers *headers; +{ + tc_headers_hook(headers); + *where += bfd_coff_swap_filehdr_out(stdoutput, &(headers->filehdr), *where); +#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER + *where += bfd_coff_swap_aouthdr_out(stdoutput, &(headers->aouthdr), *where); +#endif + obj_coff_section_header_append(where, &text_section_header); + obj_coff_section_header_append(where, &data_section_header); + obj_coff_section_header_append(where, &bss_section_header); + +} + +#else + +void obj_header_append(where, headers) +char **where; +object_headers *headers; +{ + tc_headers_hook(headers); + +#ifdef CROSS_COMPILE + /* Eventually swap bytes for cross compilation for file header */ + md_number_to_chars(*where, headers->filehdr.f_magic, sizeof(headers->filehdr.f_magic)); + *where += sizeof(headers->filehdr.f_magic); + md_number_to_chars(*where, headers->filehdr.f_nscns, sizeof(headers->filehdr.f_nscns)); + *where += sizeof(headers->filehdr.f_nscns); + md_number_to_chars(*where, headers->filehdr.f_timdat, sizeof(headers->filehdr.f_timdat)); + *where += sizeof(headers->filehdr.f_timdat); + md_number_to_chars(*where, headers->filehdr.f_symptr, sizeof(headers->filehdr.f_symptr)); + *where += sizeof(headers->filehdr.f_symptr); + md_number_to_chars(*where, headers->filehdr.f_nsyms, sizeof(headers->filehdr.f_nsyms)); + *where += sizeof(headers->filehdr.f_nsyms); + md_number_to_chars(*where, headers->filehdr.f_opthdr, sizeof(headers->filehdr.f_opthdr)); + *where += sizeof(headers->filehdr.f_opthdr); + md_number_to_chars(*where, headers->filehdr.f_flags, sizeof(headers->filehdr.f_flags)); + *where += sizeof(headers->filehdr.f_flags); + +#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER + /* Eventually swap bytes for cross compilation for a.out header */ + md_number_to_chars(*where, headers->aouthdr.magic, sizeof(headers->aouthdr.magic)); + *where += sizeof(headers->aouthdr.magic); + md_number_to_chars(*where, headers->aouthdr.vstamp, sizeof(headers->aouthdr.vstamp)); + *where += sizeof(headers->aouthdr.vstamp); + md_number_to_chars(*where, headers->aouthdr.tsize, sizeof(headers->aouthdr.tsize)); + *where += sizeof(headers->aouthdr.tsize); + md_number_to_chars(*where, headers->aouthdr.dsize, sizeof(headers->aouthdr.dsize)); + *where += sizeof(headers->aouthdr.dsize); + md_number_to_chars(*where, headers->aouthdr.bsize, sizeof(headers->aouthdr.bsize)); + *where += sizeof(headers->aouthdr.bsize); + md_number_to_chars(*where, headers->aouthdr.entry, sizeof(headers->aouthdr.entry)); + *where += sizeof(headers->aouthdr.entry); + md_number_to_chars(*where, headers->aouthdr.text_start, sizeof(headers->aouthdr.text_start)); + *where += sizeof(headers->aouthdr.text_start); + md_number_to_chars(*where, headers->aouthdr.data_start, sizeof(headers->aouthdr.data_start)); + *where += sizeof(headers->aouthdr.data_start); + md_number_to_chars(*where, headers->aouthdr.tagentries, sizeof(headers->aouthdr.tagentries)); + *where += sizeof(headers->aouthdr.tagentries); +#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */ + +#else /* CROSS_COMPILE */ + + append(where, (char *) &headers->filehdr, sizeof(headers->filehdr)); +#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER + append(where, (char *) &headers->aouthdr, sizeof(headers->aouthdr)); +#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */ + +#endif /* CROSS_COMPILE */ + + /* Output the section headers */ + obj_coff_section_header_append(where, &text_section_header); + obj_coff_section_header_append(where, &data_section_header); + obj_coff_section_header_append(where, &bss_section_header); + + return; +} /* obj_header_append() */ +#endif +void obj_symbol_to_chars(where, symbolP) +char **where; +symbolS *symbolP; +{ +#ifdef BFD_HEADERS + unsigned int numaux = symbolP->sy_symbol.ost_entry.n_numaux; + unsigned int i; + + if (S_GET_SEGMENT(symbolP) == SEG_REGISTER) { + S_SET_SEGMENT(symbolP, SEG_ABSOLUTE); + } + *where += bfd_coff_swap_sym_out(stdoutput, &symbolP->sy_symbol.ost_entry, + *where); + + for (i = 0; i < numaux; i++) + { + *where += bfd_coff_swap_aux_out(stdoutput, + &symbolP->sy_symbol.ost_auxent[i], + S_GET_DATA_TYPE(symbolP), + S_GET_STORAGE_CLASS(symbolP), + *where); + } + +#else /* BFD_HEADERS */ + SYMENT *syment = &symbolP->sy_symbol.ost_entry; + int i; + char numaux = syment->n_numaux; + unsigned short type = S_GET_DATA_TYPE(symbolP); + +#ifdef CROSS_COMPILE + md_number_to_chars(*where, syment->n_value, sizeof(syment->n_value)); + *where += sizeof(syment->n_value); + md_number_to_chars(*where, syment->n_scnum, sizeof(syment->n_scnum)); + *where += sizeof(syment->n_scnum); + md_number_to_chars(*where, 0, sizeof(short)); /* pad n_flags */ + *where += sizeof(short); + md_number_to_chars(*where, syment->n_type, sizeof(syment->n_type)); + *where += sizeof(syment->n_type); + md_number_to_chars(*where, syment->n_sclass, sizeof(syment->n_sclass)); + *where += sizeof(syment->n_sclass); + md_number_to_chars(*where, syment->n_numaux, sizeof(syment->n_numaux)); + *where += sizeof(syment->n_numaux); +#else /* CROSS_COMPILE */ + append(where, (char *) syment, sizeof(*syment)); +#endif /* CROSS_COMPILE */ + + /* Should do the following : if (.file entry) MD(..)... else if (static entry) MD(..) */ + if (numaux > OBJ_COFF_MAX_AUXENTRIES) { + as_bad("Internal error? too many auxents for symbol"); + } /* too many auxents */ + + for (i = 0; i < numaux; ++i) { +#ifdef CROSS_COMPILE +#if 0 /* This code has never been tested */ + /* The most common case, x_sym entry. */ + if ((SF_GET(symbolP) & (SF_FILE | SF_STATICS)) == 0) { + md_number_to_chars(*where, auxP->x_sym.x_tagndx, sizeof(auxP->x_sym.x_tagndx)); + *where += sizeof(auxP->x_sym.x_tagndx); + if (ISFCN(type)) { + md_number_to_chars(*where, auxP->x_sym.x_misc.x_fsize, sizeof(auxP->x_sym.x_misc.x_fsize)); + *where += sizeof(auxP->x_sym.x_misc.x_fsize); + } else { + md_number_to_chars(*where, auxP->x_sym.x_misc.x_lnno, sizeof(auxP->x_sym.x_misc.x_lnno)); + *where += sizeof(auxP->x_sym.x_misc.x_lnno); + md_number_to_chars(*where, auxP->x_sym.x_misc.x_size, sizeof(auxP->x_sym.x_misc.x_size)); + *where += sizeof(auxP->x_sym.x_misc.x_size); + } + if (ISARY(type)) { + register int index; + for (index = 0; index < DIMNUM; index++) + md_number_to_chars(*where, auxP->x_sym.x_fcnary.x_ary.x_dimen[index], sizeof(auxP->x_sym.x_fcnary.x_ary.x_dimen[index])); + *where += sizeof(auxP->x_sym.x_fcnary.x_ary.x_dimen[index]); + } else { + md_number_to_chars(*where, auxP->x_sym.x_fcnary.x_fcn.x_lnnoptr, sizeof(auxP->x_sym.x_fcnary.x_fcn.x_lnnoptr)); + *where += sizeof(auxP->x_sym.x_fcnary.x_fcn.x_lnnoptr); + md_number_to_chars(*where, auxP->x_sym.x_fcnary.x_fcn.x_endndx, sizeof(auxP->x_sym.x_fcnary.x_fcn.x_endndx)); + *where += sizeof(auxP->x_sym.x_fcnary.x_fcn.x_endndx); + } + md_number_to_chars(*where, auxP->x_sym.x_tvndx, sizeof(auxP->x_sym.x_tvndx)); + *where += sizeof(auxP->x_sym.x_tvndx); + } else if (SF_GET_FILE(symbolP)) { /* .file */ + ; + } else if (SF_GET_STATICS(symbolP)) { /* .text, .data, .bss symbols */ + md_number_to_chars(*where, auxP->x_scn.x_scnlen, sizeof(auxP->x_scn.x_scnlen)); + *where += sizeof(auxP->x_scn.x_scnlen); + md_number_to_chars(*where, auxP->x_scn.x_nreloc, sizeof(auxP->x_scn.x_nreloc)); + *where += sizeof(auxP->x_scn.x_nreloc); + md_number_to_chars(*where, auxP->x_scn.x_nlinno, sizeof(auxP->x_scn.x_nlinno)); + *where += sizeof(auxP->x_scn.x_nlinno); + } +#endif /* 0 */ +#else /* CROSS_COMPILE */ + append(where, (char *) &symbolP->sy_symbol.ost_auxent[i], sizeof(symbolP->sy_symbol.ost_auxent[i])); +#endif /* CROSS_COMPILE */ + + }; /* for each aux in use */ +#endif /* BFD_HEADERS */ + return; +} /* obj_symbol_to_chars() */ + +#ifdef BFD_HEADERS +static void obj_coff_section_header_append(where, header) +char **where; +struct internal_scnhdr *header; +{ + *where += bfd_coff_swap_scnhdr_out(stdoutput, header, *where); +} +#else +static void obj_coff_section_header_append(where, header) +char **where; +SCNHDR *header; +{ +#ifdef CROSS_COMPILE + memcpy(*where, header->s_name, sizeof(header->s_name)); + *where += sizeof(header->s_name); + + md_number_to_chars(*where, header->s_paddr, sizeof(header->s_paddr)); + *where += sizeof(header->s_paddr); + + md_number_to_chars(*where, header->s_vaddr, sizeof(header->s_vaddr)); + *where += sizeof(header->s_vaddr); + + md_number_to_chars(*where, header->s_size, sizeof(header->s_size)); + *where += sizeof(header->s_size); + + md_number_to_chars(*where, header->s_scnptr, sizeof(header->s_scnptr)); + *where += sizeof(header->s_scnptr); + + md_number_to_chars(*where, header->s_relptr, sizeof(header->s_relptr)); + *where += sizeof(header->s_relptr); + + md_number_to_chars(*where, header->s_lnnoptr, sizeof(header->s_lnnoptr)); + *where += sizeof(header->s_lnnoptr); + + md_number_to_chars(*where, header->s_nreloc, sizeof(header->s_nreloc)); + *where += sizeof(header->s_nreloc); + + md_number_to_chars(*where, header->s_nlnno, sizeof(header->s_nlnno)); + *where += sizeof(header->s_nlnno); + + md_number_to_chars(*where, header->s_flags, sizeof(header->s_flags)); + *where += sizeof(header->s_flags); + +#ifdef TC_I960 + md_number_to_chars(*where, header->s_align, sizeof(header->s_align)); + *where += sizeof(header->s_align); +#endif /* TC_I960 */ + +#else /* CROSS_COMPILE */ + + append(where, (char *) header, sizeof(*header)); + +#endif /* CROSS_COMPILE */ + + return; +} /* obj_coff_section_header_append() */ + +#endif +void obj_emit_symbols(where, symbol_rootP) +char **where; +symbolS *symbol_rootP; +{ + symbolS *symbolP; + /* + * Emit all symbols left in the symbol chain. + */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + /* Used to save the offset of the name. It is used to point + to the string in memory but must be a file offset. */ + register char * temp; + + tc_coff_symbol_emit_hook(symbolP); + + temp = S_GET_NAME(symbolP); + if (SF_GET_STRING(symbolP)) { + S_SET_OFFSET(symbolP, symbolP->sy_name_offset); + S_SET_ZEROES(symbolP, 0); + } else { + memset(symbolP->sy_symbol.ost_entry.n_name, '\0', SYMNMLEN); + strncpy(symbolP->sy_symbol.ost_entry.n_name, temp, SYMNMLEN); + } + obj_symbol_to_chars(where, symbolP); + S_SET_NAME(symbolP,temp); + } +} /* obj_emit_symbols() */ + +/* Merge a debug symbol containing debug information into a normal symbol. */ + +void c_symbol_merge(debug, normal) +symbolS *debug; +symbolS *normal; +{ + S_SET_DATA_TYPE(normal, S_GET_DATA_TYPE(debug)); + S_SET_STORAGE_CLASS(normal, S_GET_STORAGE_CLASS(debug)); + + if (S_GET_NUMBER_AUXILIARY(debug) > S_GET_NUMBER_AUXILIARY(normal)) { + S_SET_NUMBER_AUXILIARY(normal, S_GET_NUMBER_AUXILIARY(debug)); + } /* take the most we have */ + + if (S_GET_NUMBER_AUXILIARY(debug) > 0) { + memcpy((char*)&normal->sy_symbol.ost_auxent[0], (char*)&debug->sy_symbol.ost_auxent[0], S_GET_NUMBER_AUXILIARY(debug) * AUXESZ); + } /* Move all the auxiliary information */ + + /* Move the debug flags. */ + SF_SET_DEBUG_FIELD(normal, SF_GET_DEBUG_FIELD(debug)); +} /* c_symbol_merge() */ + +static symbolS *previous_file_symbol = NULL; + +void c_dot_file_symbol(filename) +char *filename; +{ + symbolS* symbolP; + + symbolP = symbol_new(".file", + SEG_DEBUG, + 0, + &zero_address_frag); + + S_SET_STORAGE_CLASS(symbolP, C_FILE); + S_SET_NUMBER_AUXILIARY(symbolP, 1); + SA_SET_FILE_FNAME(symbolP, filename); + SF_SET_DEBUG(symbolP); + S_SET_VALUE(symbolP, (long) previous_file_symbol); + + previous_file_symbol = symbolP; + + /* Make sure that the symbol is first on the symbol chain */ + if (symbol_rootP != symbolP) { + if (symbolP == symbol_lastP) { + symbol_lastP = symbol_lastP->sy_previous; + } /* if it was the last thing on the list */ + + symbol_remove(symbolP, &symbol_rootP, &symbol_lastP); + symbol_insert(symbolP, symbol_rootP, &symbol_rootP, &symbol_lastP); + symbol_rootP = symbolP; + } /* if not first on the list */ + +} /* c_dot_file_symbol() */ +/* + * Build a 'section static' symbol. + */ + +char *c_section_symbol(name, value, length, nreloc, nlnno) +char *name; +long value; +long length; +unsigned short nreloc; +unsigned short nlnno; +{ + symbolS *symbolP; + + symbolP = symbol_new(name, + (name[1] == 't' + ? SEG_TEXT + : (name[1] == 'd' + ? SEG_DATA + : SEG_BSS)), + value, + &zero_address_frag); + + S_SET_STORAGE_CLASS(symbolP, C_STAT); + S_SET_NUMBER_AUXILIARY(symbolP, 1); + + SA_SET_SCN_SCNLEN(symbolP, length); + SA_SET_SCN_NRELOC(symbolP, nreloc); + SA_SET_SCN_NLINNO(symbolP, nlnno); + + SF_SET_STATICS(symbolP); + + return (char*)symbolP; +} /* c_section_symbol() */ + +void c_section_header(header, + name, + core_address, + size, + data_ptr, + reloc_ptr, + lineno_ptr, + reloc_number, + lineno_number, + alignment) +#ifdef BFD_HEADERS +struct internal_scnhdr *header; +#else +SCNHDR *header; +#endif +char *name; +long core_address; +long size; +long data_ptr; +long reloc_ptr; +long lineno_ptr; +long reloc_number; +long lineno_number; +long alignment; +{ + strncpy(header->s_name, name, 8); + header->s_paddr = header->s_vaddr = core_address; + header->s_scnptr = ((header->s_size = size) != 0) ? data_ptr : 0; + header->s_relptr = reloc_ptr; + header->s_lnnoptr = lineno_ptr; + header->s_nreloc = reloc_number; + header->s_nlnno = lineno_number; + +#ifdef OBJ_COFF_SECTION_HEADER_HAS_ALIGNMENT +#ifdef OBJ_COFF_BROKEN_ALIGNMENT + header->s_align = ((name[1] == 'b' || (size > 0)) ? 16 : 0); +#else + header->s_align = ((alignment == 0) + ? 0 + : (1 << alignment)); +#endif /* OBJ_COFF_BROKEN_ALIGNMENT */ +#endif /* OBJ_COFF_SECTION_HEADER_HAS_ALIGNMENT */ + + header->s_flags = STYP_REG | (name[1] == 't' + ? STYP_TEXT + : (name[1] == 'd' + ? STYP_DATA + : (name[1] == 'b' + ? STYP_BSS + : STYP_INFO))); + return; +} /* c_section_header() */ + +/* Line number handling */ + +int function_lineoff = -1; /* Offset in line#s where the last function + started (the odd entry for line #0) */ +int text_lineno_number = 0; +int our_lineno_number = 0; /* we use this to build pointers from .bf's + into the linetable. It should match + exactly the values that are later + assigned in text_lineno_number by + write.c. */ +lineno* lineno_lastP = (lineno*)0; + +int + c_line_new(paddr, line_number, frag) +long paddr; +unsigned short line_number; +fragS* frag; +{ + lineno* new_line = (lineno*)xmalloc(sizeof(lineno)); + + new_line->line.l_addr.l_paddr = paddr; + new_line->line.l_lnno = line_number; + new_line->frag = (char*)frag; + new_line->next = (lineno*)0; + + if (lineno_rootP == (lineno*)0) + lineno_rootP = new_line; + else + lineno_lastP->next = new_line; + lineno_lastP = new_line; + return LINESZ * our_lineno_number++; +} + +void obj_emit_lineno(where, line, file_start) +char **where; +lineno *line; +char *file_start; +{ +#ifdef BFD_HEADERS + struct bfd_internal_lineno *line_entry; +#else + LINENO *line_entry; +#endif + for (; line; line = line->next) { + line_entry = &line->line; + + /* FIXME-SOMEDAY Resolving the sy_number of function linno's used to be done in + write_object_file() but their symbols need a fileptr to the lnno, so + I moved this resolution check here. xoxorich. */ + + if (line_entry->l_lnno == 0) { + /* There is a good chance that the symbol pointed to + is not the one that will be emitted and that the + sy_number is not accurate. */ + /* char *name; */ + symbolS *symbolP; + + symbolP = (symbolS *) line_entry->l_addr.l_symndx; + + line_entry->l_addr.l_symndx = symbolP->sy_number; + symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr = *where - file_start; + + } /* if this is a function linno */ +#ifdef BFD_HEADERS + *where += bfd_coff_swap_lineno_out(stdoutput, line_entry, *where); +#else + /* No matter which member of the union we process, they are + both long. */ +#ifdef CROSS_COMPILE + md_number_to_chars(*where, line_entry->l_addr.l_paddr, sizeof(line_entry->l_addr.l_paddr)); + *where += sizeof(line_entry->l_addr.l_paddr); + + md_number_to_chars(*where, line_entry->l_lnno, sizeof(line_entry->l_lnno)); + *where += sizeof(line_entry->l_lnno); + +#ifdef TC_I960 + **where = '0'; + ++*where; + **where = '0'; + ++*where; +#endif /* TC_I960 */ + +#else /* CROSS_COMPILE */ + append(where, (char *) line_entry, LINESZ); +#endif /* CROSS_COMPILE */ +#endif /* BFD_HEADERS */ + } /* for each line number */ + + return ; +} /* obj_emit_lineno() */ + +void obj_symbol_new_hook(symbolP) +symbolS *symbolP; +{ + char underscore = 0; /* Symbol has leading _ */ + + /* Effective symbol */ + /* Store the pointer in the offset. */ + S_SET_ZEROES(symbolP, 0L); + S_SET_DATA_TYPE(symbolP, T_NULL); + S_SET_STORAGE_CLASS(symbolP, 0); + S_SET_NUMBER_AUXILIARY(symbolP, 0); + /* Additional information */ + symbolP->sy_symbol.ost_flags = 0; + /* Auxiliary entries */ + memset((char*) &symbolP->sy_symbol.ost_auxent[0], '\0', AUXESZ); + +#ifdef STRIP_UNDERSCORE + /* Remove leading underscore at the beginning of the symbol. + * This is to be compatible with the standard librairies. + */ + if (*S_GET_NAME(symbolP) == '_') { + underscore = 1; + S_SET_NAME(symbolP, S_GET_NAME(symbolP) + 1); + } /* strip underscore */ +#endif /* STRIP_UNDERSCORE */ + + if (S_IS_STRING(symbolP)) + SF_SET_STRING(symbolP); + if (!underscore && S_IS_LOCAL(symbolP)) + SF_SET_LOCAL(symbolP); + + return; +} /* obj_symbol_new_hook() */ + +/* stack stuff */ +stack* stack_init(chunk_size, element_size) +unsigned long chunk_size; +unsigned long element_size; +{ + stack* st; + + if ((st = (stack*)malloc(sizeof(stack))) == (stack*)0) + return (stack*)0; + if ((st->data = malloc(chunk_size)) == (char*)0) { + free(st); + return (stack*)0; + } + st->pointer = 0; + st->size = chunk_size; + st->chunk_size = chunk_size; + st->element_size = element_size; + return st; +} /* stack_init() */ + +void stack_delete(st) +stack* st; +{ + free(st->data); + free(st); +} + +char *stack_push(st, element) +stack *st; +char *element; +{ + if (st->pointer + st->element_size >= st->size) { + st->size += st->chunk_size; + if ((st->data = xrealloc(st->data, st->size)) == (char*)0) + return (char*)0; + } + memcpy(st->data + st->pointer, element, st->element_size); + st->pointer += st->element_size; + return st->data + st->pointer; +} /* stack_push() */ + +char* stack_pop(st) +stack* st; +{ + if ((st->pointer -= st->element_size) < 0) { + st->pointer = 0; + return (char*)0; + } + return st->data + st->pointer; +} + +char* stack_top(st) +stack* st; +{ + return st->data + st->pointer - st->element_size; +} + + +/* + * Handle .ln directives. + */ + +static void obj_coff_ln() { + if (def_symbol_in_progress != NULL) { + as_warn(".ln pseudo-op inside .def/.endef: ignored."); + demand_empty_rest_of_line(); + return; + } /* wrong context */ + + c_line_new(obstack_next_free(&frags) - frag_now->fr_literal, + get_absolute_expression(), + frag_now); + + demand_empty_rest_of_line(); + return; +} /* obj_coff_line() */ + +/* + * def() + * + * Handle .def directives. + * + * One might ask : why can't we symbol_new if the symbol does not + * already exist and fill it with debug information. Because of + * the C_EFCN special symbol. It would clobber the value of the + * function symbol before we have a chance to notice that it is + * a C_EFCN. And a second reason is that the code is more clear this + * way. (at least I think it is :-). + * + */ + +#define SKIP_SEMI_COLON() while (*input_line_pointer++ != ';') +#define SKIP_WHITESPACES() while (*input_line_pointer == ' ' || \ + *input_line_pointer == '\t') \ + input_line_pointer++; + +static void obj_coff_def(what) +int what; +{ + char name_end; /* Char after the end of name */ + char *symbol_name; /* Name of the debug symbol */ + char *symbol_name_copy; /* Temporary copy of the name */ + unsigned int symbol_name_length; + /*$char* directiveP;$ */ /* Name of the pseudo opcode */ + /*$char directive[MAX_DIRECTIVE];$ */ /* Backup of the directive */ + /*$char end = 0;$ */ /* If 1, stop parsing */ + + if (def_symbol_in_progress != NULL) { + as_warn(".def pseudo-op used inside of .def/.endef: ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + SKIP_WHITESPACES(); + + def_symbol_in_progress = (symbolS *) obstack_alloc(¬es, sizeof(*def_symbol_in_progress)); + memset(def_symbol_in_progress, '\0', sizeof(*def_symbol_in_progress)); + + symbol_name = input_line_pointer; + name_end = get_symbol_end(); + symbol_name_length = strlen(symbol_name); + symbol_name_copy = xmalloc(symbol_name_length + 1); + strcpy(symbol_name_copy, symbol_name); + + /* Initialize the new symbol */ +#ifdef STRIP_UNDERSCORE + S_SET_NAME(def_symbol_in_progress, (*symbol_name_copy == '_' + ? symbol_name_copy + 1 + : symbol_name_copy)); +#else /* STRIP_UNDERSCORE */ + S_SET_NAME(def_symbol_in_progress, symbol_name_copy); +#endif /* STRIP_UNDERSCORE */ + /* free(symbol_name_copy); */ + def_symbol_in_progress->sy_name_offset = ~0; + def_symbol_in_progress->sy_number = ~0; + def_symbol_in_progress->sy_frag = &zero_address_frag; + + if (S_IS_STRING(def_symbol_in_progress)) { + SF_SET_STRING(def_symbol_in_progress); + } /* "long" name */ + + *input_line_pointer = name_end; + + demand_empty_rest_of_line(); + return; +} /* obj_coff_def() */ + +unsigned int dim_index; +static void obj_coff_endef() { + symbolS *symbolP; + /* DIM BUG FIX sac@cygnus.com */ + dim_index =0; + if (def_symbol_in_progress == NULL) { + as_warn(".endef pseudo-op used outside of .def/.endef: ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + /* Set the section number according to storage class. */ + switch (S_GET_STORAGE_CLASS(def_symbol_in_progress)) { + case C_STRTAG: + case C_ENTAG: + case C_UNTAG: + SF_SET_TAG(def_symbol_in_progress); + /* intentional fallthrough */ + case C_FILE: + case C_TPDEF: + SF_SET_DEBUG(def_symbol_in_progress); + S_SET_SEGMENT(def_symbol_in_progress, SEG_DEBUG); + break; + + case C_EFCN: + SF_SET_LOCAL(def_symbol_in_progress); /* Do not emit this symbol. */ + /* intentional fallthrough */ + case C_BLOCK: + SF_SET_PROCESS(def_symbol_in_progress); /* Will need processing before writing */ + /* intentional fallthrough */ + case C_FCN: + S_SET_SEGMENT(def_symbol_in_progress, SEG_TEXT); + + if (def_symbol_in_progress->sy_symbol.ost_entry.n_name[1] == 'b') { /* .bf */ + if (function_lineoff < 0) { + fprintf(stderr, "`.bf' symbol without preceding function\n"); + } /* missing function symbol */ + SA_GET_SYM_LNNOPTR(def_symbol_in_progress) = function_lineoff; + SF_SET_PROCESS(def_symbol_in_progress); /* Will need relocating */ + function_lineoff = -1; + } + break; + +#ifdef C_AUTOARG + case C_AUTOARG: +#endif /* C_AUTOARG */ + case C_AUTO: + case C_REG: + case C_MOS: + case C_MOE: + case C_MOU: + case C_ARG: + case C_REGPARM: + case C_FIELD: + case C_EOS: + SF_SET_DEBUG(def_symbol_in_progress); + S_SET_SEGMENT(def_symbol_in_progress, SEG_ABSOLUTE); + break; + + case C_EXT: + case C_STAT: + case C_LABEL: + /* Valid but set somewhere else (s_comm, s_lcomm, colon) */ + break; + + case C_USTATIC: + case C_EXTDEF: + case C_ULABEL: + as_warn("unexpected storage class %d", S_GET_STORAGE_CLASS(def_symbol_in_progress)); + break; + } /* switch on storage class */ + + /* Now that we have built a debug symbol, try to + find if we should merge with an existing symbol + or not. If a symbol is C_EFCN or SEG_ABSOLUTE or + untagged SEG_DEBUG it never merges. */ + + /* Two cases for functions. Either debug followed + by definition or definition followed by debug. + For definition first, we will merge the debug + symbol into the definition. For debug first, the + lineno entry MUST point to the definition + function or else it will point off into space + when obj_crawl_symbol_chain() merges the debug + symbol into the real symbol. Therefor, let's + presume the debug symbol is a real function + reference. */ + + /* FIXME-SOON If for some reason the definition + label/symbol is never seen, this will probably + leave an undefined symbol at link time. */ + + if (S_GET_STORAGE_CLASS(def_symbol_in_progress) == C_EFCN + || (S_GET_SEGMENT(def_symbol_in_progress) == SEG_DEBUG + && !SF_GET_TAG(def_symbol_in_progress)) + || S_GET_SEGMENT(def_symbol_in_progress) == SEG_ABSOLUTE + || (symbolP = symbol_find_base(S_GET_NAME(def_symbol_in_progress), DO_NOT_STRIP)) == NULL) { + + symbol_append(def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP); + + } else { + /* This symbol already exists, merge the + newly created symbol into the old one. + This is not mandatory. The linker can + handle duplicate symbols correctly. But I + guess that it save a *lot* of space if + the assembly file defines a lot of + symbols. [loic] */ + + /* The debug entry (def_symbol_in_progress) + is merged into the previous definition. */ + + c_symbol_merge(def_symbol_in_progress, symbolP); + /* FIXME-SOON Should *def_symbol_in_progress be free'd? xoxorich. */ + def_symbol_in_progress = symbolP; + + if (SF_GET_FUNCTION(def_symbol_in_progress) + || SF_GET_TAG(def_symbol_in_progress)) { + /* For functions, and tags, the symbol *must* be where the debug symbol + appears. Move the existing symbol to the current place. */ + /* If it already is at the end of the symbol list, do nothing */ + if (def_symbol_in_progress != symbol_lastP) { + symbol_remove(def_symbol_in_progress, &symbol_rootP, &symbol_lastP); + symbol_append(def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP); + } /* if not already in place */ + } /* if function */ + } /* normal or mergable */ + + if (SF_GET_TAG(def_symbol_in_progress) + && symbol_find_base(S_GET_NAME(def_symbol_in_progress), DO_NOT_STRIP) == NULL) { + tag_insert(S_GET_NAME(def_symbol_in_progress), def_symbol_in_progress); + } /* If symbol is a {structure,union} tag, associate symbol to its name. */ + + if (SF_GET_FUNCTION(def_symbol_in_progress)) { + know(sizeof(def_symbol_in_progress) <= sizeof(long)); + function_lineoff = c_line_new((long) def_symbol_in_progress, 0, &zero_address_frag); + SF_SET_PROCESS(def_symbol_in_progress); + + if (symbolP == NULL) { + /* That is, if this is the first + time we've seen the function... */ + symbol_table_insert(def_symbol_in_progress); + } /* definition follows debug */ + } /* Create the line number entry pointing to the function being defined */ + + def_symbol_in_progress = NULL; + demand_empty_rest_of_line(); + return; +} /* obj_coff_endef() */ + +static void obj_coff_dim() +{ + register int dim_index; + + if (def_symbol_in_progress == NULL) { + as_warn(".dim pseudo-op used outside of .def/.endef: ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1); + + for (dim_index = 0; dim_index < DIMNUM; dim_index++) { + SKIP_WHITESPACES(); + SA_SET_SYM_DIMEN(def_symbol_in_progress, dim_index, get_absolute_expression()); + + switch (*input_line_pointer) { + + case ',': + input_line_pointer++; + break; + + default: + as_warn("badly formed .dim directive ignored"); + /* intentional fallthrough */ + case '\n': + case ';': + dim_index = DIMNUM; + break; + } /* switch on following character */ + } /* for each dimension */ + + demand_empty_rest_of_line(); + return; +} /* obj_coff_dim() */ + +static void obj_coff_line() { + if (def_symbol_in_progress == NULL) { + obj_coff_ln(); + return; + } /* if it looks like a stabs style line */ + + S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1); + SA_SET_SYM_LNNO(def_symbol_in_progress, get_absolute_expression()); + + demand_empty_rest_of_line(); + return; +} /* obj_coff_line() */ + +static void obj_coff_size() { + if (def_symbol_in_progress == NULL) { + as_warn(".size pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1); + SA_SET_SYM_SIZE(def_symbol_in_progress, get_absolute_expression()); + demand_empty_rest_of_line(); + return; +} /* obj_coff_size() */ + +static void obj_coff_scl() { + if (def_symbol_in_progress == NULL) { + as_warn(".scl pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + S_SET_STORAGE_CLASS(def_symbol_in_progress, get_absolute_expression()); + demand_empty_rest_of_line(); + return; +} /* obj_coff_scl() */ + +static void obj_coff_tag() { + char *symbol_name; + char name_end; + + if (def_symbol_in_progress == NULL) { + as_warn(".tag pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1); + symbol_name = input_line_pointer; + name_end = get_symbol_end(); + + /* Assume that the symbol referred to by .tag is always defined. */ + /* This was a bad assumption. I've added find_or_make. xoxorich. */ + SA_SET_SYM_TAGNDX(def_symbol_in_progress, (long) tag_find_or_make(symbol_name)); + if (SA_GET_SYM_TAGNDX(def_symbol_in_progress) == 0L) { + as_warn("tag not found for .tag %s", symbol_name); + } /* not defined */ + + SF_SET_TAGGED(def_symbol_in_progress); + *input_line_pointer = name_end; + + demand_empty_rest_of_line(); + return; +} /* obj_coff_tag() */ + +static void obj_coff_type() { + if (def_symbol_in_progress == NULL) { + as_warn(".type pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + S_SET_DATA_TYPE(def_symbol_in_progress, get_absolute_expression()); + + if (ISFCN(S_GET_DATA_TYPE(def_symbol_in_progress)) && + S_GET_STORAGE_CLASS(def_symbol_in_progress) != C_TPDEF) { + SF_SET_FUNCTION(def_symbol_in_progress); + } /* is a function */ + + demand_empty_rest_of_line(); + return; +} /* obj_coff_type() */ + +static void obj_coff_val() { + if (def_symbol_in_progress == NULL) { + as_warn(".val pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + if (is_name_beginner(*input_line_pointer)) { + char *symbol_name = input_line_pointer; + char name_end = get_symbol_end(); + + if (!strcmp(symbol_name, ".")) { + def_symbol_in_progress->sy_frag = frag_now; + S_SET_VALUE(def_symbol_in_progress, obstack_next_free(&frags) - frag_now->fr_literal); + /* If the .val is != from the .def (e.g. statics) */ + } else if (strcmp(S_GET_NAME(def_symbol_in_progress), symbol_name)) { + def_symbol_in_progress->sy_forward = symbol_find_or_make(symbol_name); + + /* If the segment is undefined when the forward + reference is solved, then copy the segment id + from the forward symbol. */ + SF_SET_GET_SEGMENT(def_symbol_in_progress); + } + /* Otherwise, it is the name of a non debug symbol and its value will be calculated later. */ + *input_line_pointer = name_end; + } else { + S_SET_VALUE(def_symbol_in_progress, get_absolute_expression()); + } /* if symbol based */ + + demand_empty_rest_of_line(); + return; +} /* obj_coff_val() */ + +/* + * Maintain a list of the tagnames of the structres. + */ + +static void tag_init() { + tag_hash = hash_new(); + return ; +} /* tag_init() */ + +static void tag_insert(name, symbolP) +char *name; +symbolS *symbolP; +{ + register char * error_string; + + if (*(error_string = hash_jam(tag_hash, name, (char *)symbolP))) { + as_fatal("Inserting \"%s\" into structure table failed: %s", + name, error_string); + } + return ; +} /* tag_insert() */ + +static symbolS *tag_find_or_make(name) +char *name; +{ + symbolS *symbolP; + + if ((symbolP = tag_find(name)) == NULL) { + symbolP = symbol_new(name, + SEG_UNKNOWN, + 0, + &zero_address_frag); + + tag_insert(S_GET_NAME(symbolP), symbolP); + symbol_table_insert(symbolP); + } /* not found */ + + return(symbolP); +} /* tag_find_or_make() */ + +static symbolS *tag_find(name) +char *name; +{ +#ifdef STRIP_UNDERSCORE + if (*name == '_') name++; +#endif /* STRIP_UNDERSCORE */ + return((symbolS*)hash_find(tag_hash, name)); +} /* tag_find() */ + +void obj_read_begin_hook() { + /* These had better be the same. Usually 18 bytes. */ +#ifndef BFD_HEADERS + know(sizeof(SYMENT) == sizeof(AUXENT)); + know(SYMESZ == AUXESZ); +#endif + tag_init(); + + return; +} /* obj_read_begin_hook() */ + +void obj_crawl_symbol_chain(headers) +object_headers *headers; +{ + int symbol_number = 0; + lineno *lineP; + symbolS *last_functionP = NULL; + symbolS *last_tagP; + symbolS *symbolP; + symbolS *symbol_externP = NULL; + symbolS *symbol_extern_lastP = NULL; + + /* Initialize the stack used to keep track of the matching .bb .be */ + stack* block_stack = stack_init(512, sizeof(symbolS*)); + + /* JF deal with forward references first... */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + + if (symbolP->sy_forward) { + S_SET_VALUE(symbolP, (S_GET_VALUE(symbolP) + + S_GET_VALUE(symbolP->sy_forward) + + symbolP->sy_forward->sy_frag->fr_address)); + + if ( +#ifndef TE_I386AIX + SF_GET_GET_SEGMENT(symbolP) +#else + SF_GET_GET_SEGMENT(symbolP) + && S_GET_SEGMENT(symbolP) == SEG_UNKNOWN +#endif /* TE_I386AIX */ + ) { + S_SET_SEGMENT(symbolP, S_GET_SEGMENT(symbolP->sy_forward)); + } /* forward segment also */ + + symbolP->sy_forward=0; + } /* if it has a forward reference */ + } /* walk the symbol chain */ + + tc_crawl_symbol_chain(headers); + + /* The symbol list should be ordered according to the following sequence + * order : + * . .file symbol + * . debug entries for functions + * . fake symbols for .text .data and .bss + * . defined symbols + * . undefined symbols + * But this is not mandatory. The only important point is to put the + * undefined symbols at the end of the list. + */ + + if (symbol_rootP == NULL + || S_GET_STORAGE_CLASS(symbol_rootP) != C_FILE) { + know(!previous_file_symbol); + c_dot_file_symbol("fake"); + } /* Is there a .file symbol ? If not insert one at the beginning. */ + + /* + * Build up static symbols for .text, .data and .bss + */ + dot_text_symbol = (symbolS*) + c_section_symbol(".text", + 0, + H_GET_TEXT_SIZE(headers), + 0/*text_relocation_number */, + 0/*text_lineno_number */); +#ifdef TE_I386AIX + symbol_remove(dot_text_symbol, &symbol_rootP, &symbol_lastP); + symbol_append(dot_text_symbol, previous_file_symbol, + &symbol_rootP, &symbol_lastP); +#endif /* TE_I386AIX */ + + dot_data_symbol = (symbolS*) + c_section_symbol(".data", + H_GET_TEXT_SIZE(headers), + H_GET_DATA_SIZE(headers), + 0/*data_relocation_number */, + 0); /* There are no data lineno entries */ +#ifdef TE_I386AIX + symbol_remove(dot_data_symbol, &symbol_rootP, &symbol_lastP); + symbol_append(dot_data_symbol, dot_text_symbol, + &symbol_rootP, &symbol_lastP); +#endif /* TE_I386AIX */ + + dot_bss_symbol = (symbolS*) + c_section_symbol(".bss", + H_GET_TEXT_SIZE(headers) + H_GET_DATA_SIZE(headers), + H_GET_BSS_SIZE(headers), + 0, /* No relocation for a bss section. */ + 0); /* There are no bss lineno entries */ +#ifdef TE_I386AIX + symbol_remove(dot_bss_symbol, &symbol_rootP, &symbol_lastP); + symbol_append(dot_bss_symbol, dot_data_symbol, + &symbol_rootP, &symbol_lastP); +#endif /* TE_I386AIX */ + +#if defined(DEBUG) + verify_symbol_chain(symbol_rootP, symbol_lastP); +#endif /* DEBUG */ + + /* Three traversals of symbol chains here. The + first traversal yanks externals into a temporary + chain, removing the externals from the global + chain, numbers symbols, and does some other guck. + The second traversal is on the temporary chain of + externals and just appends them to the global + chain again, numbering them as we go. The third + traversal patches pointers to symbols (using sym + indexes). The last traversal was once done as + part of the first pass, but that fails when a + reference preceeds a definition as the definition + has no number at the time we process the + reference. */ + + /* Note that symbolP will be NULL at the end of a loop + if an external was at the beginning of the list (it + gets moved off the list). Hence the weird check in + the loop control. + */ + for (symbolP = symbol_rootP; + symbolP; + symbolP = symbolP ? symbol_next(symbolP) : symbol_rootP) { + if (!SF_GET_DEBUG(symbolP)) { + /* Debug symbols do not need all this rubbish */ + symbolS* real_symbolP; + + /* L* and C_EFCN symbols never merge. */ + if (!SF_GET_LOCAL(symbolP) + && (real_symbolP = symbol_find_base(S_GET_NAME(symbolP), DO_NOT_STRIP)) + && real_symbolP != symbolP) { + /* FIXME-SOON: where do dups come from? Maybe tag references before definitions? xoxorich. */ + /* Move the debug data from the debug symbol to the + real symbol. Do NOT do the oposite (i.e. move from + real symbol to debug symbol and remove real symbol from the + list.) Because some pointers refer to the real symbol + whereas no pointers refer to the debug symbol. */ + c_symbol_merge(symbolP, real_symbolP); + /* Replace the current symbol by the real one */ + /* The symbols will never be the last or the first + because : 1st symbol is .file and 3 last symbols are + .text, .data, .bss */ + symbol_remove(real_symbolP, &symbol_rootP, &symbol_lastP); + symbol_insert(real_symbolP, symbolP, &symbol_rootP, &symbol_lastP); + symbol_remove(symbolP, &symbol_rootP, &symbol_lastP); + symbolP = real_symbolP; + } /* if not local but dup'd */ + + if (flagseen['R'] && (S_GET_SEGMENT(symbolP) == SEG_DATA)) { + S_SET_SEGMENT(symbolP, SEG_TEXT); + } /* push data into text */ + + S_SET_VALUE(symbolP, S_GET_VALUE(symbolP) + symbolP->sy_frag->fr_address); + + if (!S_IS_DEFINED(symbolP) && !SF_GET_LOCAL(symbolP)) { + S_SET_EXTERNAL(symbolP); + } else if (S_GET_STORAGE_CLASS(symbolP) == C_NULL) { + if (S_GET_SEGMENT(symbolP) == SEG_TEXT){ + S_SET_STORAGE_CLASS(symbolP, C_LABEL); + } else { + S_SET_STORAGE_CLASS(symbolP, C_STAT); + } + } /* no storage class yet */ + + /* Mainly to speed up if not -g */ + if (SF_GET_PROCESS(symbolP)) { + /* Handle the nested blocks auxiliary info. */ + if (S_GET_STORAGE_CLASS(symbolP) == C_BLOCK) { + if (!strcmp(S_GET_NAME(symbolP), ".bb")) + stack_push(block_stack, (char *) &symbolP); + else { /* .eb */ + register symbolS* begin_symbolP; + begin_symbolP = *(symbolS**)stack_pop(block_stack); + if (begin_symbolP == (symbolS*)0) + as_warn("mismatched .eb"); + else + SA_SET_SYM_ENDNDX(begin_symbolP, symbol_number+2); + } + } + /* If we are able to identify the type of a function, and we + are out of a function (last_functionP == 0) then, the + function symbol will be associated with an auxiliary + entry. */ + if (last_functionP == (symbolS*)0 && + SF_GET_FUNCTION(symbolP)) { + last_functionP = symbolP; + + if (S_GET_NUMBER_AUXILIARY(symbolP) < 1) { + S_SET_NUMBER_AUXILIARY(symbolP, 1); + } /* make it at least 1 */ + + /* Clobber possible stale .dim information. */ + memset(symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen, + '\0', sizeof(symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen)); + } + /* The C_FCN doesn't need any additional information. + I don't even know if this is needed for sdb. But the + standard assembler generates it, so... + */ + if (S_GET_STORAGE_CLASS(symbolP) == C_EFCN) { + if (last_functionP == (symbolS*)0) + as_fatal("C_EFCN symbol out of scope"); + SA_SET_SYM_FSIZE(last_functionP, + (long)(S_GET_VALUE(symbolP) - + S_GET_VALUE(last_functionP))); + SA_SET_SYM_ENDNDX(last_functionP, symbol_number); + last_functionP = (symbolS*)0; + } + } + } else if (SF_GET_TAG(symbolP)) { + /* First descriptor of a structure must point to + the first slot after the structure description. */ + last_tagP = symbolP; + + } else if (S_GET_STORAGE_CLASS(symbolP) == C_EOS) { + /* +2 take in account the current symbol */ + SA_SET_SYM_ENDNDX(last_tagP, symbol_number + 2); + } else if (S_GET_STORAGE_CLASS(symbolP) == C_FILE) { + if (S_GET_VALUE(symbolP)) { + S_SET_VALUE((symbolS *) S_GET_VALUE(symbolP), symbol_number); + S_SET_VALUE(symbolP, 0); + } /* no one points at the first .file symbol */ + } /* if debug or tag or eos or file */ + + /* We must put the external symbols apart. The loader + does not bomb if we do not. But the references in + the endndx field for a .bb symbol are not corrected + if an external symbol is removed between .bb and .be. + I.e in the following case : + [20] .bb endndx = 22 + [21] foo external + [22] .be + ld will move the symbol 21 to the end of the list but + endndx will still be 22 instead of 21. */ + + + if (SF_GET_LOCAL(symbolP)) { + /* remove C_EFCN and LOCAL (L...) symbols */ + /* next pointer remains valid */ + symbol_remove(symbolP, &symbol_rootP, &symbol_lastP); + + } else if ( +#ifdef TE_I386AIX + S_GET_STORAGE_CLASS(symbolP) == C_EXT && !SF_GET_FUNCTION(symbolP) +#else /* not TE_I386AIX */ + !S_IS_DEFINED(symbolP) && !S_IS_DEBUG(symbolP) && !SF_GET_STATICS(symbolP) +#endif /* not TE_I386AIX */ + ) { + /* if external, Remove from the list */ + symbolS *hold = symbol_previous(symbolP); + + symbol_remove(symbolP, &symbol_rootP, &symbol_lastP); + symbol_clear_list_pointers(symbolP); + symbol_append(symbolP, symbol_extern_lastP, &symbol_externP, &symbol_extern_lastP); + symbolP = hold; + } else { + if (SF_GET_STRING(symbolP)) { + symbolP->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(symbolP)) + 1; + } else { + symbolP->sy_name_offset = 0; + } /* fix "long" names */ + + symbolP->sy_number = symbol_number; + symbol_number += 1 + S_GET_NUMBER_AUXILIARY(symbolP); + } /* if local symbol */ + } /* traverse the symbol list */ + + for (symbolP = symbol_externP; symbol_externP;) { + symbolS *tmp = symbol_externP; + + /* append */ + symbol_remove(tmp, &symbol_externP, &symbol_extern_lastP); + symbol_append(tmp, symbol_lastP, &symbol_rootP, &symbol_lastP); + + /* and process */ + if (SF_GET_STRING(tmp)) { + tmp->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(tmp)) + 1; + } else { + tmp->sy_name_offset = 0; + } /* fix "long" names */ + + tmp->sy_number = symbol_number; + symbol_number += 1 + S_GET_NUMBER_AUXILIARY(tmp); + } /* append the entire extern chain */ + + /* When a tag reference preceeds the tag definition, + the definition will not have a number at the time + we process the reference during the first + traversal. Thus, a second traversal. */ + + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + if (SF_GET_TAGGED(symbolP)) { + SA_SET_SYM_TAGNDX(symbolP, ((symbolS*) SA_GET_SYM_TAGNDX(symbolP))->sy_number); + } /* If the symbol has a tagndx entry, resolve it */ + } /* second traversal */ + + know(symbol_externP == NULL); + know(symbol_extern_lastP == NULL); + + /* FIXME-SOMEDAY I'm counting line no's here so we know what to put in the section + headers, and I'm resolving the addresses since I'm not sure how to + do it later. I am NOT resolving the linno's representing functions. + Their symbols need a fileptr pointing to this linno when emitted. + Thus, I resolve them on emit. xoxorich. */ + + for (lineP = lineno_rootP; lineP; lineP = lineP->next) { + if (lineP->line.l_lnno > 0) { + lineP->line.l_addr.l_paddr += ((fragS*)lineP->frag)->fr_address; + } else { + ; + } + text_lineno_number++; + } /* for each line number */ + + H_SET_SYMBOL_TABLE_SIZE(headers, symbol_number); + + return; +} /* obj_crawl_symbol_chain() */ + +/* + * Find strings by crawling along symbol table chain. + */ + +void obj_emit_strings(where) +char **where; +{ + symbolS *symbolP; + +#ifdef CROSS_COMPILE + /* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */ + md_number_to_chars(*where, string_byte_count, sizeof(string_byte_count)); + *where += sizeof(string_byte_count); +#else /* CROSS_COMPILE */ + append(where, (char *) &string_byte_count, (unsigned long) sizeof(string_byte_count)); +#endif /* CROSS_COMPILE */ + + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + if (SF_GET_STRING(symbolP)) { + append(where, S_GET_NAME(symbolP), (unsigned long)(strlen(S_GET_NAME(symbolP)) + 1)); + } /* if it has a string */ + } /* walk the symbol chain */ + + return; +} /* obj_emit_strings() */ + +void obj_pre_write_hook(headers) +object_headers *headers; +{ + register int text_relocation_number = 0; + register int data_relocation_number = 0; + register fixS *fixP; + + H_SET_MAGIC_NUMBER(headers, FILE_HEADER_MAGIC); + H_SET_ENTRY_POINT(headers, 0); + + /* FIXME-SOMEDAY this should be done at + fixup_segment time but I'm going to wait until I + do multiple segments. xoxorich. */ + /* Count the number of relocation entries for text and data */ + for (fixP = text_fix_root; fixP; fixP = fixP->fx_next) { + if (fixP->fx_addsy) { + ++text_relocation_number; +#ifdef TC_I960 + /* two relocs per callj under coff. */ + if (fixP->fx_callj) { + ++text_relocation_number; + } /* if callj and not already fixed. */ +#endif /* TC_I960 */ +#ifdef TC_A29K + /* Count 2 for a constH */ + if (fixP->fx_r_type == RELOC_CONSTH) { + ++text_relocation_number; + } +#endif + + } /* if not yet fixed */ + } /* for each fix */ + + SA_SET_SCN_NRELOC(dot_text_symbol, text_relocation_number); + /* Assign the number of line number entries for the text section */ + SA_SET_SCN_NLINNO(dot_text_symbol, text_lineno_number); + /* Assign the size of the section */ + SA_SET_SCN_SCNLEN(dot_text_symbol, H_GET_TEXT_SIZE(headers)); + + for (fixP = data_fix_root; fixP; fixP = fixP->fx_next) { + if (fixP->fx_addsy) { + ++data_relocation_number; + } /* if still relocatable */ +#ifdef TC_A29K + /* Count 2 for a constH */ + if (fixP->fx_r_type == RELOC_CONSTH) { + ++data_relocation_number; + } +#endif + + } /* for each fix */ + + + SA_SET_SCN_NRELOC(dot_data_symbol, data_relocation_number); + /* Assign the size of the section */ + SA_SET_SCN_SCNLEN(dot_data_symbol, H_GET_DATA_SIZE(headers)); + + /* Assign the size of the section */ + SA_SET_SCN_SCNLEN(dot_bss_symbol, H_GET_BSS_SIZE(headers)); + + /* pre write hook can add relocs (for 960 and 29k coff) so */ + headers->relocation_size = text_relocation_number * RELSZ + + data_relocation_number *RELSZ; + + + + /* Fill in extra coff fields */ + + /* Initialize general line number information. */ + H_SET_LINENO_SIZE(headers, text_lineno_number * LINESZ); + + /* filehdr */ + H_SET_FILE_MAGIC_NUMBER(headers, FILE_HEADER_MAGIC); + H_SET_NUMBER_OF_SECTIONS(headers, 3); /* text+data+bss */ +#ifndef OBJ_COFF_OMIT_TIMESTAMP + H_SET_TIME_STAMP(headers, (long)time((long*)0)); +#else /* OBJ_COFF_OMIT_TIMESTAMP */ + H_SET_TIME_STAMP(headers, 0); +#endif /* OBJ_COFF_OMIT_TIMESTAMP */ + H_SET_SYMBOL_TABLE_POINTER(headers, H_GET_SYMBOL_TABLE_FILE_OFFSET(headers)); +#if 0 + printf("FILHSZ %x\n", FILHSZ); + printf("OBJ_COFF_AOUTHDRSZ %x\n", OBJ_COFF_AOUTHDRSZ); + printf("section headers %x\n", H_GET_NUMBER_OF_SECTIONS(headers) * SCNHSZ); + printf("get text size %x\n", H_GET_TEXT_SIZE(headers)); + printf("get data size %x\n", H_GET_DATA_SIZE(headers)); + printf("get relocation size %x\n", H_GET_RELOCATION_SIZE(headers)); + printf("get lineno size %x\n", H_GET_LINENO_SIZE(headers)); +#endif + /* symbol table size allready set */ + H_SET_SIZEOF_OPTIONAL_HEADER(headers, OBJ_COFF_AOUTHDRSZ); + + /* do not added the F_RELFLG for the standard COFF. + * The AIX linker complain on file with relocation info striped flag. + */ +#ifdef KEEP_RELOC_INFO + H_SET_FLAGS(headers, (text_lineno_number == 0 ? F_LNNO : 0) + | BYTE_ORDERING); +#else + H_SET_FLAGS(headers, (text_lineno_number == 0 ? F_LNNO : 0) + | ((text_relocation_number + data_relocation_number) ? 0 : F_RELFLG) + | BYTE_ORDERING); +#endif + /* aouthdr */ + /* magic number allready set */ + H_SET_VERSION_STAMP(headers, 0); + /* Text, data, bss size; entry point; text_start and data_start are already set */ + + /* Build section headers */ + + c_section_header(&text_section_header, + ".text", + 0, + H_GET_TEXT_SIZE(headers), + H_GET_TEXT_FILE_OFFSET(headers), + (SA_GET_SCN_NRELOC(dot_text_symbol) + ? H_GET_RELOCATION_FILE_OFFSET(headers) + : 0), + (text_lineno_number + ? H_GET_LINENO_FILE_OFFSET(headers) + : 0), + SA_GET_SCN_NRELOC(dot_text_symbol), + text_lineno_number, + section_alignment[(int) SEG_TEXT]); + + c_section_header(&data_section_header, + ".data", + H_GET_TEXT_SIZE(headers), + H_GET_DATA_SIZE(headers), + (H_GET_DATA_SIZE(headers) + ? H_GET_DATA_FILE_OFFSET(headers) + : 0), + (SA_GET_SCN_NRELOC(dot_data_symbol) + ? (H_GET_RELOCATION_FILE_OFFSET(headers) + + text_section_header.s_nreloc * RELSZ) + : 0), + 0, /* No line number information */ + SA_GET_SCN_NRELOC(dot_data_symbol), + 0, /* No line number information */ + section_alignment[(int) SEG_DATA]); + + c_section_header(&bss_section_header, + ".bss", + H_GET_TEXT_SIZE(headers) + H_GET_DATA_SIZE(headers), + H_GET_BSS_SIZE(headers), + 0, /* No file offset */ + 0, /* No relocation information */ + 0, /* No line number information */ + 0, /* No relocation information */ + 0, /* No line number information */ + section_alignment[(int) SEG_BSS]); + + return; +} /* obj_pre_write_hook() */ + +/* This is a copy from aout. All I do is neglect to actually build the symbol. */ + +static void obj_coff_stab(what) +int what; +{ + char *string; + expressionS e; + int goof = 0; /* TRUE if we have aborted. */ + int length; + int saved_type = 0; + long longint; + symbolS *symbolP = 0; + + if (what == 's') { + string = demand_copy_C_string(&length); + SKIP_WHITESPACE(); + + if (*input_line_pointer == ',') { + input_line_pointer++; + } else { + as_bad("I need a comma after symbol's name"); + goof = 1; + } /* better be a comma */ + } /* skip the string */ + + /* + * Input_line_pointer->after ','. String->symbol name. + */ + if (!goof) { + if (get_absolute_expression_and_terminator(&longint) != ',') { + as_bad("I want a comma after the n_type expression"); + goof = 1; + input_line_pointer--; /* Backup over a non-',' char. */ + } /* on error */ + } /* no error */ + + if (!goof) { + if (get_absolute_expression_and_terminator(&longint) != ',') { + as_bad("I want a comma after the n_other expression"); + goof = 1; + input_line_pointer--; /* Backup over a non-',' char. */ + } /* on error */ + } /* no error */ + + if (!goof) { + get_absolute_expression(); + + if (what == 's' || what == 'n') { + if (*input_line_pointer != ',') { + as_bad("I want a comma after the n_desc expression"); + goof = 1; + } else { + input_line_pointer++; + } /* on goof */ + } /* not stabd */ + } /* no error */ + + expression(&e); + + if (goof) { + ignore_rest_of_line(); + } else { + demand_empty_rest_of_line(); + } /* on error */ +} /* obj_coff_stab() */ + +#ifdef DEBUG +/* for debugging */ +char *s_get_name(s) +symbolS *s; +{ + return((s == NULL) ? "(NULL)" : S_GET_NAME(s)); +} /* s_get_name() */ + +void symbol_dump() { + symbolS *symbolP; + + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + printf("%3ld: 0x%lx \"%s\" type = %ld, class = %d, segment = %d\n", + symbolP->sy_number, + (unsigned long) symbolP, + S_GET_NAME(symbolP), + (long) S_GET_DATA_TYPE(symbolP), + S_GET_STORAGE_CLASS(symbolP), + (int) S_GET_SEGMENT(symbolP)); + } /* traverse symbols */ + + return; +} /* symbol_dump() */ +#endif /* DEBUG */ + + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-coff.c */ diff --git a/gnu/usr.bin/as/config/obj-coff.h b/gnu/usr.bin/as/config/obj-coff.h new file mode 100644 index 000000000000..9720d5e3729b --- /dev/null +++ b/gnu/usr.bin/as/config/obj-coff.h @@ -0,0 +1,598 @@ +/* coff object file format + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define OBJ_COFF 1 + +#include "targ-cpu.h" + + + +#ifdef BFD_HEADERS +#ifdef TC_A29K +#include "bfd.h" +#include "coff/a29k.h" + +/* This internal_lineno crap is to stop namespace pollution from the bfd internal + coff headerfile. */ + +#define internal_lineno bfd_internal_lineno +#include "coff/internal.h" +#undef internal_lineno +/* + #undef RELOC + #undef SYMENT + #undef AUXENT + #undef LINENO + #undef FILHDR + #undef SCNHDR + #define RELOC struct internal_reloc + #define SYMENT struct internal_syment + #define AUXENT union internal_auxent + #define SCNHDR struct internal_scnhdr + #define LINENO struct bfd_internal_lineno + #define AOUTHDR struct internal_aouthdr + #define FILHDR struct internal_filehdr + #define AOUTHDRSZ sizeof(struct external_aouthdr) + */ +/*#define x_endndx x_endndx.l + #define x_tagndx x_tagndx.l*/ +#define TARGET_FORMAT "coff-a29k-big" +extern bfd *stdoutput; + +#else /* not TC_A29K */ +# ifdef TC_I386 +# include "bfd.h" +# include "coff/i386.h" +# define internal_lineno bfd_internal_lineno +# include "coff/internal.h" +# undef internal_lineno +# define TARGET_FORMAT "coff-i386" +extern bfd *stdoutput; + +#else /* not TC_I386 */ +#error help me +#endif /* not TC_I386 */ + +#endif /* not TC_A29K */ + +#else /* not BFD_HEADERS */ + +#ifdef USE_NATIVE_HEADERS +#include <filehdr.h> +#include <aouthdr.h> +#include <scnhdr.h> +#include <storclass.h> +#include <linenum.h> +#include <syms.h> +#include <reloc.h> +#include <sys/types.h> +#else /* not USE_NATIVE_HEADERS */ +#include "coff.h" +#endif /* not USE_NATIVE_HEADERS */ + +#endif /* not BFD_HEADERS */ + +/* Define some processor dependent values according to the processor we are on. */ +#ifdef TC_M68K + +#define BYTE_ORDERING F_AR32W /* See filehdr.h for more info. */ +#ifndef FILE_HEADER_MAGIC +#define FILE_HEADER_MAGIC MC68MAGIC /* ... */ +#endif /* FILE_HEADER_MAGIC */ + +#elif defined(TC_I386) + +#define BYTE_ORDERING F_AR32WR /* See filehdr.h for more info. */ +#ifndef FILE_HEADER_MAGIC +#define FILE_HEADER_MAGIC I386MAGIC /* ... */ +#endif /* FILE_HEADER_MAGIC */ + +#elif defined(TC_I960) + +#define BYTE_ORDERING F_AR32WR /* See filehdr.h for more info. */ +#ifndef FILE_HEADER_MAGIC +#define FILE_HEADER_MAGIC I960ROMAGIC /* ... */ +#endif /* FILE_HEADER_MAGIC */ + +#elif defined(TC_A29K) + +#define BYTE_ORDERING F_AR32W /* big endian. */ +#ifndef FILE_HEADER_MAGIC +#define FILE_HEADER_MAGIC SIPFBOMAGIC +#endif /* FILE_HEADER_MAGIC */ + +#else +you lose +#endif + +#ifndef OBJ_COFF_MAX_AUXENTRIES +#define OBJ_COFF_MAX_AUXENTRIES 1 +#endif /* OBJ_COFF_MAX_AUXENTRIES */ + + extern const short seg_N_TYPE[]; +extern const segT N_TYPE_seg[]; + +#ifndef BFD_HEADERS + +/* Add these definitions to have a consistent convention for all the + types used in COFF format. */ +#define AOUTHDR struct aouthdr +#define AOUTHDRSZ sizeof(AOUTHDR) +#endif + +/* SYMBOL TABLE */ + +/* targets may also set this */ +#ifndef SYMBOLS_NEED_BACKPOINTERS +#define SYMBOLS_NEED_BACKPOINTERS 1 +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + +/* Symbol table entry data type */ + +typedef struct { +#ifdef BFD_HEADERS + struct internal_syment ost_entry; /* Basic symbol */ + union internal_auxent ost_auxent[OBJ_COFF_MAX_AUXENTRIES]; /* Auxiliary entry. */ +#else + SYMENT ost_entry; /* Basic symbol */ + AUXENT ost_auxent[OBJ_COFF_MAX_AUXENTRIES]; /* Auxiliary entry. */ +#endif + unsigned int ost_flags; /* obj_coff internal use only flags */ +} obj_symbol_type; + +#define DO_NOT_STRIP 0 +#define DO_STRIP 1 + +/* Symbol table macros and constants */ + +/* Possible and usefull section number in symbol table + * The values of TEXT, DATA and BSS may not be portable. + */ + +#define C_TEXT_SECTION ((short)1) +#define C_DATA_SECTION ((short)2) +#define C_BSS_SECTION ((short)3) +#define C_ABS_SECTION N_ABS +#define C_UNDEF_SECTION N_UNDEF +#define C_DEBUG_SECTION N_DEBUG +#define C_NTV_SECTION N_TV +#define C_PTV_SECTION P_TV +#define C_REGISTER_SECTION 4 + +/* + * Macros to extract information from a symbol table entry. + * This syntaxic indirection allows independence regarding a.out or coff. + * The argument (s) of all these macros is a pointer to a symbol table entry. + */ + +/* Predicates */ +/* True if the symbol is external */ +#define S_IS_EXTERNAL(s) ((s)->sy_symbol.ost_entry.n_scnum == C_UNDEF_SECTION) +/* True if symbol has been defined, ie : + section > 0 (DATA, TEXT or BSS) + section == 0 and value > 0 (external bss symbol) */ +#define S_IS_DEFINED(s) ((s)->sy_symbol.ost_entry.n_scnum > C_UNDEF_SECTION || \ + ((s)->sy_symbol.ost_entry.n_scnum == C_UNDEF_SECTION && \ + (s)->sy_symbol.ost_entry.n_value > 0)) +/* True if a debug special symbol entry */ +#define S_IS_DEBUG(s) ((s)->sy_symbol.ost_entry.n_scnum == C_DEBUG_SECTION) +/* True if a symbol is local symbol name */ +/* A symbol name whose name begin with ^A is a gas internal pseudo symbol */ +#define S_IS_LOCAL(s) (S_GET_NAME(s)[0] == '\001' || \ + (s)->sy_symbol.ost_entry.n_scnum == C_REGISTER_SECTION || \ + (S_LOCAL_NAME(s) && !flagseen['L'])) +/* True if a symbol is not defined in this file */ +#define S_IS_EXTERN(s) ((s)->sy_symbol.ost_entry.n_scnum == 0 && (s)->sy_symbol.ost_entry.n_value == 0) +/* + * True if a symbol can be multiply defined (bss symbols have this def + * though it is bad practice) + */ +#define S_IS_COMMON(s) ((s)->sy_symbol.ost_entry.n_scnum == 0 && (s)->sy_symbol.ost_entry.n_value != 0) +/* True if a symbol name is in the string table, i.e. its length is > 8. */ +#define S_IS_STRING(s) (strlen(S_GET_NAME(s)) > 8 ? 1 : 0) + +/* Accessors */ +/* The name of the symbol */ +#define S_GET_NAME(s) ((char*)(s)->sy_symbol.ost_entry.n_offset) +/* The pointer to the string table */ +#define S_GET_OFFSET(s) ((s)->sy_symbol.ost_entry.n_offset) +/* The zeroes if symbol name is longer than 8 chars */ +#define S_GET_ZEROES(s) ((s)->sy_symbol.ost_entry.n_zeroes) +/* The value of the symbol */ +#define S_GET_VALUE(s) ((unsigned) ((s)->sy_symbol.ost_entry.n_value)) +/* The numeric value of the segment */ +#define S_GET_SEGMENT(s) (N_TYPE_seg[(s)->sy_symbol.ost_entry.n_scnum+4]) +/* The data type */ +#define S_GET_DATA_TYPE(s) ((s)->sy_symbol.ost_entry.n_type) +/* The storage class */ +#define S_GET_STORAGE_CLASS(s) ((s)->sy_symbol.ost_entry.n_sclass) +/* The number of auxiliary entries */ +#define S_GET_NUMBER_AUXILIARY(s) ((s)->sy_symbol.ost_entry.n_numaux) + +/* Modifiers */ +/* Set the name of the symbol */ +#define S_SET_NAME(s,v) ((s)->sy_symbol.ost_entry.n_offset = (unsigned long)(v)) +/* Set the offset of the symbol */ +#define S_SET_OFFSET(s,v) ((s)->sy_symbol.ost_entry.n_offset = (v)) +/* The zeroes if symbol name is longer than 8 chars */ +#define S_SET_ZEROES(s,v) ((s)->sy_symbol.ost_entry.n_zeroes = (v)) +/* Set the value of the symbol */ +#define S_SET_VALUE(s,v) ((s)->sy_symbol.ost_entry.n_value = (v)) +/* The numeric value of the segment */ +#define S_SET_SEGMENT(s,v) ((s)->sy_symbol.ost_entry.n_scnum = SEGMENT_TO_SYMBOL_TYPE(v)) +/* The data type */ +#define S_SET_DATA_TYPE(s,v) ((s)->sy_symbol.ost_entry.n_type = (v)) +/* The storage class */ +#define S_SET_STORAGE_CLASS(s,v) ((s)->sy_symbol.ost_entry.n_sclass = (v)) +/* The number of auxiliary entries */ +#define S_SET_NUMBER_AUXILIARY(s,v) ((s)->sy_symbol.ost_entry.n_numaux = (v)) + +/* Additional modifiers */ +/* The symbol is external (does not mean undefined) */ +#define S_SET_EXTERNAL(s) { S_SET_STORAGE_CLASS(s, C_EXT) ; SF_CLEAR_LOCAL(s); } + +/* Auxiliary entry macros. SA_ stands for symbol auxiliary */ +/* Omit the tv related fields */ +/* Accessors */ +#ifdef BFD_HEADERS +#define SA_GET_SYM_TAGNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx.l) +#else +#define SA_GET_SYM_TAGNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx) +#endif +#define SA_GET_SYM_LNNO(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_lnno) +#define SA_GET_SYM_SIZE(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_size) +#define SA_GET_SYM_FSIZE(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_fsize) +#define SA_GET_SYM_LNNOPTR(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr) +#ifdef BFD_HEADERS +#define SA_GET_SYM_ENDNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx.l) +#else +#define SA_GET_SYM_ENDNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx) +#endif +#define SA_GET_SYM_DIMEN(s,i) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen[(i)]) +#define SA_GET_FILE_FNAME(s) ((s)->sy_symbol.ost_auxent[0].x_file.x_fname) +#define SA_GET_SCN_SCNLEN(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_scnlen) +#define SA_GET_SCN_NRELOC(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nreloc) +#define SA_GET_SCN_NLINNO(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nlinno) + +/* Modifiers */ +#ifdef BFD_HEADERS +#define SA_SET_SYM_TAGNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx.l=(v)) +#else +#define SA_SET_SYM_TAGNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx=(v)) +#endif +#define SA_SET_SYM_LNNO(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_lnno=(v)) +#define SA_SET_SYM_SIZE(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_size=(v)) +#define SA_SET_SYM_FSIZE(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_fsize=(v)) +#define SA_SET_SYM_LNNOPTR(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr=(v)) +#ifdef BFD_HEADERS +#define SA_SET_SYM_ENDNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx.l=(v)) +#else +#define SA_SET_SYM_ENDNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx=(v)) +#endif +#define SA_SET_SYM_DIMEN(s,i,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen[(i)]=(v)) +#define SA_SET_FILE_FNAME(s,v) strncpy((s)->sy_symbol.ost_auxent[0].x_file.x_fname,(v),FILNMLEN) +#define SA_SET_SCN_SCNLEN(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_scnlen=(v)) +#define SA_SET_SCN_NRELOC(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nreloc=(v)) +#define SA_SET_SCN_NLINNO(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nlinno=(v)) + +/* + * Internal use only definitions. SF_ stands for symbol flags. + * + * These values can be assigned to sy_symbol.ost_flags field of a symbolS. + * + * You'll break i960 if you shift the SYSPROC bits anywhere else. for + * more on the balname/callname hack, see tc-i960.h. b.out is done + * differently. + */ + +#define SF_I960_MASK (0x000001ff) /* Bits 0-8 are used by the i960 port. */ +#define SF_SYSPROC (0x0000003f) /* bits 0-5 are used to store the sysproc number */ +#define SF_IS_SYSPROC (0x00000040) /* bit 6 marks symbols that are sysprocs */ +#define SF_BALNAME (0x00000080) /* bit 7 marks BALNAME symbols */ +#define SF_CALLNAME (0x00000100) /* bit 8 marks CALLNAME symbols */ + +#define SF_NORMAL_MASK (0x0000ffff) /* bits 12-15 are general purpose. */ + +#define SF_STATICS (0x00001000) /* Mark the .text & all symbols */ +#define SF_DEFINED (0x00002000) /* Symbol is defined in this file */ +#define SF_STRING (0x00004000) /* Symbol name length > 8 */ +#define SF_LOCAL (0x00008000) /* Symbol must not be emitted */ + +#define SF_DEBUG_MASK (0xffff0000) /* bits 16-31 are debug info */ + +#define SF_FUNCTION (0x00010000) /* The symbol is a function */ +#define SF_PROCESS (0x00020000) /* Process symbol before write */ +#define SF_TAGGED (0x00040000) /* Is associated with a tag */ +#define SF_TAG (0x00080000) /* Is a tag */ +#define SF_DEBUG (0x00100000) /* Is in debug or abs section */ +#define SF_GET_SEGMENT (0x00200000) /* Get the section of the forward symbol. */ +/* All other bits are unused. */ + +/* Accessors */ +#define SF_GET(s) ((s)->sy_symbol.ost_flags) +#define SF_GET_NORMAL_FIELD(s) ((s)->sy_symbol.ost_flags & SF_NORMAL_MASK) +#define SF_GET_DEBUG_FIELD(s) ((s)->sy_symbol.ost_flags & SF_DEBUG_MASK) +#define SF_GET_FILE(s) ((s)->sy_symbol.ost_flags & SF_FILE) +#define SF_GET_STATICS(s) ((s)->sy_symbol.ost_flags & SF_STATICS) +#define SF_GET_DEFINED(s) ((s)->sy_symbol.ost_flags & SF_DEFINED) +#define SF_GET_STRING(s) ((s)->sy_symbol.ost_flags & SF_STRING) +#define SF_GET_LOCAL(s) ((s)->sy_symbol.ost_flags & SF_LOCAL) +#define SF_GET_FUNCTION(s) ((s)->sy_symbol.ost_flags & SF_FUNCTION) +#define SF_GET_PROCESS(s) ((s)->sy_symbol.ost_flags & SF_PROCESS) +#define SF_GET_DEBUG(s) ((s)->sy_symbol.ost_flags & SF_DEBUG) +#define SF_GET_TAGGED(s) ((s)->sy_symbol.ost_flags & SF_TAGGED) +#define SF_GET_TAG(s) ((s)->sy_symbol.ost_flags & SF_TAG) +#define SF_GET_GET_SEGMENT(s) ((s)->sy_symbol.ost_flags & SF_GET_SEGMENT) +#define SF_GET_I960(s) ((s)->sy_symbol.ost_flags & SF_I960_MASK) /* used by i960 */ +#define SF_GET_BALNAME(s) ((s)->sy_symbol.ost_flags & SF_BALNAME) /* used by i960 */ +#define SF_GET_CALLNAME(s) ((s)->sy_symbol.ost_flags & SF_CALLNAME) /* used by i960 */ +#define SF_GET_IS_SYSPROC(s) ((s)->sy_symbol.ost_flags & SF_IS_SYSPROC) /* used by i960 */ +#define SF_GET_SYSPROC(s) ((s)->sy_symbol.ost_flags & SF_SYSPROC) /* used by i960 */ + +/* Modifiers */ +#define SF_SET(s,v) ((s)->sy_symbol.ost_flags = (v)) +#define SF_SET_NORMAL_FIELD(s,v)((s)->sy_symbol.ost_flags |= ((v) & SF_NORMAL_MASK)) +#define SF_SET_DEBUG_FIELD(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_DEBUG_MASK)) +#define SF_SET_FILE(s) ((s)->sy_symbol.ost_flags |= SF_FILE) +#define SF_SET_STATICS(s) ((s)->sy_symbol.ost_flags |= SF_STATICS) +#define SF_SET_DEFINED(s) ((s)->sy_symbol.ost_flags |= SF_DEFINED) +#define SF_SET_STRING(s) ((s)->sy_symbol.ost_flags |= SF_STRING) +#define SF_SET_LOCAL(s) ((s)->sy_symbol.ost_flags |= SF_LOCAL) +#define SF_CLEAR_LOCAL(s) ((s)->sy_symbol.ost_flags &= ~SF_LOCAL) +#define SF_SET_FUNCTION(s) ((s)->sy_symbol.ost_flags |= SF_FUNCTION) +#define SF_SET_PROCESS(s) ((s)->sy_symbol.ost_flags |= SF_PROCESS) +#define SF_SET_DEBUG(s) ((s)->sy_symbol.ost_flags |= SF_DEBUG) +#define SF_SET_TAGGED(s) ((s)->sy_symbol.ost_flags |= SF_TAGGED) +#define SF_SET_TAG(s) ((s)->sy_symbol.ost_flags |= SF_TAG) +#define SF_SET_GET_SEGMENT(s) ((s)->sy_symbol.ost_flags |= SF_GET_SEGMENT) +#define SF_SET_I960(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_I960_MASK)) /* used by i960 */ +#define SF_SET_BALNAME(s) ((s)->sy_symbol.ost_flags |= SF_BALNAME) /* used by i960 */ +#define SF_SET_CALLNAME(s) ((s)->sy_symbol.ost_flags |= SF_CALLNAME) /* used by i960 */ +#define SF_SET_IS_SYSPROC(s) ((s)->sy_symbol.ost_flags |= SF_IS_SYSPROC) /* used by i960 */ +#define SF_SET_SYSPROC(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_SYSPROC)) /* used by i960 */ + +/* File header macro and type definition */ + +/* + * File position calculators. Beware to use them when all the + * appropriate fields are set in the header. + */ + +#ifdef OBJ_COFF_OMIT_OPTIONAL_HEADER +#define OBJ_COFF_AOUTHDRSZ (0) +#else +#define OBJ_COFF_AOUTHDRSZ (AOUTHDRSZ) +#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */ + +#define H_GET_FILE_SIZE(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ + H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h) + \ + H_GET_SYMBOL_TABLE_SIZE(h) + \ + (h)->string_table_size) +#define H_GET_TEXT_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ) +#define H_GET_DATA_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h)) +#define H_GET_BSS_FILE_OFFSET(h) 0 +#define H_GET_RELOCATION_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h)) +#define H_GET_LINENO_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ + H_GET_RELOCATION_SIZE(h)) +#define H_GET_SYMBOL_TABLE_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ + H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h)) + +/* Accessors */ +/* aouthdr */ +#define H_GET_MAGIC_NUMBER(h) ((h)->aouthdr.magic) +#define H_GET_VERSION_STAMP(h) ((h)->aouthdr.vstamp) +#define H_GET_TEXT_SIZE(h) ((h)->aouthdr.tsize) +#define H_GET_DATA_SIZE(h) ((h)->aouthdr.dsize) +#define H_GET_BSS_SIZE(h) ((h)->aouthdr.bsize) +#define H_GET_ENTRY_POINT(h) ((h)->aouthdr.entry) +#define H_GET_TEXT_START(h) ((h)->aouthdr.text_start) +#define H_GET_DATA_START(h) ((h)->aouthdr.data_start) +/* filehdr */ +#define H_GET_FILE_MAGIC_NUMBER(h) ((h)->filehdr.f_magic) +#define H_GET_NUMBER_OF_SECTIONS(h) ((h)->filehdr.f_nscns) +#define H_GET_TIME_STAMP(h) ((h)->filehdr.f_timdat) +#define H_GET_SYMBOL_TABLE_POINTER(h) ((h)->filehdr.f_symptr) +#define H_GET_SYMBOL_COUNT(h) ((h)->filehdr.f_nsyms) +#define H_GET_SYMBOL_TABLE_SIZE(h) (H_GET_SYMBOL_COUNT(h) * SYMESZ) +#define H_GET_SIZEOF_OPTIONAL_HEADER(h) ((h)->filehdr.f_opthdr) +#define H_GET_FLAGS(h) ((h)->filehdr.f_flags) +/* Extra fields to achieve bsd a.out compatibility and for convenience */ +#define H_GET_RELOCATION_SIZE(h) ((h)->relocation_size) +#define H_GET_STRING_SIZE(h) ((h)->string_table_size) +#define H_GET_LINENO_SIZE(h) ((h)->lineno_size) + +#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER +#define H_GET_HEADER_SIZE(h) (sizeof(FILHDR) \ + + sizeof(AOUTHDR)\ + + (H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ)) +#else /* OBJ_COFF_OMIT_OPTIONAL_HEADER */ +#define H_GET_HEADER_SIZE(h) (sizeof(FILHDR) \ + + (H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ)) +#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */ + +#define H_GET_TEXT_RELOCATION_SIZE(h) (text_section_header.s_nreloc * RELSZ) +#define H_GET_DATA_RELOCATION_SIZE(h) (data_section_header.s_nreloc * RELSZ) + +/* Modifiers */ +/* aouthdr */ +#define H_SET_MAGIC_NUMBER(h,v) ((h)->aouthdr.magic = (v)) +#define H_SET_VERSION_STAMP(h,v) ((h)->aouthdr.vstamp = (v)) +#define H_SET_TEXT_SIZE(h,v) ((h)->aouthdr.tsize = (v)) +#define H_SET_DATA_SIZE(h,v) ((h)->aouthdr.dsize = (v)) +#define H_SET_BSS_SIZE(h,v) ((h)->aouthdr.bsize = (v)) +#define H_SET_ENTRY_POINT(h,v) ((h)->aouthdr.entry = (v)) +#define H_SET_TEXT_START(h,v) ((h)->aouthdr.text_start = (v)) +#define H_SET_DATA_START(h,v) ((h)->aouthdr.data_start = (v)) +/* filehdr */ +#define H_SET_FILE_MAGIC_NUMBER(h,v) ((h)->filehdr.f_magic = (v)) +#define H_SET_NUMBER_OF_SECTIONS(h,v) ((h)->filehdr.f_nscns = (v)) +#define H_SET_TIME_STAMP(h,v) ((h)->filehdr.f_timdat = (v)) +#define H_SET_SYMBOL_TABLE_POINTER(h,v) ((h)->filehdr.f_symptr = (v)) +#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->filehdr.f_nsyms = (v)) +#define H_SET_SIZEOF_OPTIONAL_HEADER(h,v) ((h)->filehdr.f_opthdr = (v)) +#define H_SET_FLAGS(h,v) ((h)->filehdr.f_flags = (v)) +/* Extra fields to achieve bsd a.out compatibility and for convinience */ +#define H_SET_RELOCATION_SIZE(h,t,d) ((h)->relocation_size = (t)+(d)) +#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v)) +#define H_SET_LINENO_SIZE(h,v) ((h)->lineno_size = (v)) + +/* Segment flipping */ +#define segment_name(v) (seg_name[(int) (v)]) + +typedef struct { +#ifdef BFD_HEADERS + struct internal_aouthdr aouthdr; /* a.out header */ + struct internal_filehdr filehdr; /* File header, not machine dep. */ +#else + AOUTHDR aouthdr; /* a.out header */ + FILHDR filehdr; /* File header, not machine dep. */ +#endif + long string_table_size; /* names + '\0' + sizeof(int) */ + long relocation_size; /* Cumulated size of relocation + information for all sections in + bytes. */ + long lineno_size; /* Size of the line number information + table in bytes */ +} object_headers; + +/* -------------- Line number handling ------- */ +extern int text_lineno_number; + +/* line numbering stuff. */ + +typedef struct internal_lineno { +#ifdef BFD_HEADERS + struct bfd_internal_lineno line; +#else + LINENO line; /* The lineno structure itself */ +#endif + char* frag; /* Frag to which the line number is related */ + struct internal_lineno* next; /* Forward chain pointer */ +} lineno; + +extern lineno *lineno_lastP; +extern lineno *lineno_rootP; +#define OBJ_EMIT_LINENO(a, b, c) obj_emit_lineno((a),(b),(c)) + +#if __STDC__ == 1 +void obj_emit_lineno(char **where, lineno *line, char *file_start); +#else /* not __STDC__ */ +void obj_emit_lineno(); +#endif /* not __STDC__ */ + +/* stack stuff */ +typedef struct { + unsigned long chunk_size; + unsigned long element_size; + unsigned long size; + char* data; + unsigned long pointer; +} stack; + +#if __STDC__ == 1 + +char *stack_pop(stack *st); +char *stack_push(stack *st, char *element); +char *stack_top(stack *st); +stack *stack_init(unsigned long chunk_size, unsigned long element_size); +void c_dot_file_symbol(char *filename); +void obj_extra_stuff(object_headers *headers); +void stack_delete(stack *st); + +#ifndef tc_headers_hook +void tc_headers_hook(object_headers *headers); +#endif /* tc_headers_hook */ + +#ifndef tc_coff_symbol_emit_hook +void tc_coff_symbol_emit_hook(); /* really tc_coff_symbol_emit_hook(symbolS *symbolP) */ +#endif /* tc_coff_symbol_emit_hook */ + +void c_section_header( +#ifdef BFD_HEADERS + struct internal_scnhdr *header, +#else + SCNHDR *header, +#endif + + char *name, + long core_address, + long size, + long data_ptr, + long reloc_ptr, + long lineno_ptr, + long reloc_number, + long lineno_number, + long alignment); + +#else /* not __STDC__ */ + +char *stack_pop(); +char *stack_push(); +char *stack_top(); +stack *stack_init(); +void c_dot_file_symbol(); +void c_section_header(); +void obj_extra_stuff(); +void stack_delete(); +void tc_headers_hook(); +void tc_coff_symbol_emit_hook(); + +#endif /* not __STDC__ */ + + +/* sanity check */ + +#ifdef TC_I960 +#ifndef C_LEAFSTAT +hey! Where is the C_LEAFSTAT definition? i960-coff support is depending on it. +#endif /* no C_LEAFSTAT */ +#endif /* TC_I960 */ +#ifdef BFD_HEADERS + extern struct internal_scnhdr data_section_header; +extern struct internal_scnhdr text_section_header; +#else +extern SCNHDR data_section_header; +extern SCNHDR text_section_header; +#endif + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-coff.h */ diff --git a/gnu/usr.bin/as/config/obj-coffbfd.c b/gnu/usr.bin/as/config/obj-coffbfd.c new file mode 100644 index 000000000000..d69c7a08cf15 --- /dev/null +++ b/gnu/usr.bin/as/config/obj-coffbfd.c @@ -0,0 +1,2182 @@ +/* coff object file format with bfd + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + + How does this releate to the rest of GAS ? + + Well, all the other files in gas are more or less a black box. It + takes care of opening files, parsing command lines, stripping blanks + etc etc. This module gets a chance to register what it wants to do by + saying that it is interested in various pseduo ops. The other big + change is write_object_file. This runs through all the data + structures that gas builds, and outputs the file in the format of our + choice. + + Hacked for BFDness by steve chamberlain + + This object module now supports the Hitachi H8/300 and the AMD 29k + + sac@cygnus.com + */ + +#include "as.h" +#include "obstack.h" +#include "subsegs.h" +#include "frags.h" +#include "../bfd/libbfd.h" + + +/* This vector is used to turn an internal segment into a section # + suitable for insertion into a coff symbol table + */ + +const short seg_N_TYPE[] = { /* in: segT out: N_TYPE bits */ + C_ABS_SECTION, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + C_UNDEF_SECTION, /* SEG_UNKNOWN */ + C_UNDEF_SECTION, /* SEG_ABSENT */ + C_UNDEF_SECTION, /* SEG_PASS1 */ + C_UNDEF_SECTION, /* SEG_GOOF */ + C_UNDEF_SECTION, /* SEG_BIG */ + C_UNDEF_SECTION, /* SEG_DIFFERENCE */ + C_DEBUG_SECTION, /* SEG_DEBUG */ + C_NTV_SECTION, /* SEG_NTV */ + C_PTV_SECTION, /* SEG_PTV */ + C_REGISTER_SECTION, /* SEG_REGISTER */ +}; + + +int function_lineoff = -1; /* Offset in line#s where the last function + started (the odd entry for line #0) */ + +int our_lineno_number = 0; /* we use this to build pointers from .bf's + into the linetable. It should match + exactly the values that are later + assigned in text_lineno_number by + write.c. */ + +int text_lineno_number = 0; + +/* Add 4 to the real value to get the index and compensate the + negatives. This vector is used by S_GET_SEGMENT to turn a coff + section number into a segment number + */ +static symbolS *previous_file_symbol = NULL; +void c_symbol_merge(); +static int line_base; + +symbolS *c_section_symbol(); +bfd *abfd; +void EXFUN(bfd_as_write_hook,(struct internal_filehdr *, + bfd *abfd)); + +static void EXFUN(fixup_segment,(fixS * fixP, + segT this_segment_type)); + +static void EXFUN(fill_section,(bfd *abfd , + struct internal_filehdr *f, unsigned + long *)); + + +char *EXFUN(s_get_name,(symbolS *s)); +static symbolS *EXFUN(tag_find_or_make,(char *name)); +static symbolS* EXFUN(tag_find,(char *name)); + + +static int + EXFUN(c_line_new,( + symbolS *symbol, + long paddr, + unsigned short line_number, + fragS* frag)); + + +static void EXFUN(w_symbols, + (bfd *abfd , + char *where , + symbolS *symbol_rootP)); + + + +static void EXFUN( obj_coff_def,(int what)); +static void EXFUN( obj_coff_lcomm,(void)); +static void EXFUN( obj_coff_dim,(void)); +static void EXFUN( obj_coff_text,(void)); +static void EXFUN( obj_coff_data,(void)); +static void EXFUN( obj_coff_endef,(void)); +static void EXFUN( obj_coff_line,(void)); +static void EXFUN( obj_coff_ln,(void)); +static void EXFUN( obj_coff_scl,(void)); +static void EXFUN( obj_coff_size,(void)); +static void EXFUN( obj_coff_tag,(void)); +static void EXFUN( obj_coff_type,(void)); +static void EXFUN( obj_coff_val,(void)); +static void EXFUN( obj_coff_section,(void)); +static void EXFUN( tag_init,(void)); +static void EXFUN( tag_insert,(char *name, symbolS *symbolP)); + + +static struct hash_control *tag_hash; +static symbolS *def_symbol_in_progress = NULL; + +const pseudo_typeS obj_pseudo_table[] = { + { "def", obj_coff_def, 0 }, + { "dim", obj_coff_dim, 0 }, + { "endef", obj_coff_endef, 0 }, + { "line", obj_coff_line, 0 }, + { "ln", obj_coff_ln, 0 }, + { "scl", obj_coff_scl, 0 }, + { "size", obj_coff_size, 0 }, + { "tag", obj_coff_tag, 0 }, + { "type", obj_coff_type, 0 }, + { "val", obj_coff_val, 0 }, + { "section", obj_coff_section, 0 }, + { "text", obj_coff_text, 0 }, + { "data", obj_coff_data, 0 }, + /* we don't yet handle this. */ + { "ident", s_ignore, 0 }, + { "ABORT", s_abort, 0 }, + { "lcomm", obj_coff_lcomm, 0}, + { NULL} /* end sentinel */ +}; /* obj_pseudo_table */ + + + +/* Section stuff + + We allow more than just the standard 3 sections, infact, we allow + 10 sections, (though the usual three have to be there). + + This structure performs the mappings for us: + + */ + +/* OBS stuff + static struct internal_scnhdr bss_section_header; + struct internal_scnhdr data_section_header; + struct internal_scnhdr text_section_header; + + const segT N_TYPE_seg[32] = + { + + }; + + */ + +#define N_SEG 32 +typedef struct +{ + segT seg_t; + int i; +} seg_info_type; + +seg_info_type seg_info_off_by_4[N_SEG] = +{ + {SEG_PTV, }, + {SEG_NTV, }, + {SEG_DEBUG, }, + {SEG_ABSOLUTE, }, + {SEG_UNKNOWN, }, + {SEG_E0}, + {SEG_E1}, + {SEG_E2}, + {SEG_E3}, + {SEG_E4}, + {SEG_E5}, + {SEG_E6}, + {SEG_E7}, + {SEG_E8}, + {SEG_E9}, + {15}, + {16}, + {17}, + {18}, + {19}, + {20}, + {0}, + {0}, + {0}, + {SEG_REGISTER},0,0,0,0}; + +#define SEG_INFO_FROM_SECTION_NUMBER(x) (seg_info_off_by_4[(x)+4]) +#define SEG_INFO_FROM_SEG_NUMBER(x) (seg_info_off_by_4[(x)]) + + +relax_addressT + DEFUN(relax_align,(address, alignment), + register relax_addressT address AND + register long alignment ) +{ + relax_addressT mask; + relax_addressT new_address; + + mask = ~ ( (~0) << alignment ); + new_address = (address + mask) & (~ mask); + return (new_address - address); +} /* relax_align() */ + + +segT + DEFUN(s_get_segment,(x) , + symbolS* x) +{ + return SEG_INFO_FROM_SECTION_NUMBER(x->sy_symbol.ost_entry.n_scnum).seg_t; +} + + + +/* calculate the size of the frag chain and fill in the section header + to contain all of it, also fill in the addr of the sections */ +static unsigned int DEFUN(size_section,(abfd, idx), + bfd *abfd AND + unsigned int idx) +{ + + unsigned int size = 0; + fragS *frag = segment_info[idx].frchainP->frch_root; + while (frag) { + if (frag->fr_address != size) { + printf("Out of step\n"); + size = frag->fr_address; + } + size += frag->fr_fix; + switch (frag->fr_type) { + case rs_fill: + case rs_org: + size += frag->fr_offset * frag->fr_var; + break; + case rs_align: + size += relax_align(size, frag->fr_offset); + } + frag = frag->fr_next; + } + segment_info[idx].scnhdr.s_size = size; + return size; +} + + +static unsigned int DEFUN(count_entries_in_chain,(idx), + unsigned int idx) +{ + unsigned int nrelocs; + fixS *fixup_ptr; + + /* Count the relocations */ + fixup_ptr = segment_info[idx].fix_root; + nrelocs = 0; + while (fixup_ptr != (fixS *)NULL) + { + if (TC_COUNT_RELOC(fixup_ptr)) + { + +#ifdef TC_A29K + + if (fixup_ptr->fx_r_type == RELOC_CONSTH) + nrelocs+=2; + else + nrelocs++; +#else + nrelocs++; +#endif + } + + fixup_ptr = fixup_ptr->fx_next; + } + return nrelocs; +} + +/* output all the relocations for a section */ +void DEFUN(do_relocs_for,(abfd, file_cursor), + bfd *abfd AND + unsigned long *file_cursor) +{ + unsigned int nrelocs; + unsigned int idx; + + for (idx = SEG_E0; idx < SEG_E9; idx++) + { + if (segment_info[idx].scnhdr.s_name[0]) + { + + struct external_reloc *ext_ptr; + struct external_reloc *external_reloc_vec; + unsigned int external_reloc_size; + unsigned int count = 0; + unsigned int base = segment_info[idx].scnhdr.s_paddr; + fixS * fix_ptr = segment_info[idx].fix_root; + nrelocs = count_entries_in_chain(idx); + external_reloc_size = nrelocs * RELSZ; + external_reloc_vec = + (struct external_reloc*)malloc(external_reloc_size); + + + + ext_ptr = external_reloc_vec; + + /* Fill in the internal coff style reloc struct from the + internal fix list */ + while (fix_ptr) + { + symbolS *symbol_ptr; + struct internal_reloc intr; + + /* Only output some of the relocations */ + if (TC_COUNT_RELOC(fix_ptr)) + { +#ifdef TC_RELOC_MANGLE + TC_RELOC_MANGLE(fix_ptr, &intr, base); + +#else + symbolS *dot; + symbol_ptr = fix_ptr->fx_addsy; + + intr.r_type = TC_COFF_FIX2RTYPE(fix_ptr); + intr.r_vaddr = + base + fix_ptr->fx_frag->fr_address + fix_ptr->fx_where ; + + intr.r_offset = fix_ptr->fx_offset; + + intr.r_offset = 0; + + /* Turn the segment of the symbol into an offset + */ + if (symbol_ptr) + { + dot = segment_info[S_GET_SEGMENT(symbol_ptr)].dot; + if (dot) + { + intr.r_symndx = dot->sy_number; + } + else + { + intr.r_symndx = symbol_ptr->sy_number; + } + + } + else + { + intr.r_symndx = -1; + + + } +#endif + + (void)bfd_coff_swap_reloc_out(abfd, &intr, ext_ptr); + ext_ptr++; + +#if defined(TC_A29K) + /* The 29k has a special kludge for the high 16 bit reloc. + Two relocations are emmited, R_IHIHALF, and + R_IHCONST. The second one doesn't contain a symbol, + but uses the value for offset */ + + if (intr.r_type == R_IHIHALF) + { + /* now emit the second bit */ + intr.r_type = R_IHCONST; + intr.r_symndx = fix_ptr->fx_addnumber; + (void)bfd_coff_swap_reloc_out(abfd,&intr,ext_ptr); + ext_ptr++; + } +#endif + } + + fix_ptr = fix_ptr->fx_next; + } + + /* Write out the reloc table */ + segment_info[idx].scnhdr.s_relptr = *file_cursor; + segment_info[idx].scnhdr.s_nreloc = nrelocs; + bfd_write((PTR)external_reloc_vec, 1, external_reloc_size, abfd); + *file_cursor += external_reloc_size; + free( external_reloc_vec); + } + } +} + + +/* run through a frag chain and write out the data to go with it, fill + in the scnhdrs with the info on the file postions + */ +static void DEFUN(fill_section,(abfd, filehdr, file_cursor), + bfd *abfd AND + struct internal_filehdr *filehdr AND + unsigned long *file_cursor) +{ + + unsigned int i; + unsigned int paddr = 0; + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + unsigned int offset = 0; + + struct internal_scnhdr *s = &( segment_info[i].scnhdr); + + if (s->s_name[0]) + { + fragS *frag = segment_info[i].frchainP->frch_root; + char *buffer = malloc(s->s_size); + s->s_scnptr = *file_cursor; + s->s_paddr = paddr; + s->s_vaddr = paddr; + + s->s_flags = STYP_REG; + if (strcmp(s->s_name,".text") == 0) + s->s_flags |= STYP_TEXT; + else if (strcmp(s->s_name,".data") == 0) + s->s_flags |= STYP_DATA; + else if (strcmp(s->s_name,".bss") == 0) + s->s_flags |= STYP_BSS | STYP_NOLOAD; + + while (frag) { + unsigned int fill_size; + switch (frag->fr_type) { + + case rs_fill: + case rs_align: + case rs_org: + if (frag->fr_fix) + { + memcpy(buffer + frag->fr_address, + frag->fr_literal, + frag->fr_fix); + offset += frag->fr_fix; + } + + fill_size = frag->fr_var; + if (fill_size) + { + unsigned int count ; + unsigned int off = frag->fr_fix; + for (count = frag->fr_offset; count; count--) + { + memcpy(buffer + frag->fr_address + off, + frag->fr_literal + frag->fr_fix, + fill_size); + off += fill_size; + offset += fill_size; + + } + + } + break; + default: + abort(); + } + frag = frag->fr_next; + } + + + bfd_write(buffer, s->s_size,1,abfd); + free(buffer); + + *file_cursor += s->s_size; + paddr += s->s_size; + } + } + +} + + + +/* Coff file generation & utilities */ + + +static void + DEFUN(coff_header_append,(abfd, filehdr, aouthdr), + bfd *abfd AND + struct internal_filehdr *filehdr AND + struct internal_aouthdr *aouthdr) +{ + unsigned int i; + char buffer[1000]; + char buffero[1000]; + + bfd_seek(abfd, 0, 0); +#if 0 + filehdr.f_opthdr = bfd_coff_swap_aouthdr_out(abfd, aouthdr, + buffero); +#else + filehdr->f_opthdr = 0; +#endif + i = bfd_coff_swap_filehdr_out(abfd, filehdr, buffer); + + bfd_write(buffer, i ,1, abfd); + bfd_write(buffero, filehdr->f_opthdr, 1, abfd); + + for (i = SEG_E0; i < SEG_E9; i++) + { + if (segment_info[i].scnhdr.s_name[0]) + { + unsigned int size = + bfd_coff_swap_scnhdr_out(abfd, + &(segment_info[i].scnhdr), + buffer); + bfd_write(buffer, size, 1, abfd); + } + } +} + + +char * + DEFUN(symbol_to_chars,(abfd, where, symbolP), + bfd*abfd AND + char *where AND + symbolS *symbolP) +{ + unsigned int numaux = symbolP->sy_symbol.ost_entry.n_numaux; + unsigned int i; + + /* Turn any symbols with register attributes into abs symbols */ + if (S_GET_SEGMENT(symbolP) == SEG_REGISTER) + { + S_SET_SEGMENT(symbolP, SEG_ABSOLUTE); + } + /* At the same time, relocate all symbols to their output value */ + + S_SET_VALUE(symbolP, + segment_info[S_GET_SEGMENT(symbolP)].scnhdr.s_paddr + + S_GET_VALUE(symbolP)); + + where += bfd_coff_swap_sym_out(abfd, &symbolP->sy_symbol.ost_entry, + where); + + for (i = 0; i < numaux; i++) + { + where += bfd_coff_swap_aux_out(abfd, + &symbolP->sy_symbol.ost_auxent[i], + S_GET_DATA_TYPE(symbolP), + S_GET_STORAGE_CLASS(symbolP), + where); + } + return where; + +} + + + + +void obj_symbol_new_hook(symbolP) +symbolS *symbolP; +{ + char underscore = 0; /* Symbol has leading _ */ + + /* Effective symbol */ + /* Store the pointer in the offset. */ + S_SET_ZEROES(symbolP, 0L); + S_SET_DATA_TYPE(symbolP, T_NULL); + S_SET_STORAGE_CLASS(symbolP, 0); + S_SET_NUMBER_AUXILIARY(symbolP, 0); + /* Additional information */ + symbolP->sy_symbol.ost_flags = 0; + /* Auxiliary entries */ + memset((char*) &symbolP->sy_symbol.ost_auxent[0], '\0', AUXESZ); + +#ifdef STRIP_UNDERSCORE + /* Remove leading underscore at the beginning of the symbol. + * This is to be compatible with the standard librairies. + */ + if (*S_GET_NAME(symbolP) == '_') { + underscore = 1; + S_SET_NAME(symbolP, S_GET_NAME(symbolP) + 1); + } /* strip underscore */ +#endif /* STRIP_UNDERSCORE */ + + if (S_IS_STRING(symbolP)) + SF_SET_STRING(symbolP); + if (!underscore && S_IS_LOCAL(symbolP)) + SF_SET_LOCAL(symbolP); + + return; +} /* obj_symbol_new_hook() */ + +/* stack stuff */ +stack* stack_init(chunk_size, element_size) +unsigned long chunk_size; +unsigned long element_size; +{ + stack* st; + + if ((st = (stack*)malloc(sizeof(stack))) == (stack*)0) + return (stack*)0; + if ((st->data = malloc(chunk_size)) == (char*)0) { + free(st); + return (stack*)0; + } + st->pointer = 0; + st->size = chunk_size; + st->chunk_size = chunk_size; + st->element_size = element_size; + return st; +} /* stack_init() */ + +void stack_delete(st) +stack* st; +{ + free(st->data); + free(st); +} + +char *stack_push(st, element) +stack *st; +char *element; +{ + if (st->pointer + st->element_size >= st->size) { + st->size += st->chunk_size; + if ((st->data = xrealloc(st->data, st->size)) == (char*)0) + return (char*)0; + } + memcpy(st->data + st->pointer, element, st->element_size); + st->pointer += st->element_size; + return st->data + st->pointer; +} /* stack_push() */ + +char* stack_pop(st) +stack* st; +{ + if ((st->pointer -= st->element_size) < 0) { + st->pointer = 0; + return (char*)0; + } + + return st->data + st->pointer; +} + +char* stack_top(st) +stack* st; +{ + return st->data + st->pointer - st->element_size; +} + + +/* + * Handle .ln directives. + */ + +static void obj_coff_ln() +{ + int l; + + if (def_symbol_in_progress != NULL) { + as_warn(".ln pseudo-op inside .def/.endef: ignored."); + demand_empty_rest_of_line(); + return; + } /* wrong context */ + + c_line_new(0, + obstack_next_free(&frags) - frag_now->fr_literal, + l = get_absolute_expression(), + frag_now); +#ifndef NO_LISTING + { + extern int listing; + + if (listing) + { + listing_source_line(l + line_base - 1); + } + + } +#endif + demand_empty_rest_of_line(); + return; +} /* obj_coff_line() */ + +/* + * def() + * + * Handle .def directives. + * + * One might ask : why can't we symbol_new if the symbol does not + * already exist and fill it with debug information. Because of + * the C_EFCN special symbol. It would clobber the value of the + * function symbol before we have a chance to notice that it is + * a C_EFCN. And a second reason is that the code is more clear this + * way. (at least I think it is :-). + * + */ + +#define SKIP_SEMI_COLON() while (*input_line_pointer++ != ';') +#define SKIP_WHITESPACES() while (*input_line_pointer == ' ' || \ + *input_line_pointer == '\t') \ + input_line_pointer++; + +static void + DEFUN(obj_coff_def,(what), + int what) +{ + char name_end; /* Char after the end of name */ + char *symbol_name; /* Name of the debug symbol */ + char *symbol_name_copy; /* Temporary copy of the name */ + unsigned int symbol_name_length; + /*$char* directiveP;$ */ /* Name of the pseudo opcode */ + /*$char directive[MAX_DIRECTIVE];$ */ /* Backup of the directive */ + /*$char end = 0;$ */ /* If 1, stop parsing */ + + if (def_symbol_in_progress != NULL) { + as_warn(".def pseudo-op used inside of .def/.endef: ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + SKIP_WHITESPACES(); + + def_symbol_in_progress = (symbolS *) obstack_alloc(¬es, sizeof(*def_symbol_in_progress)); + memset(def_symbol_in_progress, '\0', sizeof(*def_symbol_in_progress)); + + symbol_name = input_line_pointer; + name_end = get_symbol_end(); + symbol_name_length = strlen(symbol_name); + symbol_name_copy = xmalloc(symbol_name_length + 1); + strcpy(symbol_name_copy, symbol_name); + + /* Initialize the new symbol */ +#ifdef STRIP_UNDERSCORE + S_SET_NAME(def_symbol_in_progress, (*symbol_name_copy == '_' + ? symbol_name_copy + 1 + : symbol_name_copy)); +#else /* STRIP_UNDERSCORE */ + S_SET_NAME(def_symbol_in_progress, symbol_name_copy); +#endif /* STRIP_UNDERSCORE */ + /* free(symbol_name_copy); */ + def_symbol_in_progress->sy_name_offset = ~0; + def_symbol_in_progress->sy_number = ~0; + def_symbol_in_progress->sy_frag = &zero_address_frag; + + if (S_IS_STRING(def_symbol_in_progress)) { + SF_SET_STRING(def_symbol_in_progress); + } /* "long" name */ + + *input_line_pointer = name_end; + + demand_empty_rest_of_line(); + return; +} /* obj_coff_def() */ + +unsigned int dim_index; +static void + DEFUN_VOID(obj_coff_endef) +{ + symbolS *symbolP = 0; + /* DIM BUG FIX sac@cygnus.com */ + dim_index =0; + if (def_symbol_in_progress == NULL) { + as_warn(".endef pseudo-op used outside of .def/.endef: ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + /* Set the section number according to storage class. */ + switch (S_GET_STORAGE_CLASS(def_symbol_in_progress)) { + case C_STRTAG: + case C_ENTAG: + case C_UNTAG: + SF_SET_TAG(def_symbol_in_progress); + /* intentional fallthrough */ + case C_FILE: + case C_TPDEF: + SF_SET_DEBUG(def_symbol_in_progress); + S_SET_SEGMENT(def_symbol_in_progress, SEG_DEBUG); + break; + + case C_EFCN: + SF_SET_LOCAL(def_symbol_in_progress); /* Do not emit this symbol. */ + /* intentional fallthrough */ + case C_BLOCK: + SF_SET_PROCESS(def_symbol_in_progress); /* Will need processing before writing */ + /* intentional fallthrough */ + case C_FCN: + S_SET_SEGMENT(def_symbol_in_progress, SEG_E0); + + if (def_symbol_in_progress->sy_symbol.ost_entry.n_name[1] == 'b') { /* .bf */ + if (function_lineoff < 0) { + fprintf(stderr, "`.bf' symbol without preceding function\n"); + } /* missing function symbol */ + SA_GET_SYM_LNNOPTR(def_symbol_in_progress) = function_lineoff; + SF_SET_PROCESS(def_symbol_in_progress); /* Will need relocating */ + function_lineoff = -1; + } + break; + +#ifdef C_AUTOARG + case C_AUTOARG: +#endif /* C_AUTOARG */ + case C_AUTO: + case C_REG: + case C_MOS: + case C_MOE: + case C_MOU: + case C_ARG: + case C_REGPARM: + case C_FIELD: + case C_EOS: + SF_SET_DEBUG(def_symbol_in_progress); + S_SET_SEGMENT(def_symbol_in_progress, SEG_ABSOLUTE); + break; + + case C_EXT: + case C_STAT: + case C_LABEL: + /* Valid but set somewhere else (s_comm, s_lcomm, colon) */ + break; + + case C_USTATIC: + case C_EXTDEF: + case C_ULABEL: + as_warn("unexpected storage class %d", S_GET_STORAGE_CLASS(def_symbol_in_progress)); + break; + } /* switch on storage class */ + + /* Now that we have built a debug symbol, try to + find if we should merge with an existing symbol + or not. If a symbol is C_EFCN or SEG_ABSOLUTE or + untagged SEG_DEBUG it never merges. */ + + /* Two cases for functions. Either debug followed + by definition or definition followed by debug. + For definition first, we will merge the debug + symbol into the definition. For debug first, the + lineno entry MUST point to the definition + function or else it will point off into space + when crawl_symbols() merges the debug + symbol into the real symbol. Therefor, let's + presume the debug symbol is a real function + reference. */ + + /* FIXME-SOON If for some reason the definition + label/symbol is never seen, this will probably + leave an undefined symbol at link time. */ + + if (S_GET_STORAGE_CLASS(def_symbol_in_progress) == C_EFCN + || (S_GET_SEGMENT(def_symbol_in_progress) == SEG_DEBUG + && !SF_GET_TAG(def_symbol_in_progress)) + || S_GET_SEGMENT(def_symbol_in_progress) == SEG_ABSOLUTE + || (symbolP = symbol_find_base(S_GET_NAME(def_symbol_in_progress), DO_NOT_STRIP)) == NULL) { + + symbol_append(def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP); + + } else { + /* This symbol already exists, merge the + newly created symbol into the old one. + This is not mandatory. The linker can + handle duplicate symbols correctly. But I + guess that it save a *lot* of space if + the assembly file defines a lot of + symbols. [loic] */ + + /* The debug entry (def_symbol_in_progress) + is merged into the previous definition. */ + + c_symbol_merge(def_symbol_in_progress, symbolP); + /* FIXME-SOON Should *def_symbol_in_progress be free'd? xoxorich. */ + def_symbol_in_progress = symbolP; + + if (SF_GET_FUNCTION(def_symbol_in_progress) + || SF_GET_TAG(def_symbol_in_progress)) { + /* For functions, and tags, the symbol *must* be where the debug symbol + appears. Move the existing symbol to the current place. */ + /* If it already is at the end of the symbol list, do nothing */ + if (def_symbol_in_progress != symbol_lastP) { + symbol_remove(def_symbol_in_progress, &symbol_rootP, &symbol_lastP); + symbol_append(def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP); + } /* if not already in place */ + } /* if function */ + } /* normal or mergable */ + + if (SF_GET_TAG(def_symbol_in_progress) + && symbol_find_base(S_GET_NAME(def_symbol_in_progress), DO_NOT_STRIP) == NULL) { + tag_insert(S_GET_NAME(def_symbol_in_progress), def_symbol_in_progress); + } /* If symbol is a {structure,union} tag, associate symbol to its name. */ + + if (SF_GET_FUNCTION(def_symbol_in_progress)) { + know(sizeof(def_symbol_in_progress) <= sizeof(long)); + function_lineoff + = c_line_new(def_symbol_in_progress,0, 0, &zero_address_frag); + + + + SF_SET_PROCESS(def_symbol_in_progress); + + if (symbolP == NULL) { + /* That is, if this is the first + time we've seen the function... */ + symbol_table_insert(def_symbol_in_progress); + } /* definition follows debug */ + } /* Create the line number entry pointing to the function being defined */ + + def_symbol_in_progress = NULL; + demand_empty_rest_of_line(); + return; +} /* obj_coff_endef() */ + +static void + DEFUN_VOID(obj_coff_dim) +{ + register int dim_index; + + if (def_symbol_in_progress == NULL) + { + as_warn(".dim pseudo-op used outside of .def/.endef: ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1); + + for (dim_index = 0; dim_index < DIMNUM; dim_index++) + { + SKIP_WHITESPACES(); + SA_SET_SYM_DIMEN(def_symbol_in_progress, dim_index, get_absolute_expression()); + + switch (*input_line_pointer) + { + + case ',': + input_line_pointer++; + break; + + default: + as_warn("badly formed .dim directive ignored"); + /* intentional fallthrough */ + case '\n': + case ';': + dim_index = DIMNUM; + break; + } /* switch on following character */ + } /* for each dimension */ + + demand_empty_rest_of_line(); + return; +} /* obj_coff_dim() */ + +static void obj_coff_line() +{ + int this_base; + + if (def_symbol_in_progress == NULL) { + obj_coff_ln(); + return; + } /* if it looks like a stabs style line */ + + this_base = get_absolute_expression(); + if (this_base > line_base) + { + line_base = this_base; + } + + +#ifndef NO_LISTING + { + extern int listing; + if (listing && 0) { + listing_source_line(line_base); + } + } +#endif + S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1); + SA_SET_SYM_LNNO(def_symbol_in_progress, line_base); + + demand_empty_rest_of_line(); + return; +} /* obj_coff_line() */ + +static void obj_coff_size() { + if (def_symbol_in_progress == NULL) { + as_warn(".size pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1); + SA_SET_SYM_SIZE(def_symbol_in_progress, get_absolute_expression()); + demand_empty_rest_of_line(); + return; +} /* obj_coff_size() */ + +static void obj_coff_scl() { + if (def_symbol_in_progress == NULL) { + as_warn(".scl pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + S_SET_STORAGE_CLASS(def_symbol_in_progress, get_absolute_expression()); + demand_empty_rest_of_line(); + return; +} /* obj_coff_scl() */ + +static void obj_coff_tag() { + char *symbol_name; + char name_end; + + if (def_symbol_in_progress == NULL) { + as_warn(".tag pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1); + symbol_name = input_line_pointer; + name_end = get_symbol_end(); + + /* Assume that the symbol referred to by .tag is always defined. */ + /* This was a bad assumption. I've added find_or_make. xoxorich. */ + SA_SET_SYM_TAGNDX(def_symbol_in_progress, (long) tag_find_or_make(symbol_name)); + if (SA_GET_SYM_TAGNDX(def_symbol_in_progress) == 0L) { + as_warn("tag not found for .tag %s", symbol_name); + } /* not defined */ + + SF_SET_TAGGED(def_symbol_in_progress); + *input_line_pointer = name_end; + + demand_empty_rest_of_line(); + return; +} /* obj_coff_tag() */ + +static void obj_coff_type() { + if (def_symbol_in_progress == NULL) { + as_warn(".type pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + S_SET_DATA_TYPE(def_symbol_in_progress, get_absolute_expression()); + + if (ISFCN(S_GET_DATA_TYPE(def_symbol_in_progress)) && + S_GET_STORAGE_CLASS(def_symbol_in_progress) != C_TPDEF) { + SF_SET_FUNCTION(def_symbol_in_progress); + } /* is a function */ + + demand_empty_rest_of_line(); + return; +} /* obj_coff_type() */ + +static void obj_coff_val() { + if (def_symbol_in_progress == NULL) { + as_warn(".val pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line(); + return; + } /* if not inside .def/.endef */ + + if (is_name_beginner(*input_line_pointer)) { + char *symbol_name = input_line_pointer; + char name_end = get_symbol_end(); + + if (!strcmp(symbol_name, ".")) { + def_symbol_in_progress->sy_frag = frag_now; + S_SET_VALUE(def_symbol_in_progress, obstack_next_free(&frags) - frag_now->fr_literal); + /* If the .val is != from the .def (e.g. statics) */ + } else if (strcmp(S_GET_NAME(def_symbol_in_progress), symbol_name)) { + def_symbol_in_progress->sy_forward = symbol_find_or_make(symbol_name); + + /* If the segment is undefined when the forward + reference is solved, then copy the segment id + from the forward symbol. */ + SF_SET_GET_SEGMENT(def_symbol_in_progress); + } + /* Otherwise, it is the name of a non debug symbol and its value will be calculated later. */ + *input_line_pointer = name_end; + } else { + S_SET_VALUE(def_symbol_in_progress, get_absolute_expression()); + } /* if symbol based */ + + demand_empty_rest_of_line(); + return; +} /* obj_coff_val() */ + +/* + * Maintain a list of the tagnames of the structres. + */ + +static void tag_init() { + tag_hash = hash_new(); + return ; +} /* tag_init() */ + +static void tag_insert(name, symbolP) +char *name; +symbolS *symbolP; +{ + register char * error_string; + + if (*(error_string = hash_jam(tag_hash, name, (char *)symbolP))) { + as_fatal("Inserting \"%s\" into structure table failed: %s", + name, error_string); + } + return ; +} /* tag_insert() */ + +static symbolS *tag_find_or_make(name) +char *name; +{ + symbolS *symbolP; + + if ((symbolP = tag_find(name)) == NULL) { + symbolP = symbol_new(name, + SEG_UNKNOWN, + 0, + &zero_address_frag); + + tag_insert(S_GET_NAME(symbolP), symbolP); + symbol_table_insert(symbolP); + } /* not found */ + + return(symbolP); +} /* tag_find_or_make() */ + +static symbolS *tag_find(name) +char *name; +{ +#ifdef STRIP_UNDERSCORE + if (*name == '_') name++; +#endif /* STRIP_UNDERSCORE */ + return((symbolS*)hash_find(tag_hash, name)); +} /* tag_find() */ + +void obj_read_begin_hook() { + /* These had better be the same. Usually 18 bytes. */ +#ifndef BFD_HEADERS + know(sizeof(SYMENT) == sizeof(AUXENT)); + know(SYMESZ == AUXESZ); +#endif + tag_init(); + + return; +} /* obj_read_begin_hook() */ + +/* This function runs through the symbol table and puts all the + externals onto another chain */ + +/* The chain of externals */ +symbolS *symbol_externP = NULL; +symbolS *symbol_extern_lastP = NULL; + +stack*block_stack; +symbolS *last_functionP = NULL; +symbolS *last_tagP; + + +static unsigned int DEFUN_VOID(yank_symbols) +{ + symbolS *symbolP; + unsigned int symbol_number =0; + + for (symbolP = symbol_rootP; + symbolP; + symbolP = symbolP ? symbol_next(symbolP) : symbol_rootP) { + if (!SF_GET_DEBUG(symbolP)) { + /* Debug symbols do not need all this rubbish */ + symbolS* real_symbolP; + + /* L* and C_EFCN symbols never merge. */ + if (!SF_GET_LOCAL(symbolP) + && (real_symbolP = symbol_find_base(S_GET_NAME(symbolP), DO_NOT_STRIP)) + && real_symbolP != symbolP) { + /* FIXME-SOON: where do dups come from? + Maybe tag references before definitions? xoxorich. */ + /* Move the debug data from the debug symbol to the + real symbol. Do NOT do the oposite (i.e. move from + real symbol to debug symbol and remove real symbol from the + list.) Because some pointers refer to the real symbol + whereas no pointers refer to the debug symbol. */ + c_symbol_merge(symbolP, real_symbolP); + /* Replace the current symbol by the real one */ + /* The symbols will never be the last or the first + because : 1st symbol is .file and 3 last symbols are + .text, .data, .bss */ + symbol_remove(real_symbolP, &symbol_rootP, &symbol_lastP); + symbol_insert(real_symbolP, symbolP, &symbol_rootP, &symbol_lastP); + symbol_remove(symbolP, &symbol_rootP, &symbol_lastP); + symbolP = real_symbolP; + } /* if not local but dup'd */ + + if (flagseen['R'] && (S_GET_SEGMENT(symbolP) == SEG_E1)) { + S_SET_SEGMENT(symbolP, SEG_E0); + } /* push data into text */ + + S_SET_VALUE(symbolP, + S_GET_VALUE(symbolP) + symbolP->sy_frag->fr_address); + + if (!S_IS_DEFINED(symbolP) && !SF_GET_LOCAL(symbolP)) + { + S_SET_EXTERNAL(symbolP); + } + else if (S_GET_STORAGE_CLASS(symbolP) == C_NULL) + { + if (S_GET_SEGMENT(symbolP) == SEG_E0) + { + S_SET_STORAGE_CLASS(symbolP, C_LABEL); + } + else + { + S_SET_STORAGE_CLASS(symbolP, C_STAT); + } + } + + /* Mainly to speed up if not -g */ + if (SF_GET_PROCESS(symbolP)) + { + /* Handle the nested blocks auxiliary info. */ + if (S_GET_STORAGE_CLASS(symbolP) == C_BLOCK) { + if (!strcmp(S_GET_NAME(symbolP), ".bb")) + stack_push(block_stack, (char *) &symbolP); + else { /* .eb */ + register symbolS* begin_symbolP; + begin_symbolP = *(symbolS**)stack_pop(block_stack); + if (begin_symbolP == (symbolS*)0) + as_warn("mismatched .eb"); + else + SA_SET_SYM_ENDNDX(begin_symbolP, symbol_number+2); + } + } + /* If we are able to identify the type of a function, and we + are out of a function (last_functionP == 0) then, the + function symbol will be associated with an auxiliary + entry. */ + if (last_functionP == (symbolS*)0 && + SF_GET_FUNCTION(symbolP)) { + last_functionP = symbolP; + + if (S_GET_NUMBER_AUXILIARY(symbolP) < 1) { + S_SET_NUMBER_AUXILIARY(symbolP, 1); + } /* make it at least 1 */ + + /* Clobber possible stale .dim information. */ + memset(symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen, + '\0', sizeof(symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen)); + } + /* The C_FCN doesn't need any additional information. + I don't even know if this is needed for sdb. But the + standard assembler generates it, so... + */ + if (S_GET_STORAGE_CLASS(symbolP) == C_EFCN) { + if (last_functionP == (symbolS*)0) + as_fatal("C_EFCN symbol out of scope"); + SA_SET_SYM_FSIZE(last_functionP, + (long)(S_GET_VALUE(symbolP) - + S_GET_VALUE(last_functionP))); + SA_SET_SYM_ENDNDX(last_functionP, symbol_number); + last_functionP = (symbolS*)0; + } + } + } else if (SF_GET_TAG(symbolP)) { + /* First descriptor of a structure must point to + the first slot after the structure description. */ + last_tagP = symbolP; + + } else if (S_GET_STORAGE_CLASS(symbolP) == C_EOS) { + /* +2 take in account the current symbol */ + SA_SET_SYM_ENDNDX(last_tagP, symbol_number + 2); + } else if (S_GET_STORAGE_CLASS(symbolP) == C_FILE) { + if (S_GET_VALUE(symbolP)) { + S_SET_VALUE((symbolS *) S_GET_VALUE(symbolP), symbol_number); + S_SET_VALUE(symbolP, 0); + } /* no one points at the first .file symbol */ + } /* if debug or tag or eos or file */ + + /* We must put the external symbols apart. The loader + does not bomb if we do not. But the references in + the endndx field for a .bb symbol are not corrected + if an external symbol is removed between .bb and .be. + I.e in the following case : + [20] .bb endndx = 22 + [21] foo external + [22] .be + ld will move the symbol 21 to the end of the list but + endndx will still be 22 instead of 21. */ + + + if (SF_GET_LOCAL(symbolP)) { + /* remove C_EFCN and LOCAL (L...) symbols */ + /* next pointer remains valid */ + symbol_remove(symbolP, &symbol_rootP, &symbol_lastP); + + } + else if (!S_IS_DEFINED(symbolP) + && !S_IS_DEBUG(symbolP) + && !SF_GET_STATICS(symbolP) && + S_GET_STORAGE_CLASS(symbolP) == C_EXT) + { /* C_EXT && !SF_GET_FUNCTION(symbolP)) */ + /* if external, Remove from the list */ + symbolS *hold = symbol_previous(symbolP); + + symbol_remove(symbolP, &symbol_rootP, &symbol_lastP); + symbol_clear_list_pointers(symbolP); + symbol_append(symbolP, symbol_extern_lastP, &symbol_externP, &symbol_extern_lastP); + symbolP = hold; + } else { + if (SF_GET_STRING(symbolP)) { + symbolP->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(symbolP)) + 1; + } else { + symbolP->sy_name_offset = 0; + } /* fix "long" names */ + + symbolP->sy_number = symbol_number; + symbol_number += 1 + S_GET_NUMBER_AUXILIARY(symbolP); + } /* if local symbol */ + } /* traverse the symbol list */ + return symbol_number; + +} + + +static unsigned int DEFUN_VOID(glue_symbols) +{ + unsigned int symbol_number = 0; + symbolS *symbolP; + for (symbolP = symbol_externP; symbol_externP;) { + symbolS *tmp = symbol_externP; + + /* append */ + symbol_remove(tmp, &symbol_externP, &symbol_extern_lastP); + symbol_append(tmp, symbol_lastP, &symbol_rootP, &symbol_lastP); + + /* and process */ + if (SF_GET_STRING(tmp)) { + tmp->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(tmp)) + 1; + } else { + tmp->sy_name_offset = 0; + } /* fix "long" names */ + + tmp->sy_number = symbol_number; + symbol_number += 1 + S_GET_NUMBER_AUXILIARY(tmp); + } /* append the entire extern chain */ + return symbol_number; + +} + +static unsigned int DEFUN_VOID(tie_tags) +{ + unsigned int symbol_number = 0; + + symbolS*symbolP; + for (symbolP = symbol_rootP; symbolP; symbolP = + symbol_next(symbolP)) + { + symbolP->sy_number = symbol_number; + + + + if (SF_GET_TAGGED(symbolP)) + { + SA_SET_SYM_TAGNDX + (symbolP, + ((symbolS*) SA_GET_SYM_TAGNDX(symbolP))->sy_number); + } + + symbol_number += 1 + S_GET_NUMBER_AUXILIARY(symbolP); + } + return symbol_number; + +} + +static void + DEFUN(crawl_symbols,(headers, abfd), + struct internal_filehdr *headers AND + bfd *abfd) +{ + + unsigned int i; + unsigned int ptr = 0; + + + symbolS *symbolP; + + /* Initialize the stack used to keep track of the matching .bb .be */ + + block_stack = stack_init(512, sizeof(symbolS*)); + /* JF deal with forward references first... */ + for (symbolP = symbol_rootP; + symbolP; + symbolP = symbol_next(symbolP)) + { + + if (symbolP->sy_forward) { + S_SET_VALUE(symbolP, (S_GET_VALUE(symbolP) + + S_GET_VALUE(symbolP->sy_forward) + + symbolP->sy_forward->sy_frag->fr_address)); + + if (SF_GET_GET_SEGMENT(symbolP)) { + S_SET_SEGMENT(symbolP, S_GET_SEGMENT(symbolP->sy_forward)); + } /* forward segment also */ + + symbolP->sy_forward=0; + } /* if it has a forward reference */ + } /* walk the symbol chain */ + + + /* The symbol list should be ordered according to the following sequence + * order : + * . .file symbol + * . debug entries for functions + * . fake symbols for the sections, including.text .data and .bss + * . defined symbols + * . undefined symbols + * But this is not mandatory. The only important point is to put the + * undefined symbols at the end of the list. + */ + + if (symbol_rootP == NULL + || S_GET_STORAGE_CLASS(symbol_rootP) != C_FILE) { + c_dot_file_symbol("fake"); + } + /* Is there a .file symbol ? If not insert one at the beginning. */ + + /* + * Build up static symbols for the sections, they are filled in later + */ + + + for (i = SEG_E0; i < SEG_E9; i++) + { + if (segment_info[i].scnhdr.s_name[0]) + { + segment_info[i].dot = + c_section_symbol(segment_info[i].scnhdr.s_name, + i-SEG_E0+1); + + } + } + + + /* Take all the externals out and put them into another chain */ + headers->f_nsyms = yank_symbols(); + /* Take the externals and glue them onto the end.*/ + headers->f_nsyms += glue_symbols(); + + headers->f_nsyms = tie_tags(); + know(symbol_externP == NULL); + know(symbol_extern_lastP == NULL); + + return; +} + +/* + * Find strings by crawling along symbol table chain. + */ + +void DEFUN(w_strings,(where), + char *where) +{ + symbolS *symbolP; + + /* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */ + md_number_to_chars(where, string_byte_count, sizeof(string_byte_count)); + where += sizeof(string_byte_count); + for (symbolP = symbol_rootP; + symbolP; + symbolP = symbol_next(symbolP)) + { + unsigned int size; + + if (SF_GET_STRING(symbolP)) { + size = strlen(S_GET_NAME(symbolP)) + 1; + + memcpy(where, S_GET_NAME(symbolP),size); + where += size; + + } + } + +} + + + + + +static void + DEFUN(do_linenos_for,(abfd, file_cursor), + bfd *abfd AND + unsigned long *file_cursor) +{ + unsigned int idx; + + for (idx = SEG_E0; idx < SEG_E9; idx++) + { + segment_info_type *s = segment_info + idx; + + + if (s->scnhdr.s_nlnno != 0) + { + struct lineno_list *line_ptr ; + + struct external_lineno *buffer = + (struct external_lineno *)xmalloc(s->scnhdr.s_nlnno * LINESZ); + + struct external_lineno *dst= buffer; + + /* Run through the table we've built and turn it into its external + form, take this chance to remove duplicates */ + + for (line_ptr = s->lineno_list_head; + line_ptr != (struct lineno_list *)NULL; + line_ptr = line_ptr->next) + { + + if (line_ptr->line.l_lnno == 0) + { + /* Turn a pointer to a symbol into the symbols' index */ + line_ptr->line.l_addr.l_symndx = + ( (symbolS *)line_ptr->line.l_addr.l_symndx)->sy_number; + } + else + { + line_ptr->line.l_addr.l_paddr += ((struct frag * )(line_ptr->frag))->fr_address; + } + + + (void) bfd_coff_swap_lineno_out(abfd, &(line_ptr->line), dst); + dst++; + + } + + s->scnhdr.s_lnnoptr = *file_cursor; + + bfd_write(buffer, 1, s->scnhdr.s_nlnno* LINESZ, abfd); + free(buffer); + + *file_cursor += s->scnhdr.s_nlnno * LINESZ; + } + } +} + + +/* Now we run through the list of frag chains in a segment and + make all the subsegment frags appear at the end of the + list, as if the seg 0 was extra long */ + +static void DEFUN_VOID(remove_subsegs) +{ + unsigned int i; + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + frchainS *head = segment_info[i].frchainP; + fragS dummy; + fragS * prev_frag = &dummy; + + while (head && head->frch_seg == i) + { + prev_frag->fr_next = head->frch_root; + prev_frag = head->frch_last; + head = head->frch_next; + } + prev_frag->fr_next = 0; + } +} + + +extern void DEFUN_VOID(write_object_file) +{ + int i; + struct frchain *frchain_ptr; + + struct internal_filehdr filehdr; + struct internal_aouthdr aouthdr; + unsigned long file_cursor; + bfd *abfd; + unsigned int addr = 0; + abfd = bfd_openw(out_file_name, TARGET_FORMAT); + + + if (abfd == 0) { + as_perror ("FATAL: Can't create %s", out_file_name); + exit(42); + } + bfd_set_format(abfd, bfd_object); + bfd_set_arch_mach(abfd, BFD_ARCH, 0); + + + + string_byte_count = 4; + + for (frchain_ptr = frchain_root; + frchain_ptr != (struct frchain *)NULL; + frchain_ptr = frchain_ptr->frch_next) { + /* Run through all the sub-segments and align them up. Also close any + open frags. We tack a .fill onto the end of the frag chain so + that any .align's size can be worked by looking at the next + frag */ + + subseg_new(frchain_ptr->frch_seg, frchain_ptr->frch_subseg); +#define SUB_SEGMENT_ALIGN 1 + frag_align(SUB_SEGMENT_ALIGN,0); + frag_wane(frag_now); + frag_now->fr_fix = 0; + know( frag_now->fr_next == NULL ); + } + + + remove_subsegs(); + + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + relax_segment(segment_info[i].frchainP->frch_root, i); + } + + + + + + filehdr.f_nscns = 0; + + /* Find out how big the sections are */ + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + + if (segment_info[i].scnhdr.s_name[0]) + { + filehdr.f_nscns++; + } + segment_info[i].scnhdr.s_paddr = addr; + if (i == SEG_E2) { + /* THis is a special case, we leave the size alone, which will have */ + /* been made up from all and any lcomms seen */ + } + else { + addr += size_section(abfd, i); + } + } + + + + /* Turn the gas native symbol table shape into a coff symbol table */ + crawl_symbols(&filehdr, abfd); +#ifndef TC_H8300 + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + fixup_segment(segment_info[i].fix_root, i); + } +#endif + + file_cursor = FILHSZ + SCNHSZ * filehdr.f_nscns ; + + bfd_seek(abfd, file_cursor, 0); + + + do_relocs_for(abfd, &file_cursor); + + do_linenos_for(abfd, &file_cursor); + + + /* Plant the data */ + + fill_section(abfd,&filehdr, &file_cursor); + + filehdr.f_magic = COFF_MAGIC; + filehdr.f_timdat = 0; + filehdr.f_flags = 0; + + + + { + + unsigned int symtable_size = filehdr.f_nsyms * SYMESZ; + char *buffer1 = malloc(symtable_size + string_byte_count + 4); + char *ptr = buffer1; + filehdr.f_symptr = bfd_tell(abfd); + w_symbols(abfd, buffer1, symbol_rootP); + w_strings(buffer1 + symtable_size); + bfd_write(buffer1, 1,symtable_size + string_byte_count + 4, abfd); + free(buffer1); + + } + coff_header_append(abfd, &filehdr, &aouthdr); + + bfd_close_all_done(abfd); +} + + +static void DEFUN(change_to_section,(name, len, exp), + char *name AND + unsigned int len AND + unsigned int exp) +{ + unsigned int i; + /* Find out if we've already got a section of this name etc */ + for (i = SEG_E0; i < SEG_E9 && segment_info[i].scnhdr.s_name[0] ; i++) + { + if (strncmp(segment_info[i].scnhdr.s_name, name, len) == 0) + { + subseg_new(i, exp); + return; + + } + } + /* No section, add one */ + strncpy(segment_info[i].scnhdr.s_name, name, 8); + subseg_new(i, exp); +} + +static void + DEFUN_VOID(obj_coff_section) +{ + /* Strip out the section name */ + char *section_name ; + char *section_name_end; + char c; + + unsigned int len; + unsigned int exp; + + section_name = input_line_pointer; + c = get_symbol_end(); + section_name_end = input_line_pointer; + + len = section_name_end - section_name ; + input_line_pointer++; + SKIP_WHITESPACE(); + if (c == ',') + { + exp = get_absolute_expression(); + } + else if ( *input_line_pointer == ',') + { + + input_line_pointer++; + exp = get_absolute_expression(); + } + else + { + exp = 0; + } + + change_to_section(section_name, len,exp); + *section_name_end = c; + +} + + +static void obj_coff_text() +{ + change_to_section(".text",5, get_absolute_expression()); +} + + +static void obj_coff_data() +{ + change_to_section(".data",5, get_absolute_expression()); +} + +void c_symbol_merge(debug, normal) +symbolS *debug; +symbolS *normal; +{ + S_SET_DATA_TYPE(normal, S_GET_DATA_TYPE(debug)); + S_SET_STORAGE_CLASS(normal, S_GET_STORAGE_CLASS(debug)); + + if (S_GET_NUMBER_AUXILIARY(debug) > S_GET_NUMBER_AUXILIARY(normal)) { + S_SET_NUMBER_AUXILIARY(normal, S_GET_NUMBER_AUXILIARY(debug)); + } /* take the most we have */ + + if (S_GET_NUMBER_AUXILIARY(debug) > 0) { + memcpy((char*)&normal->sy_symbol.ost_auxent[0], (char*)&debug->sy_symbol.ost_auxent[0], S_GET_NUMBER_AUXILIARY(debug) * AUXESZ); + } /* Move all the auxiliary information */ + + /* Move the debug flags. */ + SF_SET_DEBUG_FIELD(normal, SF_GET_DEBUG_FIELD(debug)); +} /* c_symbol_merge() */ + +static int + DEFUN(c_line_new,(symbol, paddr, line_number, frag), + symbolS *symbol AND + long paddr AND + unsigned short line_number AND + fragS* frag) +{ + struct lineno_list* new_line = + (struct lineno_list *)xmalloc(sizeof(struct lineno_list)); + + segment_info_type *s = segment_info + now_seg; + new_line->line.l_lnno = line_number; + + if (line_number == 0) + { + new_line->line.l_addr.l_symndx = (long)symbol; + } + else + { + new_line->line.l_addr.l_paddr = paddr; + } + + new_line->frag = (char*)frag; + new_line->next = (struct lineno_list*)NULL; + + + if (s->lineno_list_head == (struct lineno_list *)NULL) + { + s->lineno_list_head = new_line; + } + else + { + s->lineno_list_tail->next = new_line; + } + s->lineno_list_tail = new_line; + return LINESZ * s->scnhdr.s_nlnno ++; +} + +void c_dot_file_symbol(filename) +char *filename; +{ + symbolS* symbolP; + + symbolP = symbol_new(".file", + SEG_DEBUG, + 0, + &zero_address_frag); + + S_SET_STORAGE_CLASS(symbolP, C_FILE); + S_SET_NUMBER_AUXILIARY(symbolP, 1); + SA_SET_FILE_FNAME(symbolP, filename); +#ifndef NO_LISTING + { + extern int listing; + if (listing) + { + listing_source_file(filename); + } + + } + +#endif + SF_SET_DEBUG(symbolP); + S_SET_VALUE(symbolP, (long) previous_file_symbol); + + previous_file_symbol = symbolP; + + /* Make sure that the symbol is first on the symbol chain */ + if (symbol_rootP != symbolP) { + if (symbolP == symbol_lastP) { + symbol_lastP = symbol_lastP->sy_previous; + } /* if it was the last thing on the list */ + + symbol_remove(symbolP, &symbol_rootP, &symbol_lastP); + symbol_insert(symbolP, symbol_rootP, &symbol_rootP, &symbol_lastP); + symbol_rootP = symbolP; + } /* if not first on the list */ + +} /* c_dot_file_symbol() */ + +/* + * Build a 'section static' symbol. + */ + +symbolS *c_section_symbol(name,idx) +char *name; +int idx; +{ + symbolS *symbolP; + + symbolP = symbol_new(name,idx, + 0, + &zero_address_frag); + + S_SET_STORAGE_CLASS(symbolP, C_STAT); + S_SET_NUMBER_AUXILIARY(symbolP, 1); + + SF_SET_STATICS(symbolP); + + return symbolP; +} /* c_section_symbol() */ + +static void + DEFUN(w_symbols,(abfd, where, symbol_rootP), + bfd *abfd AND + char *where AND + symbolS *symbol_rootP) +{ + symbolS *symbolP; + unsigned int i; + + /* First fill in those values we have only just worked out */ + for (i = SEG_E0; i < SEG_E9; i++) + { + symbolP = segment_info[i].dot; + if (symbolP) + { + + SA_SET_SCN_SCNLEN(symbolP, segment_info[i].scnhdr.s_size); + SA_SET_SCN_NRELOC(symbolP, segment_info[i].scnhdr.s_nreloc); + SA_SET_SCN_NLINNO(symbolP, segment_info[i].scnhdr.s_nlnno); + + } + } + + /* + * Emit all symbols left in the symbol chain. + */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + /* Used to save the offset of the name. It is used to point + to the string in memory but must be a file offset. */ + register char * temp; + + tc_coff_symbol_emit_hook(symbolP); + + temp = S_GET_NAME(symbolP); + if (SF_GET_STRING(symbolP)) { + S_SET_OFFSET(symbolP, symbolP->sy_name_offset); + S_SET_ZEROES(symbolP, 0); + } else { + memset(symbolP->sy_symbol.ost_entry.n_name, '\0', SYMNMLEN); + strncpy(symbolP->sy_symbol.ost_entry.n_name, temp, SYMNMLEN); + } + where = symbol_to_chars(abfd, where, symbolP); + S_SET_NAME(symbolP,temp); + } + +} /* w_symbols() */ + +static void DEFUN_VOID(obj_coff_lcomm) +{ + char *name; + char c; + int temp; + char *p; + symbolS *symbolP; + name = input_line_pointer; + + + + c = get_symbol_end(); + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE(); + if (*input_line_pointer != ',') { + as_bad("Expected comma after name"); + ignore_rest_of_line(); + return; + } + if (*input_line_pointer == '\n') { + as_bad("Missing size expression"); + return; + } + input_line_pointer++; + if ((temp = get_absolute_expression ()) < 0) { + as_warn("lcomm length (%d.) <0! Ignored.", temp); + ignore_rest_of_line(); + return; + } + *p = 0; + symbolP = symbol_find_or_make(name); + S_SET_VALUE(symbolP, segment_info[SEG_E2].scnhdr.s_size); + S_SET_SEGMENT(symbolP, SEG_E2); + segment_info[SEG_E2].scnhdr.s_size += temp; + S_SET_STORAGE_CLASS(symbolP, C_STAT); + demand_empty_rest_of_line(); +} + + +#if 1 +static void DEFUN(fixup_segment,(fixP, this_segment_type), + register fixS * fixP AND + segT this_segment_type) +{ + register symbolS *add_symbolP; + register symbolS *sub_symbolP; + register long add_number; + register int size; + register char *place; + register long where; + register char pcrel; + register fragS *fragP; + register segT add_symbol_segment = SEG_ABSOLUTE; + + + for ( ; fixP; fixP = fixP->fx_next) + { + fragP = fixP->fx_frag; + know(fragP); + where = fixP->fx_where; + place = fragP->fr_literal + where; + size = fixP->fx_size; + add_symbolP = fixP->fx_addsy; +#ifdef TC_I960 + if (fixP->fx_callj && TC_S_IS_CALLNAME(add_symbolP)) { + /* Relocation should be done via the + associated 'bal' entry point + symbol. */ + + if (!TC_S_IS_BALNAME(tc_get_bal_of_call(add_symbolP))) { + as_bad("No 'bal' entry point for leafproc %s", + S_GET_NAME(add_symbolP)); + continue; + } + fixP->fx_addsy = add_symbolP = tc_get_bal_of_call(add_symbolP); + } /* callj relocation */ +#endif + sub_symbolP = fixP->fx_subsy; + add_number = fixP->fx_offset; + pcrel = fixP->fx_pcrel; + + if (add_symbolP) { + add_symbol_segment = S_GET_SEGMENT(add_symbolP); + } /* if there is an addend */ + + if (sub_symbolP) { + if (!add_symbolP) { + /* Its just -sym */ + if (S_GET_SEGMENT(sub_symbolP) != SEG_ABSOLUTE) { + as_bad("Negative of non-absolute symbol %s", S_GET_NAME(sub_symbolP)); + } /* not absolute */ + + add_number -= S_GET_VALUE(sub_symbolP); + + /* if sub_symbol is in the same segment that add_symbol + and add_symbol is either in DATA, TEXT, BSS or ABSOLUTE */ + } else if ((S_GET_SEGMENT(sub_symbolP) == add_symbol_segment) + && (SEG_NORMAL(add_symbol_segment) + || (add_symbol_segment == SEG_ABSOLUTE))) { + /* Difference of 2 symbols from same segment. */ + /* Can't make difference of 2 undefineds: 'value' means */ + /* something different for N_UNDF. */ +#ifdef TC_I960 + /* Makes no sense to use the difference of 2 arbitrary symbols + * as the target of a call instruction. + */ + if (fixP->fx_callj) { + as_bad("callj to difference of 2 symbols"); + } +#endif /* TC_I960 */ + add_number += S_GET_VALUE(add_symbolP) - + S_GET_VALUE(sub_symbolP); + + add_symbolP = NULL; + fixP->fx_addsy = NULL; + } else { + /* Different segments in subtraction. */ + know(!(S_IS_EXTERNAL(sub_symbolP) && (S_GET_SEGMENT(sub_symbolP) == SEG_ABSOLUTE))); + + if ((S_GET_SEGMENT(sub_symbolP) == SEG_ABSOLUTE)) { + add_number -= S_GET_VALUE(sub_symbolP); + } else { + as_bad("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %d.", + segment_name(S_GET_SEGMENT(sub_symbolP)), + S_GET_NAME(sub_symbolP), fragP->fr_address + where); + } /* if absolute */ + } + } /* if sub_symbolP */ + + if (add_symbolP) { + if (add_symbol_segment == this_segment_type && pcrel) { + /* + * This fixup was made when the symbol's segment was + * SEG_UNKNOWN, but it is now in the local segment. + * So we know how to do the address without relocation. + */ +#ifdef TC_I960 + /* reloc_callj() may replace a 'call' with a 'calls' or a 'bal', + * in which cases it modifies *fixP as appropriate. In the case + * of a 'calls', no further work is required, and *fixP has been + * set up to make the rest of the code below a no-op. + */ + reloc_callj(fixP); +#endif /* TC_I960 */ + + add_number += S_GET_VALUE(add_symbolP); + add_number -= md_pcrel_from (fixP); + pcrel = 0; /* Lie. Don't want further pcrel processing. */ + fixP->fx_addsy = NULL; /* No relocations please. */ + } else + { + switch (add_symbol_segment) + { + case SEG_ABSOLUTE: +#ifdef TC_I960 + reloc_callj(fixP); /* See comment about reloc_callj() above*/ +#endif /* TC_I960 */ + add_number += S_GET_VALUE(add_symbolP); + fixP->fx_addsy = NULL; + add_symbolP = NULL; + break; + default: + + add_number += S_GET_VALUE(add_symbolP) + + segment_info[S_GET_SEGMENT(add_symbolP)].scnhdr.s_paddr ; + break; + + case SEG_UNKNOWN: +#ifdef TC_I960 + if ((int)fixP->fx_bit_fixP == 13) { + /* This is a COBR instruction. They have only a + * 13-bit displacement and are only to be used + * for local branches: flag as error, don't generate + * relocation. + */ + as_bad("can't use COBR format with external label"); + fixP->fx_addsy = NULL; /* No relocations please. */ + continue; + } /* COBR */ +#endif /* TC_I960 */ + + + + break; + + + } /* switch on symbol seg */ + } /* if not in local seg */ + } /* if there was a + symbol */ + + if (pcrel) { + add_number -= md_pcrel_from(fixP); + if (add_symbolP == 0) { + fixP->fx_addsy = & abs_symbol; + } /* if there's an add_symbol */ + } /* if pcrel */ + + if (!fixP->fx_bit_fixP) { + if ((size == 1 + && (add_number & ~0xFF) && (add_number & ~0xFF != (-1 & ~0xFF))) || + (size == 2 + && (add_number & ~0xFFFF) && (add_number & ~0xFFFF != (-1 & ~0xFFFF)))) { + as_bad("Value of %d too large for field of %d bytes at 0x%x", + add_number, size, fragP->fr_address + where); + } /* generic error checking */ + } /* not a bit fix */ + /* once this fix has been applied, we don't have to output anything + nothing more need be done -*/ + md_apply_fix(fixP, add_number); + + } /* For each fixS in this segment. */ + + +} /* fixup_segment() */ +#endif + +/* + * Local Variables: + * fill-column: 131 + * End: + */ + +/* end of obj-coffbfd.c */ diff --git a/gnu/usr.bin/as/config/obj-coffbfd.h b/gnu/usr.bin/as/config/obj-coffbfd.h new file mode 100644 index 000000000000..d1afabb24b07 --- /dev/null +++ b/gnu/usr.bin/as/config/obj-coffbfd.h @@ -0,0 +1,516 @@ +/* coff object file format + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef OBJ_FORMAT_H +#define OBJ_FORMAT_H + +#define OBJ_COFF 1 + +#include "targ-cpu.h" + +#include "bfd.h" + +/*extern bfd *stdoutput;*/ +/* This internal_lineno crap is to stop namespace pollution from the + bfd internal coff headerfile. */ + +#define internal_lineno bfd_internal_lineno +#include "coff/internal.h" +#undef internal_lineno + +#if defined(TC_H8300) +#include "coff/h8300.h" +#define TARGET_FORMAT "coff-h8300" +#elif defined(TC_A29K) +#include "coff/a29k.h" +#define TARGET_FORMAT "coff-a29k-big" +#else +help me +#endif + +#if 0 + /* Define some processor dependent values according to the processor we are + on. */ +#if defined(TC_H8300) +#define BYTE_ORDERING 0 +#define FILE_HEADER_MAGIC H8300MAGIC +#elif defined(TC_M68K) + +#define BYTE_ORDERING F_AR32W /* See filehdr.h for more info. */ +#ifndef FILE_HEADER_MAGIC +#define FILE_HEADER_MAGIC MC68MAGIC /* ... */ +#endif /* FILE_HEADER_MAGIC */ + +#elif defined(TC_I386) + +#define BYTE_ORDERING F_AR32WR /* See filehdr.h for more info. */ +#ifndef FILE_HEADER_MAGIC +#define FILE_HEADER_MAGIC I386MAGIC /* ... */ +#endif /* FILE_HEADER_MAGIC */ + +#elif defined(TC_I960) + +#define BYTE_ORDERING F_AR32WR /* See filehdr.h for more info. */ +#ifndef FILE_HEADER_MAGIC +#define FILE_HEADER_MAGIC I960ROMAGIC /* ... */ +#endif /* FILE_HEADER_MAGIC */ + +#elif defined(TC_A29K) + +#define BYTE_ORDERING F_AR32W /* big endian. */ +#ifndef FILE_HEADER_MAGIC +#define FILE_HEADER_MAGIC SIPFBOMAGIC +#endif /* FILE_HEADER_MAGIC */ + +#else +you lose +#endif + +#endif + +#ifndef OBJ_COFF_MAX_AUXENTRIES +#define OBJ_COFF_MAX_AUXENTRIES 1 +#endif /* OBJ_COFF_MAX_AUXENTRIES */ + + + extern const segT N_TYPE_seg[]; + +/* Magic number of paged executable. */ +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE 0x8300 + + +/* SYMBOL TABLE */ + +/* targets may also set this */ +#ifndef SYMBOLS_NEED_BACKPOINTERS +#define SYMBOLS_NEED_BACKPOINTERS 1 +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + +/* Symbol table entry data type */ + +typedef struct +{ + struct internal_syment ost_entry; /* Basic symbol */ + union internal_auxent ost_auxent[OBJ_COFF_MAX_AUXENTRIES]; /* Auxiliary entry. */ + + unsigned int ost_flags; /* obj_coff internal use only flags */ +} obj_symbol_type; + +#ifndef DO_NOT_STRIP +#define DO_NOT_STRIP 0 +#define DO_STRIP 1 +#endif +/* Symbol table macros and constants */ + +/* Possible and usefull section number in symbol table + * The values of TEXT, DATA and BSS may not be portable. + */ + +#define C_ABS_SECTION N_ABS +#define C_UNDEF_SECTION N_UNDEF +#define C_DEBUG_SECTION N_DEBUG +#define C_NTV_SECTION N_TV +#define C_PTV_SECTION P_TV +#define C_REGISTER_SECTION 20 + +/* + * Macros to extract information from a symbol table entry. + * This syntaxic indirection allows independence regarding a.out or coff. + * The argument (s) of all these macros is a pointer to a symbol table entry. + */ + +/* Predicates */ +/* True if the symbol is external */ +#define S_IS_EXTERNAL(s) ((s)->sy_symbol.ost_entry.n_scnum == C_UNDEF_SECTION) +/* True if symbol has been defined, ie : + section > 0 (DATA, TEXT or BSS) + section == 0 and value > 0 (external bss symbol) */ +#define S_IS_DEFINED(s) ((s)->sy_symbol.ost_entry.n_scnum > C_UNDEF_SECTION || \ + ((s)->sy_symbol.ost_entry.n_scnum == C_UNDEF_SECTION && \ + (s)->sy_symbol.ost_entry.n_value > 0)) +/* True if a debug special symbol entry */ +#define S_IS_DEBUG(s) ((s)->sy_symbol.ost_entry.n_scnum == C_DEBUG_SECTION) +/* True if a symbol is local symbol name */ +/* A symbol name whose name begin with ^A is a gas internal pseudo symbol */ +#define S_IS_LOCAL(s) (S_GET_NAME(s)[0] == '\001' || \ + (s)->sy_symbol.ost_entry.n_scnum == C_REGISTER_SECTION || \ + (S_LOCAL_NAME(s) && !flagseen['L'])) +/* True if a symbol is not defined in this file */ +#define S_IS_EXTERN(s) ((s)->sy_symbol.ost_entry.n_scnum == 0 && (s)->sy_symbol.ost_entry.n_value == 0) +/* + * True if a symbol can be multiply defined (bss symbols have this def + * though it is bad practice) + */ +#define S_IS_COMMON(s) ((s)->sy_symbol.ost_entry.n_scnum == 0 && (s)->sy_symbol.ost_entry.n_value != 0) +/* True if a symbol name is in the string table, i.e. its length is > 8. */ +#define S_IS_STRING(s) (strlen(S_GET_NAME(s)) > 8 ? 1 : 0) + +/* Accessors */ +/* The name of the symbol */ +#define S_GET_NAME(s) ((char*)(s)->sy_symbol.ost_entry.n_offset) +/* The pointer to the string table */ +#define S_GET_OFFSET(s) ((s)->sy_symbol.ost_entry.n_offset) +/* The zeroes if symbol name is longer than 8 chars */ +#define S_GET_ZEROES(s) ((s)->sy_symbol.ost_entry.n_zeroes) +/* The value of the symbol */ +#define S_GET_VALUE(s) ((unsigned) ((s)->sy_symbol.ost_entry.n_value)) +/* The numeric value of the segment */ +#define S_GET_SEGMENT(s) s_get_segment(s) +/* The data type */ +#define S_GET_DATA_TYPE(s) ((s)->sy_symbol.ost_entry.n_type) +/* The storage class */ +#define S_GET_STORAGE_CLASS(s) ((s)->sy_symbol.ost_entry.n_sclass) +/* The number of auxiliary entries */ +#define S_GET_NUMBER_AUXILIARY(s) ((s)->sy_symbol.ost_entry.n_numaux) + +/* Modifiers */ +/* Set the name of the symbol */ +#define S_SET_NAME(s,v) ((s)->sy_symbol.ost_entry.n_offset = (unsigned long)(v)) +/* Set the offset of the symbol */ +#define S_SET_OFFSET(s,v) ((s)->sy_symbol.ost_entry.n_offset = (v)) +/* The zeroes if symbol name is longer than 8 chars */ +#define S_SET_ZEROES(s,v) ((s)->sy_symbol.ost_entry.n_zeroes = (v)) +/* Set the value of the symbol */ +#define S_SET_VALUE(s,v) ((s)->sy_symbol.ost_entry.n_value = (v)) +/* The numeric value of the segment */ +#define S_SET_SEGMENT(s,v) ((s)->sy_symbol.ost_entry.n_scnum = SEGMENT_TO_SYMBOL_TYPE(v)) +/* The data type */ +#define S_SET_DATA_TYPE(s,v) ((s)->sy_symbol.ost_entry.n_type = (v)) +/* The storage class */ +#define S_SET_STORAGE_CLASS(s,v) ((s)->sy_symbol.ost_entry.n_sclass = (v)) +/* The number of auxiliary entries */ +#define S_SET_NUMBER_AUXILIARY(s,v) ((s)->sy_symbol.ost_entry.n_numaux = (v)) + +/* Additional modifiers */ +/* The symbol is external (does not mean undefined) */ +#define S_SET_EXTERNAL(s) { S_SET_STORAGE_CLASS(s, C_EXT) ; SF_CLEAR_LOCAL(s); } + +/* Auxiliary entry macros. SA_ stands for symbol auxiliary */ +/* Omit the tv related fields */ +/* Accessors */ +#ifdef BFD_HEADERS +#define SA_GET_SYM_TAGNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx.l) +#else +#define SA_GET_SYM_TAGNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx) +#endif +#define SA_GET_SYM_LNNO(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_lnno) +#define SA_GET_SYM_SIZE(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_size) +#define SA_GET_SYM_FSIZE(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_fsize) +#define SA_GET_SYM_LNNOPTR(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr) +#ifdef BFD_HEADERS +#define SA_GET_SYM_ENDNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx.l) +#else +#define SA_GET_SYM_ENDNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx) +#endif +#define SA_GET_SYM_DIMEN(s,i) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen[(i)]) +#define SA_GET_FILE_FNAME(s) ((s)->sy_symbol.ost_auxent[0].x_file.x_fname) +#define SA_GET_SCN_SCNLEN(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_scnlen) +#define SA_GET_SCN_NRELOC(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nreloc) +#define SA_GET_SCN_NLINNO(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nlinno) + +/* Modifiers */ +#ifdef BFD_HEADERS +#define SA_SET_SYM_TAGNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx.l=(v)) +#else +#define SA_SET_SYM_TAGNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx=(v)) +#endif +#define SA_SET_SYM_LNNO(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_lnno=(v)) +#define SA_SET_SYM_SIZE(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_size=(v)) +#define SA_SET_SYM_FSIZE(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_fsize=(v)) +#define SA_SET_SYM_LNNOPTR(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr=(v)) +#ifdef BFD_HEADERS +#define SA_SET_SYM_ENDNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx.l=(v)) +#else +#define SA_SET_SYM_ENDNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx=(v)) +#endif +#define SA_SET_SYM_DIMEN(s,i,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen[(i)]=(v)) +#define SA_SET_FILE_FNAME(s,v) strncpy((s)->sy_symbol.ost_auxent[0].x_file.x_fname,(v),FILNMLEN) +#define SA_SET_SCN_SCNLEN(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_scnlen=(v)) +#define SA_SET_SCN_NRELOC(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nreloc=(v)) +#define SA_SET_SCN_NLINNO(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nlinno=(v)) + +/* + * Internal use only definitions. SF_ stands for symbol flags. + * + * These values can be assigned to sy_symbol.ost_flags field of a symbolS. + * + * You'll break i960 if you shift the SYSPROC bits anywhere else. for + * more on the balname/callname hack, see tc-i960.h. b.out is done + * differently. + */ + +#define SF_I960_MASK (0x000001ff) /* Bits 0-8 are used by the i960 port. */ +#define SF_SYSPROC (0x0000003f) /* bits 0-5 are used to store the sysproc number */ +#define SF_IS_SYSPROC (0x00000040) /* bit 6 marks symbols that are sysprocs */ +#define SF_BALNAME (0x00000080) /* bit 7 marks BALNAME symbols */ +#define SF_CALLNAME (0x00000100) /* bit 8 marks CALLNAME symbols */ + +#define SF_NORMAL_MASK (0x0000ffff) /* bits 12-15 are general purpose. */ + +#define SF_STATICS (0x00001000) /* Mark the .text & all symbols */ +#define SF_DEFINED (0x00002000) /* Symbol is defined in this file */ +#define SF_STRING (0x00004000) /* Symbol name length > 8 */ +#define SF_LOCAL (0x00008000) /* Symbol must not be emitted */ + +#define SF_DEBUG_MASK (0xffff0000) /* bits 16-31 are debug info */ + +#define SF_FUNCTION (0x00010000) /* The symbol is a function */ +#define SF_PROCESS (0x00020000) /* Process symbol before write */ +#define SF_TAGGED (0x00040000) /* Is associated with a tag */ +#define SF_TAG (0x00080000) /* Is a tag */ +#define SF_DEBUG (0x00100000) /* Is in debug or abs section */ +#define SF_GET_SEGMENT (0x00200000) /* Get the section of the forward symbol. */ +/* All other bits are unused. */ + +/* Accessors */ +#define SF_GET(s) ((s)->sy_symbol.ost_flags) +#define SF_GET_NORMAL_FIELD(s) ((s)->sy_symbol.ost_flags & SF_NORMAL_MASK) +#define SF_GET_DEBUG_FIELD(s) ((s)->sy_symbol.ost_flags & SF_DEBUG_MASK) +#define SF_GET_FILE(s) ((s)->sy_symbol.ost_flags & SF_FILE) +#define SF_GET_STATICS(s) ((s)->sy_symbol.ost_flags & SF_STATICS) +#define SF_GET_DEFINED(s) ((s)->sy_symbol.ost_flags & SF_DEFINED) +#define SF_GET_STRING(s) ((s)->sy_symbol.ost_flags & SF_STRING) +#define SF_GET_LOCAL(s) ((s)->sy_symbol.ost_flags & SF_LOCAL) +#define SF_GET_FUNCTION(s) ((s)->sy_symbol.ost_flags & SF_FUNCTION) +#define SF_GET_PROCESS(s) ((s)->sy_symbol.ost_flags & SF_PROCESS) +#define SF_GET_DEBUG(s) ((s)->sy_symbol.ost_flags & SF_DEBUG) +#define SF_GET_TAGGED(s) ((s)->sy_symbol.ost_flags & SF_TAGGED) +#define SF_GET_TAG(s) ((s)->sy_symbol.ost_flags & SF_TAG) +#define SF_GET_GET_SEGMENT(s) ((s)->sy_symbol.ost_flags & SF_GET_SEGMENT) +#define SF_GET_I960(s) ((s)->sy_symbol.ost_flags & SF_I960_MASK) /* used by i960 */ +#define SF_GET_BALNAME(s) ((s)->sy_symbol.ost_flags & SF_BALNAME) /* used by i960 */ +#define SF_GET_CALLNAME(s) ((s)->sy_symbol.ost_flags & SF_CALLNAME) /* used by i960 */ +#define SF_GET_IS_SYSPROC(s) ((s)->sy_symbol.ost_flags & SF_IS_SYSPROC) /* used by i960 */ +#define SF_GET_SYSPROC(s) ((s)->sy_symbol.ost_flags & SF_SYSPROC) /* used by i960 */ + +/* Modifiers */ +#define SF_SET(s,v) ((s)->sy_symbol.ost_flags = (v)) +#define SF_SET_NORMAL_FIELD(s,v)((s)->sy_symbol.ost_flags |= ((v) & SF_NORMAL_MASK)) +#define SF_SET_DEBUG_FIELD(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_DEBUG_MASK)) +#define SF_SET_FILE(s) ((s)->sy_symbol.ost_flags |= SF_FILE) +#define SF_SET_STATICS(s) ((s)->sy_symbol.ost_flags |= SF_STATICS) +#define SF_SET_DEFINED(s) ((s)->sy_symbol.ost_flags |= SF_DEFINED) +#define SF_SET_STRING(s) ((s)->sy_symbol.ost_flags |= SF_STRING) +#define SF_SET_LOCAL(s) ((s)->sy_symbol.ost_flags |= SF_LOCAL) +#define SF_CLEAR_LOCAL(s) ((s)->sy_symbol.ost_flags &= ~SF_LOCAL) +#define SF_SET_FUNCTION(s) ((s)->sy_symbol.ost_flags |= SF_FUNCTION) +#define SF_SET_PROCESS(s) ((s)->sy_symbol.ost_flags |= SF_PROCESS) +#define SF_SET_DEBUG(s) ((s)->sy_symbol.ost_flags |= SF_DEBUG) +#define SF_SET_TAGGED(s) ((s)->sy_symbol.ost_flags |= SF_TAGGED) +#define SF_SET_TAG(s) ((s)->sy_symbol.ost_flags |= SF_TAG) +#define SF_SET_GET_SEGMENT(s) ((s)->sy_symbol.ost_flags |= SF_GET_SEGMENT) +#define SF_SET_I960(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_I960_MASK)) /* used by i960 */ +#define SF_SET_BALNAME(s) ((s)->sy_symbol.ost_flags |= SF_BALNAME) /* used by i960 */ +#define SF_SET_CALLNAME(s) ((s)->sy_symbol.ost_flags |= SF_CALLNAME) /* used by i960 */ +#define SF_SET_IS_SYSPROC(s) ((s)->sy_symbol.ost_flags |= SF_IS_SYSPROC) /* used by i960 */ +#define SF_SET_SYSPROC(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_SYSPROC)) /* used by i960 */ + +/* File header macro and type definition */ + +/* + * File position calculators. Beware to use them when all the + * appropriate fields are set in the header. + */ + +#ifdef OBJ_COFF_OMIT_OPTIONAL_HEADER +#define OBJ_COFF_AOUTHDRSZ (0) +#else +#define OBJ_COFF_AOUTHDRSZ (AOUTHDRSZ) +#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */ + +#define H_GET_FILE_SIZE(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ + H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h) + \ + H_GET_SYMBOL_TABLE_SIZE(h) + \ + (h)->string_table_size) +#define H_GET_TEXT_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ) +#define H_GET_DATA_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h)) +#define H_GET_BSS_FILE_OFFSET(h) 0 +#define H_GET_RELOCATION_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h)) +#define H_GET_LINENO_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ + H_GET_RELOCATION_SIZE(h)) +#define H_GET_SYMBOL_TABLE_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ + H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h)) + +/* Accessors */ +/* aouthdr */ +#define H_GET_MAGIC_NUMBER(h) ((h)->aouthdr.magic) +#define H_GET_VERSION_STAMP(h) ((h)->aouthdr.vstamp) +#define H_GET_TEXT_SIZE(h) ((h)->aouthdr.tsize) +#define H_GET_DATA_SIZE(h) ((h)->aouthdr.dsize) +#define H_GET_BSS_SIZE(h) ((h)->aouthdr.bsize) +#define H_GET_ENTRY_POINT(h) ((h)->aouthdr.entry) +#define H_GET_TEXT_START(h) ((h)->aouthdr.text_start) +#define H_GET_DATA_START(h) ((h)->aouthdr.data_start) +/* filehdr */ +#define H_GET_FILE_MAGIC_NUMBER(h) ((h)->filehdr.f_magic) +#define H_GET_NUMBER_OF_SECTIONS(h) ((h)->filehdr.f_nscns) +#define H_GET_TIME_STAMP(h) ((h)->filehdr.f_timdat) +#define H_GET_SYMBOL_TABLE_POINTER(h) ((h)->filehdr.f_symptr) +#define H_GET_SYMBOL_COUNT(h) ((h)->filehdr.f_nsyms) +#define H_GET_SYMBOL_TABLE_SIZE(h) (H_GET_SYMBOL_COUNT(h) * SYMESZ) +#define H_GET_SIZEOF_OPTIONAL_HEADER(h) ((h)->filehdr.f_opthdr) +#define H_GET_FLAGS(h) ((h)->filehdr.f_flags) +/* Extra fields to achieve bsd a.out compatibility and for convenience */ +#define H_GET_RELOCATION_SIZE(h) ((h)->relocation_size) +#define H_GET_STRING_SIZE(h) ((h)->string_table_size) +#define H_GET_LINENO_SIZE(h) ((h)->lineno_size) + +#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER +#define H_GET_HEADER_SIZE(h) (sizeof(FILHDR) \ + + sizeof(AOUTHDR)\ + + (H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ)) +#else /* OBJ_COFF_OMIT_OPTIONAL_HEADER */ +#define H_GET_HEADER_SIZE(h) (sizeof(FILHDR) \ + + (H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ)) +#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */ + +#define H_GET_TEXT_RELOCATION_SIZE(h) (text_section_header.s_nreloc * RELSZ) +#define H_GET_DATA_RELOCATION_SIZE(h) (data_section_header.s_nreloc * RELSZ) + +/* Modifiers */ +/* aouthdr */ +#define H_SET_MAGIC_NUMBER(h,v) ((h)->aouthdr.magic = (v)) +#define H_SET_VERSION_STAMP(h,v) ((h)->aouthdr.vstamp = (v)) +#define H_SET_TEXT_SIZE(h,v) ((h)->aouthdr.tsize = (v)) +#define H_SET_DATA_SIZE(h,v) ((h)->aouthdr.dsize = (v)) +#define H_SET_BSS_SIZE(h,v) ((h)->aouthdr.bsize = (v)) +#define H_SET_ENTRY_POINT(h,v) ((h)->aouthdr.entry = (v)) +#define H_SET_TEXT_START(h,v) ((h)->aouthdr.text_start = (v)) +#define H_SET_DATA_START(h,v) ((h)->aouthdr.data_start = (v)) +/* filehdr */ +#define H_SET_FILE_MAGIC_NUMBER(h,v) ((h)->filehdr.f_magic = (v)) +#define H_SET_NUMBER_OF_SECTIONS(h,v) ((h)->filehdr.f_nscns = (v)) +#define H_SET_TIME_STAMP(h,v) ((h)->filehdr.f_timdat = (v)) +#define H_SET_SYMBOL_TABLE_POINTER(h,v) ((h)->filehdr.f_symptr = (v)) +#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->filehdr.f_nsyms = (v)) +#define H_SET_SIZEOF_OPTIONAL_HEADER(h,v) ((h)->filehdr.f_opthdr = (v)) +#define H_SET_FLAGS(h,v) ((h)->filehdr.f_flags = (v)) +/* Extra fields to achieve bsd a.out compatibility and for convinience */ +#define H_SET_RELOCATION_SIZE(h,t,d) ((h)->relocation_size = (t)+(d)) +#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v)) +#define H_SET_LINENO_SIZE(h,v) ((h)->lineno_size = (v)) + +/* Segment flipping */ +#define segment_name(v) (seg_name[(int) (v)]) + +typedef struct { +#ifdef BFD_HEADERS + struct internal_aouthdr aouthdr; /* a.out header */ + struct internal_filehdr filehdr; /* File header, not machine dep. */ +#else + AOUTHDR aouthdr; /* a.out header */ + FILHDR filehdr; /* File header, not machine dep. */ +#endif + long string_table_size; /* names + '\0' + sizeof(int) */ + long relocation_size; /* Cumulated size of relocation + information for all sections in + bytes. */ + long lineno_size; /* Size of the line number information + table in bytes */ +} object_headers; + + + +struct lineno_list +{ + + struct bfd_internal_lineno line; + char* frag; /* Frag to which the line number is related */ + struct lineno_list* next; /* Forward chain pointer */ +} ; + + + + +/* stack stuff */ +typedef struct { + unsigned long chunk_size; + unsigned long element_size; + unsigned long size; + char* data; + unsigned long pointer; +} stack; + + + +char *EXFUN(stack_pop,(stack *st)); +char *EXFUN(stack_push,(stack *st, char *element)); +char *EXFUN(stack_top,(stack *st)); +stack *EXFUN(stack_init,(unsigned long chunk_size, unsigned long element_size)); +void EXFUN(c_dot_file_symbol,(char *filename)); +void EXFUN(obj_extra_stuff,(object_headers *headers)); +void EXFUN(stack_delete,(stack *st)); + + + +void EXFUN(c_section_header,( + + struct internal_scnhdr *header, + char *name, + long core_address, + long size, + long data_ptr, + long reloc_ptr, + long lineno_ptr, + long reloc_number, + long lineno_number, + long alignment)); + + +/* sanity check */ + +#ifdef TC_I960 +#ifndef C_LEAFSTAT +hey! Where is the C_LEAFSTAT definition? i960-coff support is depending on it. +#endif /* no C_LEAFSTAT */ +#endif /* TC_I960 */ +#ifdef BFD_HEADERS + extern struct internal_scnhdr data_section_header; +extern struct internal_scnhdr text_section_header; +#else +extern SCNHDR data_section_header; +extern SCNHDR text_section_header; +#endif +#endif + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-coffbfd.h */ diff --git a/gnu/usr.bin/as/config/obj-generic.c b/gnu/usr.bin/as/config/obj-generic.c new file mode 100644 index 000000000000..a91eff9aac73 --- /dev/null +++ b/gnu/usr.bin/as/config/obj-generic.c @@ -0,0 +1,41 @@ +/* This file is obj-generic.c and is intended to be a template for + object format specific source files. + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Chars that can be used to separate mant from exp in floating point nums */ +char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant */ +/* As in 0f12.456 */ +/* or 0d1.2345e12 */ +char FLT_CHARS[] = "rRsSfFdDxXpP"; + +/* These chars start a comment anywhere in a source file (except inside + another comment */ +const char comment_chars[] = "#"; + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-generic.c */ diff --git a/gnu/usr.bin/as/config/obj-generic.h b/gnu/usr.bin/as/config/obj-generic.h new file mode 100644 index 000000000000..f37072268b92 --- /dev/null +++ b/gnu/usr.bin/as/config/obj-generic.h @@ -0,0 +1,78 @@ +/* This file is obj-generic.h + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * This file is obj-generic.h and is intended to be a template for + * object format specific header files. + */ + +/* define an obj specific macro off which target cpu back ends may key. */ +#define OBJ_GENERIC 1 + +/* include whatever target cpu is appropriate. */ +#include "targ-cpu.h" + +/* + * SYMBOLS + */ + +/* + * If your object format needs to reorder symbols, define this. When + * defined, symbols are kept on a doubly linked list and functions are + * made available for push, insert, append, and delete. If not defined, + * symbols are kept on a singly linked list, only the append and clear + * facilities are available, and they are macros. + */ + +/* #define SYMBOLS_NEED_PACKPOINTERS */ + +/* */ +typedef struct { + void *nothing; +} obj_symbol_type; /* should be the format's symbol structure */ + +typedef void *object_headers; + +/* symbols have names */ +#define S_GET_NAME(s) ("foo") /* get the name of a symbolP */ +#define S_SET_NAME(s,v) ; + /* symbols have segments */ +#define S_GET_SEGMENT(s) (SEG_UNKNOWN) +#define S_SET_SEGMENT(s,v) ; + /* symbols have a value */ +#define S_GET_VALUE(s) (0) +#define S_SET_VALUE(s,v) ; + /* symbols may be external */ +#define S_IS_EXTERNAL(s) (0) +#define S_SET_EXTERNAL(s) ; + + /* symbols may or may not be defined */ +#define S_IS_DEFINED(s) (0) + + +#define OBJ_EMIT_LINENO(a,b,c) /* must be *something*. This no-op's it out. */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-generic.h */ diff --git a/gnu/usr.bin/as/config/obj-ieee.c b/gnu/usr.bin/as/config/obj-ieee.c new file mode 100644 index 000000000000..5f74a5f8edfa --- /dev/null +++ b/gnu/usr.bin/as/config/obj-ieee.c @@ -0,0 +1,539 @@ +/* obj-format for ieee-695 records. + Copyright (C) 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* + created by + + steve chamberlain steve@cygnus.com + */ + +/* + this will hopefully become the port through which bfd and gas talk, + for the moment, only ieee is known to work well. + */ + +#include "bfd.h" +#include "as.h" +#include "subsegs.h" +#include "output-file.h" +#include "frags.h" + +bfd *abfd; + +/* How many addresses does the .align take? */ +static relax_addressT relax_align(address, alignment) +register relax_addressT address; /* Address now. */ +register long alignment; /* Alignment (binary). */ +{ + relax_addressT mask; + relax_addressT new_address; + + mask = ~ ( (~0) << alignment ); + new_address = (address + mask) & (~ mask); + return (new_address - address); +} /* relax_align() */ + +/* calculate the size of the frag chain and create a bfd section + to contain all of it */ +static void DEFUN(size_section,(abfd, idx), + bfd *abfd AND + unsigned int idx) +{ + asection *sec; + unsigned int size = 0; + fragS *frag = segment_info[idx].frag_root; + while (frag) { + if (frag->fr_address != size) { + printf("Out of step\n"); + size = frag->fr_address; + } + size += frag->fr_fix; + switch (frag->fr_type) { + case rs_fill: + case rs_org: + size += frag->fr_offset * frag->fr_var; + break; + case rs_align: + size += relax_align(size, frag->fr_offset); + } + frag = frag->fr_next; + } + if (size) { + char *name = segment_info[idx].name; + if (name == (char *)NULL) { + name = ".data"; + } + segment_info[idx].user_stuff = (char *)(sec = bfd_make_section(abfd, name)); + /* Make it output through itself */ + sec->output_section = sec; + sec->flags |= SEC_HAS_CONTENTS; + bfd_set_section_size(abfd, sec, size); + } +} + +/* run through a frag chain and write out the data to go with it */ +static void DEFUN(fill_section,(abfd, idx), + bfd *abfd AND + unsigned int idx) +{ + asection *sec = segment_info[idx].user_stuff; + if (sec) { + fragS *frag = segment_info[idx].frag_root; + unsigned int offset = 0; + while (frag) { + unsigned int fill_size; + unsigned int count; + switch (frag->fr_type) { + case rs_fill: + case rs_align: + case rs_org: + if (frag->fr_fix) + { + bfd_set_section_contents(abfd, + sec, + frag->fr_literal, + frag->fr_address, + frag->fr_fix); + } + offset += frag->fr_fix; + fill_size = frag->fr_var; + if (fill_size) + { + unsigned int off = frag->fr_fix; + for (count = frag->fr_offset; count; count--) + { + bfd_set_section_contents(abfd, sec, + frag->fr_literal + + frag->fr_fix, + frag->fr_address + off, + fill_size); + off += fill_size; + } + } + break; + default: + abort(); + } + frag = frag->fr_next; + } + } +} + +/* Count the relocations in a chain */ + +static unsigned int DEFUN(count_entries_in_chain,(idx), + unsigned int idx) +{ + unsigned int nrelocs; + fixS *fixup_ptr; + + /* Count the relocations */ + fixup_ptr = segment_info[idx].fix_root; + nrelocs = 0; + while (fixup_ptr != (fixS *)NULL) + { + fixup_ptr = fixup_ptr->fx_next; + nrelocs ++ ; + } + return nrelocs; +} + +/* output all the relocations for a section */ +void DEFUN(do_relocs_for,(idx), + unsigned int idx) +{ + unsigned int nrelocs; + arelent **reloc_ptr_vector; + arelent *reloc_vector; + asymbol **ptrs; + asection *section = (asection *)(segment_info[idx].user_stuff); + unsigned int i; + fixS *from; + if (section) { + nrelocs = count_entries_in_chain(idx); + + reloc_ptr_vector = (arelent**)malloc((nrelocs+1) * sizeof(arelent *)); + reloc_vector = (arelent*)malloc(nrelocs * sizeof(arelent)); + ptrs = (asymbol **)malloc(nrelocs * sizeof(asymbol *)); + from = segment_info[idx].fix_root; + for (i = 0; i < nrelocs; i++) + { + arelent *to = reloc_vector + i; + asymbol *s ; + reloc_ptr_vector[i] = to; + to->howto = (reloc_howto_type *)(from->fx_r_type); + + /* We can't represent complicated things in a reloc yet */ + /* if (from->fx_addsy == 0 || + from->fx_subsy != 0) abort(); + */ + s = &( from->fx_addsy->sy_symbol.sy); + to->address = ((char *)( from->fx_frag->fr_address + + from->fx_where)) + - ((char *)(&(from->fx_frag->fr_literal))); + to->addend = from->fx_offset ; + /* If we know the symbol which we want to relocate to, turn this + reloaction into a section relative. + + If this relocation is pcrelative, and we know the + destination, we still want to keep the relocation - since + the linker might relax some of the bytes, but it stops + being pc relative and turns into an absolute relocation. + + */ + if (s) { + if ((s->flags & BSF_UNDEFINED) == 0) { + to->section = s->section; + to->addend += s->value ; + to->sym_ptr_ptr = 0; + if (to->howto->pcrel_offset) { + /* This is a pcrel relocation, the addend should be adjusted */ + to->addend -= to->address +1; + } + } + else { + to->section = 0; + *ptrs = &(from->fx_addsy->sy_symbol.sy); + to->sym_ptr_ptr = ptrs; + + if (to->howto->pcrel_offset) { + /* This is a pcrel relocation, the addend should be adjusted */ + to->addend -= to->address -1; + } + } + + } + else { + to->section = 0; + } + + ptrs++; + from = from->fx_next; + } + + /* attatch to the section */ + section->orelocation = reloc_ptr_vector; + section->reloc_count = nrelocs; + section->flags |= SEC_LOAD; + } +} + +/* do the symbols.. */ +static void DEFUN(do_symbols, (abfd), + bfd *abfd) +{ + extern symbolS *symbol_rootP; + symbolS *ptr; + asymbol **symbol_ptr_vec; + asymbol *symbol_vec; + unsigned int count = 0; + unsigned int index; + + + for (ptr = symbol_rootP; + ptr != (symbolS *)NULL; + ptr = ptr->sy_next) + { + if (SEG_NORMAL(ptr->sy_symbol.seg)) + { + ptr->sy_symbol.sy.section = + (asection *)(segment_info[ptr->sy_symbol.seg].user_stuff); + ptr->sy_symbol.sy.value += ptr->sy_frag->fr_address; + if (ptr->sy_symbol.sy.flags == 0) { + ptr->sy_symbol.sy.flags = BSF_LOCAL ; + } + } + else { + switch (ptr->sy_symbol.seg) { + case SEG_ABSOLUTE: + ptr->sy_symbol.sy.flags |= BSF_ABSOLUTE; + ptr->sy_symbol.sy.section = 0; + break; + case SEG_UNKNOWN: + ptr->sy_symbol.sy.flags = BSF_UNDEFINED ; + ptr->sy_symbol.sy.section = 0; + break; + default: + abort(); + } + } + count++; + } + symbol_ptr_vec = (asymbol **)malloc((count+1) * sizeof(asymbol *)); + + index = 0; + for (ptr = symbol_rootP; + ptr != (symbolS *)NULL; + ptr = ptr->sy_next) + { + symbol_ptr_vec[index] = &(ptr->sy_symbol.sy); + index++; + } + symbol_ptr_vec[index] =0; + abfd->outsymbols = symbol_ptr_vec; + abfd->symcount = count; +} + +/* The generic as->bfd converter. Other backends may have special case + code */ + +void DEFUN_VOID(bfd_as_write_hook) +{ + int i; + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) { + size_section(abfd, i); + } + + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + fill_section(abfd,i); + + do_symbols(abfd); + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + do_relocs_for(i); + +} + + + +S_GET_VALUE(x) +symbolS *x; +{ + return x->sy_symbol.sy.value; +} + +S_SET_SEGMENT(x,y) +symbolS *x ; +int y; +{ + x->sy_symbol.seg = y; +} + +S_IS_DEFINED(x) +symbolS *x; +{ + if (SEG_NORMAL(x->sy_symbol.seg)) + { + return 1; + } + switch (x->sy_symbol.seg) + { + case SEG_UNKNOWN: + return 0; + default: + abort(); + } +} + +S_IS_EXTERNAL(x) { abort(); } +S_GET_DESC(x) { abort() ; } + +S_GET_SEGMENT(x) +symbolS *x; +{ return x->sy_symbol.seg; } + +S_SET_EXTERNAL(x) +symbolS *x; +{ + x->sy_symbol.sy.flags |= BSF_GLOBAL | BSF_EXPORT; +} + +S_SET_NAME(x,y) +symbolS*x; +char *y; { + x->sy_symbol.sy.name = y; } + +S_SET_VALUE(s,v) +symbolS *s; +long v; +{ + s->sy_symbol.sy.value = v; +} + +S_GET_OTHER(x) { abort() ;} +S_IS_DEBUG(x) { abort(); } + +char *segment_name() { abort(); } + +void obj_read_begin_hook() { } + +static void obj_ieee_section(ignore) +int ignore; +{ + extern char *input_line_pointer; + extern char is_end_of_line[]; + char *p= input_line_pointer; + char *s = p; + int i; + /* Look up the name, if it doesn't exist, make it */ + while (*p &&* p != ' ' && *p != ',' && !is_end_of_line[*p]) { + p++; + } + for (i = SEG_E0; i < SEG_UNKNOWN; i++) { + if (segment_info[i].hadone){ + if (strncmp(segment_info[i].name, s, p-s) == 0) { + goto ok; + + } + } + else break; + } + if (i == SEG_UNKNOWN) { + as_bad("too many sections"); + return; + } + + segment_info[i].hadone = 1; + segment_info[i].name = malloc(p-s + 1); + memcpy(segment_info[i].name, s, p-s); + segment_info[i].name[p-s] = 0; + ok: + subseg_new(i,0); + while (!is_end_of_line[*p]) + p++; + input_line_pointer = p; + +} + + +void cons(); +void s_ignore(); + + +/* + * stringer() + * + * We read 0 or more ',' seperated, double-quoted strings. + * + * Caller should have checked need_pass_2 is FALSE because we don't check it. + */ + +void stringer(); +void s_globl(); +const pseudo_typeS obj_pseudo_table[] = +{ + {"section", obj_ieee_section, 0}, + {"data.b", cons, 1}, + {"data.w", cons, 2}, + {"data.l", cons, 4}, + {"export", s_globl, 0}, + {"option", s_ignore, 0}, + {"end", s_ignore, 0}, + {"import", s_ignore, 0}, + {"sdata", stringer, 0}, + 0, + +}; + + + +void obj_symbol_new_hook(symbolP) +symbolS *symbolP; +{ + symbolP->sy_symbol.sy.the_bfd = abfd; +} + + + + + +#if 1 +extern void DEFUN_VOID(write_object_file) +{ + int i; + struct frchain *frchain_ptr; + struct frag *frag_ptr; + + abfd = bfd_openw(out_file_name, "ieee"); + + if (abfd == 0) { + as_perror ("FATAL: Can't create %s", out_file_name); + exit(42); + } + bfd_set_format(abfd, bfd_object); + bfd_set_arch_mach(abfd, bfd_arch_h8300, 0); + subseg_new(1,0); + subseg_new(2,0); + subseg_new(3,0); + for (frchain_ptr = frchain_root; + frchain_ptr != (struct frchain *)NULL; + frchain_ptr = frchain_ptr->frch_next) { + /* Run through all the sub-segments and align them up. Also close any + open frags. We tack a .fill onto the end of the frag chain so + that any .align's size can be worked by looking at the next + frag */ + + subseg_new(frchain_ptr->frch_seg, frchain_ptr->frch_subseg); +#define SUB_SEGMENT_ALIGN 2 + frag_align(SUB_SEGMENT_ALIGN,0); + frag_wane(frag_now); + frag_now->fr_fix = 0; + know( frag_now->fr_next == NULL ); + } + + /* Now build one big frag chain for each segment, linked through + fr_next. */ + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + + fragS ** prev_frag_ptr_ptr ; + struct frchain *next_frchain_ptr; + + /* struct frag **head_ptr = segment_info[i].frag_root;*/ + + segment_info[i].frag_root = segment_info[i].frchainP->frch_root; +#if 0 + /* Im not sure what this is for */ + for (frchain_ptr = segment_info[i].frchainP->frch_root; + frchain_ptr != (struct frchain *)NULL; + frchain_ptr = frchain_ptr->frch_next) + { + *head_ptr = frchain_ptr; + head_ptr = &frchain_ptr->next; + } + + +#endif + } + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) { + relax_segment(segment_info[i].frag_root, i); + } + + /* Now the addresses of the frags are correct within the segment */ + + bfd_as_write_hook(); + bfd_close(abfd); +} + +#endif + +H_SET_TEXT_SIZE(a,b) { abort(); } +H_GET_TEXT_SIZE() { abort(); } +H_SET_BSS_SIZE() { abort(); } +H_SET_STRING_SIZE() { abort(); } +H_SET_RELOCATION_SIZE() { abort(); } +H_SET_MAGIC_NUMBER() { abort(); } +H_GET_FILE_SIZE() { abort(); } +H_GET_TEXT_RELOCATION_SIZE() { abort(); } + +/* end of obj-ieee.c */ diff --git a/gnu/usr.bin/as/config/obj-ieee.h b/gnu/usr.bin/as/config/obj-ieee.h new file mode 100644 index 000000000000..3baa08118265 --- /dev/null +++ b/gnu/usr.bin/as/config/obj-ieee.h @@ -0,0 +1,46 @@ +/* This file is obj-ieee.h + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define BFD 1 + +#include <bfd.h> + +typedef struct +{ +asymbol sy; +int seg; +} obj_symbol_type; + +#define S_GET_NAME(s) (((s)->sy_symbol.sy.name)) + +typedef struct { +int x; +} +object_headers; + +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE 1 + + +int lineno_rootP; + + +#define IEEE_STYLE + +/* end of obj-ieee.h */ diff --git a/gnu/usr.bin/as/config/obj-vms.c b/gnu/usr.bin/as/config/obj-vms.c new file mode 100644 index 000000000000..5d12387e30db --- /dev/null +++ b/gnu/usr.bin/as/config/obj-vms.c @@ -0,0 +1,5484 @@ +/* vms.c -- Write out a VAX/VMS object file + Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Written by David L. Kashtan */ +/* Modified by Eric Youngdale to write VMS debug records for program + variables */ +#include "as.h" +#include "subsegs.h" +#include "obstack.h" + +/* What we do if there is a goof. */ +#define error as_fatal + +#ifdef HO_VMS /* These are of no use if we are cross assembling. */ +#include <fab.h> /* Define File Access Block */ +#include <nam.h> /* Define NAM Block */ +#include <xab.h> /* Define XAB - all different types*/ +#endif +/* + * Version string of the compiler that produced the code we are + * assembling. (And this assembler, if we do not have compiler info.) + */ +extern const char version_string[]; +char *compiler_version_string; + +/* Flag that determines how we map names. This takes several values, and + * is set with the -h switch. A value of zero implies names should be + * upper case, and the presence of the -h switch inhibits the case hack. + * No -h switch at all sets vms_name_mapping to 0, and allows case hacking. + * A value of 2 (set with -h2) implies names should be + * all lower case, with no case hack. A value of 3 (set with -h3) implies + * that case should be preserved. */ + +/* If the -+ switch is given, then the hash is appended to any name that is + * longer than 31 characters, irregardless of the setting of the -h switch. + */ + +char vms_name_mapping = 0; + + +extern char *strchr (); +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; + + +static struct input_file *find_file (symbolS *); + +/* + * This enum is used to keep track of the various types of variables that + * may be present. + */ + +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}; + +/* + * 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 ) + +/* + * This variable is used to keep track of the name of the symbol we are + * working on while we are parsing the stabs directives. + */ +static char *symbol_name; + +/* We use this counter to assign numbers to all of the structures, unions + * and enums that we define. When we actually declare a variable to the + * debugger, we can simply do it by number, rather than describing the + * whole thing each time. + */ + +static structure_count = 0; + +/* This variable is used to keep track of the current structure number + * for a given variable. If this is < 0, that means that the structure + * has not yet been defined to the debugger. This is still cool, since + * the VMS object language has ways of fixing things up after the fact, + * so we just make a note of this, and generate fixups at the end. + */ +static int struct_number; + + +/* + * Variable descriptors are used tell the debugger the data types of certain + * more complicated variables (basically anything involving a structure, + * union, enum, array or pointer). Some non-pointer variables of the + * basic types that the debugger knows about do not require a variable + * descriptor. + * + * Since it is impossible to have a variable descriptor longer than 128 + * bytes by virtue of the way that the VMS object language is set up, + * it makes not sense to make the arrays any longer than this, or worrying + * about dynamic sizing of the array. + * + * These are the arrays and counters that we use to build a variable + * descriptor. + */ + +#define MAX_DEBUG_RECORD 128 +static char Local[MAX_DEBUG_RECORD]; /* buffer for variable descriptor */ +static char Asuffix[MAX_DEBUG_RECORD]; /* buffer for array descriptor */ +static int Lpnt; /* index into Local */ +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*/ + +/* Flag if we have told user about finding global constants in the text + section. */ +static gave_compiler_message = 0; + +/* A pointer to the current routine that we are working on. */ + +static symbolS *Current_Routine; + +/* The psect number for $code a.k.a. the text section. */ + +static int Text_Psect; + + +/* + * 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) \ +{ md_number_to_chars(Object_Record_Buffer + \ + Object_Record_Offset, val, 4); \ + Object_Record_Offset += 4; } + +#define PUT_SHORT(val) \ +{ md_number_to_chars(Object_Record_Buffer + \ + Object_Record_Offset, val, 2); \ + Object_Record_Offset += 2; } + +#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) + + + /* in: segT out: N_TYPE bits */ +const short seg_N_TYPE[] = +{ + N_ABS, + N_TEXT, + N_DATA, + N_BSS, + N_UNDF, /* unknown */ + N_UNDF, /* absent */ + N_UNDF, /* pass1 */ + N_UNDF, /* error */ + N_UNDF, /* bignum/flonum */ + N_UNDF, /* difference */ + N_UNDF, /* debug */ + N_UNDF, /* ntv */ + N_UNDF, /* ptv */ + N_REGISTER, /* register */ +}; + +const segT N_TYPE_seg[N_TYPE + 2] = +{ /* N_TYPE == 0x1E = 32-2 */ + SEG_UNKNOWN, /* N_UNDF == 0 */ + SEG_GOOF, + SEG_ABSOLUTE, /* N_ABS == 2 */ + SEG_GOOF, + SEG_TEXT, /* N_TEXT == 4 */ + SEG_GOOF, + SEG_DATA, /* N_DATA == 6 */ + SEG_GOOF, + SEG_BSS, /* N_BSS == 8 */ + SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_REGISTER, /* dummy N_REGISTER for regs = 30 */ + SEG_GOOF, +}; + + +/* The following code defines the special types of pseudo-ops that we + * use with VMS. + */ + +char const_flag = 0; + +void +s_const () +{ + register int temp; + + temp = get_absolute_expression (); + subseg_new (SEG_DATA, (subsegT) temp); + const_flag = 1; + demand_empty_rest_of_line (); +} + +/* + * stab() + * + * Handle .stabX directives, which used to be open-coded. + * So much creeping featurism overloaded the semantics that we decided + * to put all .stabX thinking in one place. Here. + * + * We try to make any .stabX directive legal. Other people's AS will often + * do assembly-time consistency checks: eg assigning meaning to n_type bits + * and "protecting" you from setting them to certain values. (They also zero + * certain bits before emitting symbols. Tut tut.) + * + * If an expression is not absolute we either gripe or use the relocation + * information. Other people's assemblers silently forget information they + * don't need and invent information they need that you didn't supply. + * + * .stabX directives always make a symbol table entry. It may be junk if + * the rest of your .stabX directive is malformed. + */ +static void +obj_aout_stab (what) + int what; +{ + register symbolS *symbolP = 0; + register char *string; + int saved_type = 0; + int length; + int goof; /* TRUE if we have aborted. */ + long longint; + +/* + * Enter with input_line_pointer pointing past .stabX and any following + * whitespace. + */ + goof = 0; /* JF who forgot this?? */ + if (what == 's') + { + string = demand_copy_C_string (&length); + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + input_line_pointer++; + else + { + as_bad ("I need a comma after symbol's name"); + goof = 1; + } + } + else + string = ""; + +/* + * Input_line_pointer->after ','. String->symbol name. + */ + if (!goof) + { + symbolP = symbol_new (string, + SEG_UNKNOWN, + 0, + (struct frag *) 0); + switch (what) + { + case 'd': + S_SET_NAME (symbolP, NULL); /* .stabd feature. */ + S_SET_VALUE (symbolP, obstack_next_free (&frags) - frag_now->fr_literal); + symbolP->sy_frag = frag_now; + break; + + case 'n': + symbolP->sy_frag = &zero_address_frag; + break; + + case 's': + symbolP->sy_frag = &zero_address_frag; + break; + + default: + BAD_CASE (what); + break; + } + + if (get_absolute_expression_and_terminator (&longint) == ',') + symbolP->sy_symbol.n_type = saved_type = longint; + else + { + as_bad ("I want a comma after the n_type expression"); + goof = 1; + input_line_pointer--; /* Backup over a non-',' char. */ + } + } + + if (!goof) + { + if (get_absolute_expression_and_terminator (&longint) == ',') + S_SET_OTHER (symbolP, longint); + else + { + as_bad ("I want a comma after the n_other expression"); + goof = 1; + input_line_pointer--; /* Backup over a non-',' char. */ + } + } + + if (!goof) + { + S_SET_DESC (symbolP, get_absolute_expression ()); + if (what == 's' || what == 'n') + { + if (*input_line_pointer != ',') + { + as_bad ("I want a comma after the n_desc expression"); + goof = 1; + } + else + { + input_line_pointer++; + } + } + } + + if ((!goof) && (what == 's' || what == 'n')) + { + pseudo_set (symbolP); + symbolP->sy_symbol.n_type = saved_type; + } + + if (goof) + ignore_rest_of_line (); + else + demand_empty_rest_of_line (); +} /* obj_aout_stab() */ + +const pseudo_typeS obj_pseudo_table[] = +{ + {"stabd", obj_aout_stab, 'd'},/* stabs */ + {"stabn", obj_aout_stab, 'n'},/* stabs */ + {"stabs", obj_aout_stab, 's'},/* stabs */ + {"const", s_const, 0}, + {0, 0, 0}, + +}; /* obj_pseudo_table */ + +void +obj_read_begin_hook () +{ + return; +} /* obj_read_begin_hook() */ + +void +obj_crawl_symbol_chain (headers) + object_headers *headers; +{ + symbolS *symbolP; + symbolS **symbolPP; + int symbol_number = 0; + + /* JF deal with forward references first... */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) + { + if (symbolP->sy_forward) + { + S_SET_VALUE (symbolP, S_GET_VALUE (symbolP) + + S_GET_VALUE (symbolP->sy_forward) + + symbolP->sy_forward->sy_frag->fr_address); + symbolP->sy_forward = 0; + } /* if it has a forward reference */ + } /* walk the symbol chain */ + + { /* crawl symbol table */ + register int symbol_number = 0; + + { + symbolPP = &symbol_rootP; /* -> last symbol chain link. */ + while ((symbolP = *symbolPP) != NULL) + { + S_GET_VALUE (symbolP) += symbolP->sy_frag->fr_address; + + /* OK, here is how we decide which symbols go out into the + brave new symtab. Symbols that do are: + + * symbols with no name (stabd's?) + * symbols with debug info in their N_TYPE + + Symbols that don't are: + * symbols that are registers + * symbols with \1 as their 3rd character (numeric labels) + * "local labels" as defined by S_LOCAL_NAME(name) + if the -L switch was passed to gas. + + All other symbols are output. We complain if a deleted + symbol was marked external. */ + + + if (!S_IS_REGISTER (symbolP)) + { + symbolP->sy_name_offset = 0; + symbolPP = &(symbol_next (symbolP)); + } + else + { + if (S_IS_EXTERNAL (symbolP) || !S_IS_DEFINED (symbolP)) + { + as_bad ("Local symbol %s never defined", S_GET_NAME (symbolP)); + } /* oops. */ + + } /* if this symbol should be in the output */ + } /* for each symbol */ + } + H_SET_STRING_SIZE (headers, string_byte_count); + H_SET_SYMBOL_TABLE_SIZE (headers, symbol_number); + } /* crawl symbol table */ + +} /* obj_crawl_symbol_chain() */ + + + /****** VMS OBJECT FILE HACKING ROUTINES *******/ + + +/* + * Create the VMS object file + */ +static +Create_VMS_Object_File () +{ +#if defined(eunice) || !defined(HO_VMS) + VMS_Object_File_FD = creat (out_file_name, 0777, "var"); +#else /* eunice */ + VMS_Object_File_FD = creat (out_file_name, 0, "rfm=var", + "mbc=16", "deq=64", "fop=tef", "shr=nil"); +#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; +} + + +/* + * Flush the object record buffer to the object file + */ +static +Flush_VMS_Object_Record_Buffer () +{ + int i; + short int zero; + /* + * If the buffer is empty, we are done + */ + if (Object_Record_Offset == 0) + return; + /* + * Write the data to the file + */ +#ifndef HO_VMS /* For cross-assembly purposes. */ + i = write (VMS_Object_File_FD, &Object_Record_Offset, 2); +#endif /* not HO_VMS */ + 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"); +#ifndef HO_VMS /* When cross-assembling, we need to pad the record to an even + number of bytes. */ + /* pad it if needed */ + zero = 0; + if (Object_Record_Offset & 1 != 0) + write (VMS_Object_File_FD, &zero, 1); +#endif /* not HO_VMS */ + /* + * The buffer is now empty + */ + Object_Record_Offset = 0; +} + + +/* + * Declare a particular type of object file record + */ +static +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; +} + + + +/* + * Close the VMS Object file + */ +static +Close_VMS_Object_File () +{ + short int m_one = -1; +#ifndef HO_VMS /* For cross-assembly purposes. */ +/* Write a 0xffff into the file, which means "End of File" */ + write (VMS_Object_File_FD, &m_one, 2); +#endif /* not HO_VMS */ + close (VMS_Object_File_FD); +} + + +/* + * Store immediate data in current Psect + */ +static +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 (); + } +} + +/* + * Make a data reference + */ +static +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_S_C_STA_WPL); + PUT_SHORT (Psect_Index); + PUT_LONG (Offset); + } + else + { + PUT_CHAR (TIR_S_C_STA_PL); + PUT_CHAR (Psect_Index); + PUT_LONG (Offset); + } + } + else + { + if (Offset > 32767) + { + PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (Psect_Index); + PUT_LONG (Offset); + } + else if (Offset > 127) + { + PUT_CHAR (TIR_S_C_STA_WPW); + PUT_SHORT (Psect_Index); + PUT_SHORT (Offset); + } + else + { + PUT_CHAR (TIR_S_C_STA_WPB); + PUT_SHORT (Psect_Index); + PUT_CHAR (Offset); + }; + }; + /* + * Set relocation base + */ + PUT_CHAR (TIR_S_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. + */ +static +VMS_Store_Struct (int Struct_Index) +{ + /* + * We are writing a "OBJ_S_C_DBG" record + */ + Set_VMS_Object_File_Record (OBJ_S_C_DBG); + /* + * If the buffer is empty we must insert the record type + */ + if (Object_Record_Offset == 0) + PUT_CHAR (OBJ_S_C_DBG); + PUT_CHAR (TIR_S_C_STA_UW); + PUT_SHORT (Struct_Index); + PUT_CHAR (TIR_S_C_CTL_STKDL); + PUT_CHAR (TIR_S_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. + */ +static +VMS_Def_Struct (int Struct_Index) +{ + /* + * We are writing a "OBJ_S_C_DBG" record + */ + Set_VMS_Object_File_Record (OBJ_S_C_DBG); + /* + * If the buffer is empty we must insert the record type + */ + if (Object_Record_Offset == 0) + PUT_CHAR (OBJ_S_C_DBG); + PUT_CHAR (TIR_S_C_STA_UW); + PUT_SHORT (Struct_Index); + PUT_CHAR (TIR_S_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 (); +} + +static +VMS_Set_Struct (int Struct_Index) +{ /* see previous functions for comments */ + Set_VMS_Object_File_Record (OBJ_S_C_DBG); + if (Object_Record_Offset == 0) + PUT_CHAR (OBJ_S_C_DBG); + PUT_CHAR (TIR_S_C_STA_UW); + PUT_SHORT (Struct_Index); + PUT_CHAR (TIR_S_C_CTL_STLOC); + if (Object_Record_Offset > + (sizeof (Object_Record_Buffer) * 3 / 4)) + Flush_VMS_Object_Record_Buffer (); +} + +/* + * Write the Traceback Module Begin record + */ +static +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_S_C_MODBEG; + /* + * Unused + */ + *cp++ = 0; + /* + * Language type == "C" + */ + *(long *) cp = DST_S_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_S_C_TBT); +} + + +/* + * Write the Traceback Module End record +*/ +static +VMS_TBT_Module_End () +{ + char Local[2]; + + /* + * End module + */ + Local[0] = 1; + Local[1] = DST_S_C_MODEND; + /* + * Put it into the object record + */ + VMS_Store_Immediate_Data (Local, 2, OBJ_S_C_TBT); +} + + +/* + * Write the Traceback Routine Begin record + */ +static +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 = S_GET_NAME (symbolP); + if (*Name == '_') + Name++; + /* + * Get the text psect offset + */ + Offset = S_GET_VALUE (symbolP); + /* + * Calculate the record size + */ + Size = 1 + 1 + 4 + 1 + strlen (Name); + /* + * Record Size + */ + Local[0] = Size; + /* + * Begin Routine + */ + Local[1] = DST_S_C_RTNBEG; + /* + * Uses CallS/CallG + */ + Local[2] = 0; + /* + * Store the data so far + */ + VMS_Store_Immediate_Data (Local, 3, OBJ_S_C_TBT); + /* + * Make sure we are still generating a OBJ_S_C_TBT record + */ + if (Object_Record_Offset == 0) + PUT_CHAR (OBJ_S_C_TBT); + /* + * Now get the symbol address + */ + PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (Psect); + PUT_LONG (Offset); + /* + * Store the data reference + */ + PUT_CHAR (TIR_S_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_S_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. + */ +static +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 = symbol_next (symbolP)) + { + if (!S_IS_DEBUG (symbolP) && S_GET_TYPE (symbolP) == N_TEXT) + { + if (*S_GET_NAME (symbolP) == 'L') + continue; + if ((S_GET_VALUE (symbolP) > S_GET_VALUE (sp)) && + (S_GET_VALUE (symbolP) < Size)) + Size = S_GET_VALUE (symbolP); + /* check if gcc_compiled. has size of zero */ + if ((S_GET_VALUE (symbolP) == S_GET_VALUE (sp)) && + sp != symbolP && + (!strcmp (S_GET_NAME (sp), "gcc_compiled.") || + !strcmp (S_GET_NAME (sp), "gcc2_compiled."))) + Size = S_GET_VALUE (symbolP); + + }; + }; + if (Size == 0x7fffffff) + Size = Max_Size; + Size -= S_GET_VALUE (sp); /* and get the size of the routine */ + /* + * Record Size + */ + Local[0] = 6; + /* + * End of Routine + */ + Local[1] = DST_S_C_RTNEND; + /* + * Unused + */ + Local[2] = 0; + /* + * Size of routine + */ + *((long *) (Local + 3)) = Size; + /* + * Store the record + */ + VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_TBT); +} + +/* + * Write the Traceback Block End record + */ +static +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_S_C_BLKBEG; + /* + * Uses CallS/CallG + */ + Local[2] = 0; + /* + * Store the data so far + */ + VMS_Store_Immediate_Data (Local, 3, OBJ_S_C_DBG); + /* + * Make sure we are still generating a OBJ_S_C_DBG record + */ + if (Object_Record_Offset == 0) + PUT_CHAR (OBJ_S_C_DBG); + /* + * Now get the symbol address + */ + PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (Psect); + /* + * Get the text psect offset + */ + Offset = S_GET_VALUE (symbolP); + PUT_LONG (Offset); + /* + * Store the data reference + */ + PUT_CHAR (TIR_S_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_S_C_DBG); +} + + +/* + * Write the Traceback Block End record + */ +static +VMS_TBT_Block_End (int Size) +{ + char Local[16]; + + /* + * End block - simulate with a phony end routine + */ + Local[0] = 6; + Local[1] = DST_S_C_BLKEND; + *((long *) (Local + 3)) = Size; + /* + * Unused + */ + Local[2] = 0; + VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_DBG); +} + + + +/* + * Write a Line number / PC correlation record + */ +static +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_S_C_LINE_NUM; + /* + * Set Line number + */ + Local[2] = DST_S_C_SET_LINE_NUM; + *((unsigned short *) (Local + 3)) = Line_Number - 1; + /* + * Set PC + */ + Local[5] = DST_S_C_SET_ABS_PC; + VMS_Store_Immediate_Data (Local, 6, OBJ_S_C_TBT); + /* + * Make sure we are still generating a OBJ_S_C_TBT record + */ + if (Object_Record_Offset == 0) + PUT_CHAR (OBJ_S_C_TBT); + if (Psect < 255) + { + PUT_CHAR (TIR_S_C_STA_PL); + PUT_CHAR (Psect); + } + else + { + PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (Psect); + } + PUT_LONG (Offset); + PUT_CHAR (TIR_S_C_STO_PIDR); + /* + * Do a PC offset of 0 to register the line number + */ + Local[0] = 2; + Local[1] = DST_S_C_LINE_NUM; + Local[2] = 0; /* Increment PC by 0 and register line # */ + VMS_Store_Immediate_Data (Local, 3, OBJ_S_C_TBT); + } + else + { + /* + * If Delta is negative, terminate the line numbers + */ + if (Do_Delta < 0) + { + Local[0] = 1 + 1 + 4; + Local[1] = DST_S_C_LINE_NUM; + Local[2] = DST_S_C_TERM_L; + *((long *) (Local + 3)) = Offset; + VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_TBT); + /* + * Done + */ + return; + } + /* + * Do a PC/Line delta + */ + cp = Local + 1; + *cp++ = DST_S_C_LINE_NUM; + if (Line_Number > 1) + { + /* + * We need to increment the line number + */ + if (Line_Number - 1 <= 255) + { + *cp++ = DST_S_C_INCR_LINUM; + *cp++ = Line_Number - 1; + } + else + { + *cp++ = DST_S_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_S_C_DELTA_PC_W; + *(short *) cp = Offset; + cp += sizeof (short); + } + else + { + *cp++ = DST_S_C_DELTA_PC_L; + *(long *) cp = Offset; + cp += sizeof (long); + } + } + Local[0] = cp - (Local + 1); + VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT); + } +} + + +/* + * Describe a source file to the debugger + */ +static +VMS_TBT_Source_File (Filename, ID_Number) + char *Filename; + int ID_Number; +{ + register char *cp, *cp1; + int Status, i; + char Local[512]; +#ifndef HO_VMS /* Used for cross-assembly */ + i = strlen (Filename); +#else /* HO_VMS */ + 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 = (char *) &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); + /* + * 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; +#endif /* HO_VMS */ + /* + * Size of record + */ + Local[0] = 1 + 1 + 1 + 1 + 1 + 2 + 8 + 4 + 2 + 1 + 1 + i + 1; + /* + * Source declaration + */ + Local[1] = DST_S_C_SOURCE; + /* + * Make formfeeds count as source records + */ + Local[2] = DST_S_C_SRC_FORMFEED; + /* + * Declare source file + */ + Local[3] = DST_S_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); +#ifndef HO_VMS + /* + * Creation Date. Unknown, so we fill with zeroes. + */ + *(long *) cp = 0; + cp += sizeof (long); + *(long *) cp = 0; + cp += sizeof (long); + /* + * End of file block + */ + *(long *) cp = 0; + cp += sizeof (long); + /* + * First free byte + */ + *(short *) cp = 0; + cp += sizeof (short); + /* + * Record format + */ + *cp++ = 0; + /* + * Filename + */ + *cp++ = i; + cp1 = Filename; +#else /* Use this code when assembling for VMS on a VMS system */ + /* + * 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; +#endif /* HO_VMS */ + while (--i >= 0) + *cp++ = *cp1++; + /* + * Library module name (none) + */ + *cp++ = 0; + /* + * Done + */ + VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT); + return 1; +} + + +/* + * Give the number of source lines to the debugger + */ +static +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_S_C_SOURCE; + /* + * Set Source File + */ + cp = Local + 2; + *cp++ = DST_S_C_SRC_SETFILE; + /* + * File ID Number + */ + *(short *) cp = ID_Number; + cp += sizeof (short); + /* + * Set record number + */ + *cp++ = DST_S_C_SRC_SETREC_L; + *(long *) cp = Starting_Line_Number; + cp += sizeof (long); + /* + * Define lines + */ + *cp++ = DST_S_C_SRC_DEFLINES_W; + *(short *) cp = Number_Of_Lines; + cp += sizeof (short); + /* + * Done + */ + VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT); +} + + + + +/* 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. */ +static 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 (S_GET_NAME (sp), 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 = S_GET_NAME (sp); + 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; +} + +/* + * The following functions and definitions are used to generate object records + * that will describe program variables to the VMS debugger. + * + * 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. + */ + + +/* 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 (str, rtn) + 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 + * + * We also use this to strip the PsectAttribute hack from the name before we + * write a debugger record */ + +static char * +fix_name (pnt) + char *pnt; +{ + char *pnt1; + /* + * Kill any leading "_" + */ + if (*pnt == '_') + pnt++; + /* + * Is there a Psect Attribute to skip?? + */ + if (HAS_PSECT_ATTRIBUTES (pnt)) + { + /* + * Yes: Skip it + */ + pnt += PSECT_ATTRIBUTES_STRING_LENGTH; + while (*pnt) + { + if ((pnt[0] == '$') && (pnt[1] == '$')) + { + pnt += 2; + break; + } + pnt++; + } + } +/* Here we fix the .this -> $this conversion */ + for (pnt1 = pnt; *pnt1 != 0; pnt1++) + { + if (*pnt1 == '.') + *pnt1 = '$'; + }; + return pnt; +} + +/* 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 (str) + 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 (dbx_type) + 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; +} + + +/* 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 + */ +static +push (value, size) + int value, 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 < size1; i++) + { + Local[Lpnt--] = *pnt--; + if (Lpnt < 0) + { + overflow = 1; + Lpnt = 1; + }; + } + else + for (i = 0; i < size1; 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 (spnt2) + 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 (dbx_type) + 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 (spnt, array_suffix_len) + struct VMS_DBG_Symbol *spnt; + int array_suffix_len; +{ + struct VMS_DBG_Symbol *spnt1; + int i; + switch (spnt->advanced) + { + case VOID: + push (DBG_S_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_S_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_S_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_S_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_S_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 (spnt, dbx_type) + 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_S_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_S_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_S_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_S_C_DBG); + Lpnt = 0; + }; + i = 0; + while (i < Apoint) + Local[Lpnt++] = Asuffix[i++]; + if (Lpnt != 0) + VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_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). + */ +static +VMS_DBG_record (spnt, Psect, Offset, Name) + struct VMS_DBG_Symbol *spnt; + int Psect; + int Offset; + char *Name; +{ + char *pnt; + char *Name_pnt; + int j; + int maxlen; + int i = 0; + Name_pnt = fix_name (Name); /* if there are bad characters in name, convert them */ + if (Psect < 0) + { /* this is a local variable, referenced to SP */ + maxlen = 7 + strlen (Name_pnt); + Local[i++] = maxlen; + Local[i++] = spnt->VMS_type; + if (Offset > 0) + Local[i++] = DBG_S_C_FUNCTION_PARAMETER; + else + Local[i++] = DBG_S_C_LOCAL_SYM; + pnt = (char *) &Offset; + for (j = 0; j < 4; j++) + Local[i++] = *pnt++; /* copy the offset */ + } + else + { + maxlen = 7 + strlen (Name_pnt); /* symbols fixed in memory */ + Local[i++] = 7 + strlen (Name_pnt); + Local[i++] = spnt->VMS_type; + Local[i++] = 1; + VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); + i = 0; + VMS_Set_Data (Psect, Offset, OBJ_S_C_DBG, 0); + } + Local[i++] = strlen (Name_pnt); + while (*Name_pnt != '\0') + Local[i++] = *Name_pnt++; + VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); + if (spnt->VMS_type == DBG_S_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 + */ +static int +VMS_local_stab_Parse (sp) + 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 = S_GET_NAME (sp); + 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 = symbol_next (sp); sp1; sp1 = symbol_next (sp1)) + { + if (!S_IS_DEBUG (sp1)) + continue; + if (S_GET_RAW_TYPE (sp1) == N_FUN) + { + char * pnt3=(char*) strchr (S_GET_NAME (sp1), ':') + 1; + if (*pnt3 == 'F' || *pnt3 == 'f') break; + }; + if (S_GET_RAW_TYPE (sp1) != N_RSYM) + continue; + str1 = S_GET_NAME (sp1); /* 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, S_GET_VALUE (sp), 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 +VMS_stab_parse (sp, expected_type, type1, type2, Text_Psect) + symbolS *sp; + char expected_type; + int type1, type2, 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 = S_GET_NAME (sp); + 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 = S_GET_NAME (vsp->Symbol); + 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) + && ((S_GET_RAW_TYPE (vsp->Symbol) == type1) || + (S_GET_RAW_TYPE (vsp->Symbol) == 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 = symbol_next (sp1)) + { + /* + * Dispatch on STAB type + */ + if (S_IS_DEBUG (sp1) || (S_GET_TYPE (sp1) != N_TEXT)) + continue; + pnt = S_GET_NAME (sp1); + 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, + S_GET_VALUE (sp1), + str); + *pnt1 = ':'; + *S_GET_NAME (sp1) = 'L'; + /* fool assembler to not output this + * as a routine in the TBT */ + return 1; + }; + }; + }; + *pnt1 = ':'; /* and restore the string */ + return 0; +} + +static +VMS_GSYM_Parse (sp, Text_Psect) + symbolS *sp; + int Text_Psect; +{ /* Global variables */ + VMS_stab_parse (sp, 'G', (N_UNDF | N_EXT), (N_DATA | N_EXT), Text_Psect); +} + + +static +VMS_LCSYM_Parse (sp, Text_Psect) + symbolS *sp; + int Text_Psect; +{ /* Static symbols - uninitialized */ + VMS_stab_parse (sp, 'S', N_BSS, -1, Text_Psect); +} + +static +VMS_STSYM_Parse (sp, Text_Psect) + 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. + */ +static +VMS_RSYM_Parse (sp, Current_Routine, Text_Psect) + symbolS *sp, *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 = symbol_next (symbolP)) + { + /* + * Dispatch on STAB type + */ + switch (S_GET_RAW_TYPE (symbolP)) + { + case N_LBRAC: + if (bcnt++ == 0) + Min_Offset = S_GET_VALUE (symbolP); + break; + case N_RBRAC: + if (--bcnt == 0) + Max_Offset = + S_GET_VALUE (symbolP) - 1; + break; + } + if ((Min_Offset != -1) && (bcnt == 0)) + break; + if (S_GET_RAW_TYPE (symbolP) == N_FUN) + { + pnt=(char*) strchr (S_GET_NAME (symbolP), ':') + 1; + if (*pnt == 'F' || *pnt == 'f') 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 = S_GET_VALUE (sp); + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) + { + /* + * Dispatch on STAB type + */ + This_Offset = S_GET_VALUE (symbolP); + switch (S_GET_RAW_TYPE (symbolP)) + { + 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 = S_GET_NAME (sp); + 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'; + pnt = fix_name (S_GET_NAME (sp)); /* if there are bad characters in name, convert them */ + maxlen = 25 + strlen (pnt); + Local[i++] = maxlen; + Local[i++] = spnt->VMS_type; + Local[i++] = 0xfb; + Local[i++] = strlen (pnt) + 1; + Local[i++] = 0x00; + Local[i++] = 0x00; + Local[i++] = 0x00; + Local[i++] = strlen (pnt); + 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_S_C_DBG); + i = 0; + VMS_Set_Data (Text_Psect, Min_Offset, OBJ_S_C_DBG, 1); + VMS_Set_Data (Text_Psect, Max_Offset, OBJ_S_C_DBG, 1); + Local[i++] = 0x03; + Local[i++] = S_GET_VALUE (sp); + Local[i++] = 0x00; + Local[i++] = 0x00; + Local[i++] = 0x00; + VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); + *pnt1 = ':'; + if (spnt->VMS_type == DBG_S_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 (pnt) + 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 (str) + 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; + }; + if (type_check ("unknown type")) + { /* this is the void symbol */ + *str = '\0'; + spnt->advanced = UNKNOWN; + 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_S_C_SLINT; + spnt->data_size = 4; + } + else if (type_check ("long int")) + { + spnt->VMS_type = DBG_S_C_SLINT; + spnt->data_size = 4; + } + else if (type_check ("unsigned int")) + { + spnt->VMS_type = DBG_S_C_ULINT; + spnt->data_size = 4; + } + else if (type_check ("long unsigned int")) + { + spnt->VMS_type = DBG_S_C_ULINT; + spnt->data_size = 4; + } + else if (type_check ("short int")) + { + spnt->VMS_type = DBG_S_C_SSINT; + spnt->data_size = 2; + } + else if (type_check ("short unsigned int")) + { + spnt->VMS_type = DBG_S_C_USINT; + spnt->data_size = 2; + } + else if (type_check ("char")) + { + spnt->VMS_type = DBG_S_C_SCHAR; + spnt->data_size = 1; + } + else if (type_check ("signed char")) + { + spnt->VMS_type = DBG_S_C_SCHAR; + spnt->data_size = 1; + } + else if (type_check ("unsigned char")) + { + spnt->VMS_type = DBG_S_C_UCHAR; + spnt->data_size = 1; + } + else if (type_check ("float")) + { + spnt->VMS_type = DBG_S_C_REAL4; + spnt->data_size = 4; + } + else if (type_check ("double")) + { + spnt->VMS_type = DBG_S_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_S_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_S_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_S_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_S_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_S_C_ADVANCED_TYPE; + Local[i++] = DBG_S_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_S_C_DBG); + i = 0; + if (spnt1 == (struct VMS_DBG_Symbol *) NULL) + generate_suffix (spnt1, dtype); + else if (spnt1->VMS_type == DBG_S_C_ADVANCED_TYPE) + generate_suffix (spnt1, 0); + }; + }; + pnt1++; + Local[i++] = 0x01; /* length byte */ + Local[i++] = DBG_S_C_STRUCT_END; + VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); + i = 0; + break; + case 'e': + spnt->advanced = ENUM; + spnt->VMS_type = DBG_S_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_S_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_S_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_S_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_S_C_DBG); + i = 0; + pnt = pnt1; /* Skip final semicolon */ + }; + Local[i++] = 0x01; /* len byte */ + Local[i++] = DBG_S_C_ENUM_END; + VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); + i = 0; + pnt1 = pnt + 1; + break; + case 'a': + spnt->advanced = ARRAY; + spnt->VMS_type = DBG_S_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_S_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_S_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. + */ +static 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 = symbol_next (sp)) + { + /* + * Deal with STAB symbols + */ + if (S_IS_DEBUG (sp)) + { + /* + * Dispatch on STAB type + */ + switch (S_GET_RAW_TYPE (sp)) + { + 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 = S_GET_NAME (sp); + 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 +Define_Local_Symbols (s1, s2) + symbolS *s1, *s2; +{ + symbolS *symbolP1; + for (symbolP1 = symbol_next (s1); symbolP1 != s2; symbolP1 = symbol_next (symbolP1)) + { + if (symbolP1 == (symbolS *) NULL) + return; + if (S_GET_RAW_TYPE (symbolP1) == N_FUN) + { + char * pnt=(char*) strchr (S_GET_NAME (symbolP1), ':') + 1; + if (*pnt == 'F' || *pnt == 'f') break; + }; + /* + * Deal with STAB symbols + */ + if (S_IS_DEBUG (symbolP1)) + { + /* + * Dispatch on STAB type + */ + switch (S_GET_RAW_TYPE (symbolP1)) + { + 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 */ +} + + +/* This function crawls the symbol chain searching for local symbols that need + * to be described to the debugger. When we enter a new scope with a "{", it + * creates a new "block", which helps the debugger keep track of which scope + * we are currently in. + */ + +static symbolS * +Define_Routine (symbolP, Level) + symbolS *symbolP; + int Level; +{ + symbolS *sstart; + symbolS *symbolP1; + char str[10]; + int rcount = 0; + int Offset; + sstart = symbolP; + for (symbolP1 = symbol_next (symbolP); symbolP1; symbolP1 = symbol_next (symbolP1)) + { + if (S_GET_RAW_TYPE (symbolP1) == N_FUN) + { + char * pnt=(char*) strchr (S_GET_NAME (symbolP1), ':') + 1; + if (*pnt == 'F' || *pnt == 'f') break; + }; + /* + * Deal with STAB symbols + */ + if (S_IS_DEBUG (symbolP1)) + { + /* + * Dispatch on STAB type + */ + switch (S_GET_RAW_TYPE (symbolP1)) + { + case N_LBRAC: + if (Level != 0) + { + sprintf (str, "$%d", rcount++); + VMS_TBT_Block_Begin (symbolP1, Text_Psect, str); + }; + Offset = S_GET_VALUE (symbolP1); + Define_Local_Symbols (sstart, symbolP1); + symbolP1 = + Define_Routine (symbolP1, Level + 1); + if (Level != 0) + VMS_TBT_Block_End (S_GET_VALUE (symbolP1) - + 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); + return symbolP1; +} + + +static +VMS_DBG_Define_Routine (symbolP, Curr_Routine, Txt_Psect) + symbolS *symbolP; + symbolS *Curr_Routine; + int Txt_Psect; +{ + Current_Routine = Curr_Routine; + Text_Psect = Txt_Psect; + Define_Routine (symbolP, 0); +} + + + + +#ifndef HO_VMS +#include <sys/types.h> +#include <time.h> + +/* Manufacure a VMS like time on a unix based system. */ +get_VMS_time_on_unix (char *Now) +{ + char *pnt; + time_t timeb; + time (&timeb); + pnt = ctime (&timeb); + pnt[3] = 0; + pnt[7] = 0; + pnt[10] = 0; + pnt[16] = 0; + pnt[24] = 0; + sprintf (Now, "%2s-%3s-%s %s", pnt + 8, pnt + 4, pnt + 20, pnt + 11); +} + +#endif /* not HO_VMS */ +/* + * Write the MHD (Module Header) records + */ +static +Write_VMS_MHD_Records () +{ + register char *cp, *cp1; + register int i; + struct + { + int Size; + char *Ptr; + } Descriptor; + char Module_Name[256]; + char Now[18]; + + /* + * We are writing a module header record + */ + Set_VMS_Object_File_Record (OBJ_S_C_HDR); + /* + * *************************** + * *MAIN MODULE HEADER RECORD* + * *************************** + * + * Store record type and header type + */ + PUT_CHAR (OBJ_S_C_HDR); + PUT_CHAR (MHD_S_C_MHD); + /* + * Structure level is 0 + */ + PUT_CHAR (OBJ_S_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) + */ +#ifndef HO_VMS + get_VMS_time_on_unix (&Now[0]); +#else /* HO_VMS */ + Descriptor.Size = 17; + Descriptor.Ptr = Now; + sys$asctim (0, &Descriptor, 0, 0); +#endif /* HO_VMS */ + 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_S_C_HDR); + PUT_CHAR (MHD_S_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 + */ +static +Write_VMS_EOM_Record (Psect, Offset) + int Psect; + int Offset; +{ + /* + * We are writing an end-of-module record + */ + Set_VMS_Object_File_Record (OBJ_S_C_EOM); + /* + * Store record Type + */ + PUT_CHAR (OBJ_S_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) + */ +static +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[0] == '_') && ((In[1] > '9') || (In[1] < '0'))) + In++; + + new_name = Out; /* save this for later*/ + +#if barfoo /* Dead code */ + if ((In[0] == '_') && (In[1] == '$') && (In[2] == '_')) + destructor = 1; +#endif + + /* 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; + switch (vms_name_mapping) + { + case 0: + if (isupper(*In)) { + *Out++ = *In++; + Case_Hack_Bits |= 1; + } else { + *Out++ = islower(*In) ? toupper(*In++) : *In++; + } + break; + case 3: *Out++ = *In++; + break; + case 2: + if (islower(*In)) { + *Out++ = *In++; + } else { + *Out++ = isupper(*In) ? tolower(*In++) : *In++; + } + break; + }; + } + /* + * 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 + */ + for (i = 0; (In[i] != 0) && (i < 8); i++) + if (isupper(In[i]) && !Saw_Dollar && !flagseen['h']) + 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)) + switch (vms_name_mapping){ + case 0: *Out++ = islower(*In) ? + toupper (*In++) : + *In++; + break; + case 3: *Out++ = *In++; + break; + case 2: *Out++ = isupper(*In) ? + tolower(*In++) : + *In++; + break; + }; + } + } + } + /* + * 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 + */ +#define GLOBALSYMBOL_BIT 0x10000 +#define GLOBALVALUE_BIT 0x20000 + + +static +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_S_M_PIC}, + {"LIB", GPS_S_M_LIB}, + {"OVR", GPS_S_M_OVR}, + {"REL", GPS_S_M_REL}, + {"GBL", GPS_S_M_GBL}, + {"SHR", GPS_S_M_SHR}, + {"EXE", GPS_S_M_EXE}, + {"RD", GPS_S_M_RD}, + {"WRT", GPS_S_M_WRT}, + {"VEC", GPS_S_M_VEC}, + {"GLOBALSYMBOL", GLOBALSYMBOL_BIT}, + {"GLOBALVALUE", GLOBALVALUE_BIT}, + {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 global symbol + */ +static +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_S_C_GSD); + /* + * If the buffer is empty we must insert the GSD record type + */ + if (Object_Record_Offset == 0) + PUT_CHAR (OBJ_S_C_GSD); + /* + * We are writing a Global symbol definition subrecord + */ + if (Psect_Number <= 255) + { + PUT_CHAR (GSD_S_C_SYM); + } + else + { + PUT_CHAR (GSD_S_C_SYMW); + } + /* + * Data type is undefined + */ + PUT_CHAR (0); + /* + * Switch on Definition/Reference + */ + if ((Defined & 1) != 0) + { + /* + * Definition: + * Flags = "RELOCATABLE" and "DEFINED" for regular symbol + * = "DEFINED" for globalvalue (Defined & 2 == 1) + */ + if ((Defined & 2) == 0) + { + PUT_SHORT (GSY_S_M_DEF | GSY_S_M_REL); + } + else + { + PUT_SHORT (GSY_S_M_DEF); + }; + /* + * Psect Number + */ + if (Psect_Number <= 255) + { + PUT_CHAR (Psect_Number); + } + else + { + PUT_SHORT (Psect_Number); + } + /* + * Offset + */ + PUT_LONG (Psect_Offset); + } + else + { + /* + * Reference: + * Flags = "RELOCATABLE" for regular symbol, + * = "" for globalvalue (Defined & 2 == 1) + */ + if ((Defined & 2) == 0) + { + PUT_SHORT (GSY_S_M_REL); + } + else + { + PUT_SHORT (0); + }; + } + /* + * 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 psect + */ +static int +VMS_Psect_Spec (Name, Size, Type, vsp) + char *Name; + int Size; + char *Type; + struct VMS_Symbol *vsp; +{ + char Local[32]; + int Psect_Attributes; + + /* + * 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_S_M_PIC | GPS_S_M_OVR | GPS_S_M_REL | GPS_S_M_GBL | + GPS_S_M_SHR | GPS_S_M_RD | GPS_S_M_WRT); + } + else if (strcmp (Type, "CONST") == 0) + { + /* + * Common block psects are: PIC,OVR,REL,GBL,SHR,RD + */ + Psect_Attributes = (GPS_S_M_PIC | GPS_S_M_OVR | GPS_S_M_REL | GPS_S_M_GBL | + GPS_S_M_SHR | GPS_S_M_RD); + } + else if (strcmp (Type, "DATA") == 0) + { + /* + * The Data psects are PIC,REL,RD,WRT + */ + Psect_Attributes = + (GPS_S_M_PIC | GPS_S_M_REL | GPS_S_M_RD | GPS_S_M_WRT); + } + else if (strcmp (Type, "TEXT") == 0) + { + /* + * The Text psects are PIC,REL,SHR,EXE,RD + */ + Psect_Attributes = + (GPS_S_M_PIC | GPS_S_M_REL | GPS_S_M_SHR | + GPS_S_M_EXE | GPS_S_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); + /* + * Check for globalref/def/val. + */ + if ((Psect_Attributes & GLOBALVALUE_BIT) != 0) + { + /* + * globalvalue symbols were generated before. This code + * prevents unsightly psect buildup, and makes sure that + * fixup references are emitted correctly. + */ + vsp->Psect_Index = -1; /* to catch errors */ + S_GET_RAW_TYPE (vsp->Symbol) = N_UNDF; /* make refs work */ + return 1; /* decrement psect counter */ + }; + + if ((Psect_Attributes & GLOBALSYMBOL_BIT) != 0) + { + switch (S_GET_RAW_TYPE (vsp->Symbol)) + { + case N_UNDF | N_EXT: + VMS_Global_Symbol_Spec (Name, vsp->Psect_Index, + vsp->Psect_Offset, 0); + vsp->Psect_Index = -1; + S_GET_RAW_TYPE (vsp->Symbol) = N_UNDF; + return 1; /* return and indicate no psect */ + case N_DATA | N_EXT: + VMS_Global_Symbol_Spec (Name, vsp->Psect_Index, + vsp->Psect_Offset, 1); + /* In this case we still generate the psect */ + break; + default: + { + char Error_Line[256]; + sprintf (Error_Line, "Globalsymbol attribute for" + " symbol %s was unexpected.\n", Name); + error (Error_Line); + break; + }; + }; /* switch */ + }; + + Psect_Attributes &= 0xffff; /* clear out the globalref/def stuff */ + /* + * We are writing a GSD record + */ + Set_VMS_Object_File_Record (OBJ_S_C_GSD); + /* + * If the buffer is empty we must insert the GSD record type + */ + if (Object_Record_Offset == 0) + PUT_CHAR (OBJ_S_C_GSD); + /* + * We are writing a PSECT definition subrecord + */ + PUT_CHAR (GSD_S_C_PSC); + /* + * Psects are always LONGWORD aligned + */ + PUT_CHAR (2); + /* + * 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 (); + return 0; +} + + +/* + * 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. + */ +static 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 = symbol_next (sp1)) + { + /* + * The data type must match + */ + if (S_GET_TYPE (sp1) != N_DATA) + continue; + /* + * The symbol must be AFTER this symbol + */ + if (S_GET_VALUE (sp1) <= S_GET_VALUE (sp)) + 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 (S_GET_VALUE (sp1) > + S_GET_VALUE (Next_Symbol)) + continue; + /* + * Win: Make this the candidate + */ + Next_Symbol = sp1; + } + else + { + /* + * This is the 1st candidate + */ + Next_Symbol = sp1; + } + } + /* + * Calculate its size + */ + return (Next_Symbol ? + (S_GET_VALUE (Next_Symbol) - + S_GET_VALUE (sp)) : + (End_Of_Data - S_GET_VALUE (sp))); +} + +/* + * Check symbol names for the Psect hack with a globalvalue, and then + * generate globalvalues for those that have it. + */ +static +VMS_Emit_Globalvalues (text_siz, data_siz, Data_Segment) + unsigned text_siz; + unsigned data_siz; + char *Data_Segment; +{ + register symbolS *sp; + char *stripped_name, *Name; + int Size; + int Psect_Attributes; + int globalvalue; + + /* + * Scan the symbol table for globalvalues, and emit def/ref when + * required. These will be caught again later and converted to + * N_UNDF + */ + for (sp = symbol_rootP; sp; sp = sp->sy_next) + { + /* + * See if this is something we want to look at. + */ + if ((S_GET_RAW_TYPE (sp) != (N_DATA | N_EXT)) && + (S_GET_RAW_TYPE (sp) != (N_UNDF | N_EXT))) + continue; + /* + * See if this has globalvalue specification. + */ + Name = S_GET_NAME (sp); + + if (!HAS_PSECT_ATTRIBUTES (Name)) + continue; + + stripped_name = (char *) malloc (strlen (Name) + 1); + strcpy (stripped_name, Name); + Psect_Attributes = 0; + VMS_Modify_Psect_Attributes (stripped_name, &Psect_Attributes); + + if ((Psect_Attributes & GLOBALVALUE_BIT) != 0) + { + switch (S_GET_RAW_TYPE (sp)) + { + case N_UNDF | N_EXT: + VMS_Global_Symbol_Spec (stripped_name, 0, 0, 2); + break; + case N_DATA | N_EXT: + Size = VMS_Initialized_Data_Size (sp, text_siz + data_siz); + if (Size > 4) + error ("Invalid data type for globalvalue"); + globalvalue = 0; + + memcpy (&globalvalue, Data_Segment + S_GET_VALUE (sp) - + text_siz, Size); + /* Three times for good luck. The linker seems to get confused + if there are fewer than three */ + VMS_Global_Symbol_Spec (stripped_name, 0, 0, 2); + VMS_Global_Symbol_Spec (stripped_name, 0, globalvalue, 3); + VMS_Global_Symbol_Spec (stripped_name, 0, globalvalue, 3); + break; + default: + printf (" Invalid globalvalue of %s\n", stripped_name); + break; + }; /* switch */ + }; /* if */ + free (stripped_name); /* clean up */ + }; /* for */ + +} + + +/* + * Define a procedure entry pt/mask + */ +static +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_S_C_GSD); + /* + * If the buffer is empty we must insert the GSD record type + */ + if (Object_Record_Offset == 0) + PUT_CHAR (OBJ_S_C_GSD); + /* + * We are writing a Procedure Entry Pt/Mask subrecord + */ + if (Psect_Number <= 255) + { + PUT_CHAR (GSD_S_C_EPM); + } + else + { + PUT_CHAR (GSD_S_C_EPMW); + } + /* + * Data type is undefined + */ + PUT_CHAR (0); + /* + * Flags = "RELOCATABLE" and "DEFINED" + */ + PUT_SHORT (GSY_S_M_DEF | GSY_S_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 + */ +static +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_S_C_STA_PL); + PUT_CHAR (Psect_Index); + } + else + { + PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (Psect_Index); + } + PUT_LONG (Offset); + /* + * Set relocation base + */ + PUT_CHAR (TIR_S_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 (); +} + + +/* + * Store repeated immediate data in current Psect + */ +static +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_S_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_S_C_STA_LW); + PUT_LONG (Repeat_Count); + /* + * And now the command and its data + */ + PUT_CHAR (TIR_S_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 + */ +static +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 (S_GET_RAW_TYPE (Symbol)) + { + /* + * 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 (S_GET_NAME (Symbol), Local); + /* + * Stack the global symbol value + */ + PUT_CHAR (TIR_S_C_STA_GBL); + PUT_COUNTED_STRING (Local); + if (Offset) + { + /* + * Stack the longword offset + */ + PUT_CHAR (TIR_S_C_STA_LW); + PUT_LONG (Offset); + /* + * Add the two, leaving the result on the stack + */ + PUT_CHAR (TIR_S_C_OPR_ADD); + } + break; + /* + * Uninitialized local data + */ + case N_BSS: + /* + * Stack the Psect (+offset) + */ + if (vsp->Psect_Index < 255) + { + PUT_CHAR (TIR_S_C_STA_PL); + PUT_CHAR (vsp->Psect_Index); + } + else + { + PUT_CHAR (TIR_S_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_S_C_STA_PL); + PUT_CHAR (vsp->Psect_Index); + } + else + { + PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (vsp->Psect_Index); + } + PUT_LONG (S_GET_VALUE (Symbol) + Offset); + 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_S_C_STA_PL); + PUT_CHAR (vsp->Psect_Index); + } + else + { + PUT_CHAR (TIR_S_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_S_C_STO_PICR : TIR_S_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_S_C_STO_PIRR IN THE + * PIC CODE GENERATING FIXUP ROUTINE. + */ +static +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_S_C_TIR); + VMS_Store_Immediate_Data (&Address_Mode, 1, OBJ_S_C_TIR); + } +} + + + +/* + * 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! + */ +#if !defined(eunice) && defined(HO_VMS) +_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 */ + + +/* + * 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 && !S_IS_DEBUG (symbolP) && + S_IS_EXTERNAL (symbolP) && (S_GET_TYPE (symbolP) == N_TEXT)) + { +#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 = symbol_next (symbolP)) + { + /* + * 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 (S_GET_VALUE (symbolP) >= 2) + S_GET_VALUE (symbolP) += 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)); + S_GET_NAME (symbolP) = "_c$main_args"; + S_SET_TYPE (symbolP, N_UNDF); + S_GET_OTHER (symbolP) = 0; + S_GET_DESC (symbolP) = 0; + S_GET_VALUE (symbolP) = 0; + symbolP->sy_name_offset = 0; + symbolP->sy_number = 0; + symbolP->sy_frag = New_Frag; + symbolP->sy_forward = 0; + /* this actually inserts at the beginning of the list */ + symbol_append (symbol_rootP, symbolP, &symbol_rootP, &symbol_lastP); + + 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; + char *Data_Segment; + int Local_Initialized_Data_Size = 0; + int Globalref; + 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 (); + + /* + * 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. + * We need to generate this early, so that globalvalues + * can be properly emitted. + */ + if (data_siz > 0) + { + /* + * 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) + memcpy (Data_Segment + i, + fragP->fr_literal, + 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) + memcpy (Data_Segment + i, fill_literal, fill_size); + i += fill_size; + } + } + } + + + /* + * Generate the VMS object file records + * 1st GSD then TIR records + */ + + /******* Global Symbol Dictionary *******/ + /* + * Emit globalvalues now. We must do this before the text psect + * is defined, or we will get linker warnings about multiply defined + * symbols. All of the globalvalues "reference" psect 0, although + * it really does not have anything to do with it. + */ + VMS_Emit_Globalvalues (text_siz, data_siz, Data_Segment); + /* + * Define the Text Psect + */ + Text_Psect = Psect_Number++; + VMS_Psect_Spec ("$code", text_siz, "TEXT", 0); + /* + * Define the BSS Psect + */ + if (local_bss_counter > 0) + { + Bss_Psect = Psect_Number++; + VMS_Psect_Spec ("$uninitialized_data", local_bss_counter, "DATA", + 0); + } +#ifndef gxx_bug_fixed + /* + * The g++ compiler does not write out external references to vtables + * correctly. Check for this and holler if we see it happening. + * If that compiler bug is ever fixed we can remove this. + */ + for (sp = symbol_rootP; sp; sp = symbol_next (sp)) + { + /* + * Dispatch on symbol type + */ + switch (S_GET_RAW_TYPE (sp)) { + /* + * Global Reference + */ + case N_UNDF: + /* + * Make a GSD global symbol reference + * record. + */ + if (strncmp (S_GET_NAME (sp),"__vt.",5) == 0) + { + S_GET_RAW_TYPE (sp) = N_UNDF | N_EXT; + as_warn("g++ wrote an extern reference to %s as a routine.", + S_GET_NAME (sp)); + as_warn("I will fix it, but I hope that it was not really a routine"); + }; + break; + default: + break; + } + } +#endif /* gxx_bug_fixed */ + /* + * Now scan the symbols and emit the appropriate GSD records + */ + for (sp = symbol_rootP; sp; sp = symbol_next (sp)) + { + /* + * Dispatch on symbol type + */ + switch (S_GET_RAW_TYPE (sp)) + { + /* + * 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 = S_GET_VALUE (sp); + 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 (S_GET_OTHER (sp)) + Globalref = VMS_Psect_Spec ( + S_GET_NAME (sp), + vsp->Size, + "CONST", + vsp); + else + Globalref = VMS_Psect_Spec ( + S_GET_NAME (sp), + vsp->Size, + "COMMON", + vsp); + if (Globalref) + Psect_Number--; +#ifdef NOT_VAX_11_C_COMPATIBLE + /* + * Place a global symbol at the + * beginning of the Psect + */ + VMS_Global_Symbol_Spec (S_GET_NAME (sp), + 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 = + S_GET_VALUE (sp) - + 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 (S_GET_OTHER (sp)) + Globalref = VMS_Psect_Spec ( + S_GET_NAME (sp), + vsp->Size, + "CONST", + vsp); + else + Globalref = VMS_Psect_Spec ( + S_GET_NAME (sp), + vsp->Size, + "COMMON", + vsp); + if (Globalref) + Psect_Number--; +#ifdef NOT_VAX_11_C_COMPATIBLE + /* + * Place a global symbol at the + * beginning of the Psect + */ + VMS_Global_Symbol_Spec (S_GET_NAME (sp), + 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 (S_GET_NAME (sp), + Text_Psect, + S_GET_VALUE (sp), + 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 = S_GET_VALUE (sp); + 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 (S_GET_NAME (sp), + 0, + 0, + 0); + break; + /* + * Anything else + */ + default: + /* + * Ignore STAB symbols + * Including .stabs emitted by g++ + */ + if (S_IS_DEBUG (sp) || (S_GET_TYPE (sp) == 22)) + break; + /* + * Error + */ + if (S_GET_TYPE (sp) != 22) + printf (" ERROR, unknown type (%d)\n", + S_GET_TYPE (sp)); + 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", 0); + /* + * 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 ((S_GET_TYPE (vsp->Symbol) == N_DATA) && !S_IS_EXTERNAL (vsp->Symbol)) + 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_S_C_TIR); + /* + * Store the "fixed" part + */ + if (fragP->fr_fix) + VMS_Store_Immediate_Data (fragP->fr_literal, + fragP->fr_fix, + OBJ_S_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_S_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 (S_GET_RAW_TYPE (fixP->fx_subsy) != + S_GET_RAW_TYPE (fixP->fx_addsy)) + 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 ((S_GET_TYPE (fixP->fx_addsy) != N_DATA) && + (S_GET_TYPE (fixP->fx_addsy) != 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 = S_GET_VALUE (fixP->fx_addsy) - + S_GET_VALUE (fixP->fx_subsy); + /* + * 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_S_C_TIR); + VMS_Store_Immediate_Data (&i, + fixP->fx_size, + OBJ_S_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_S_C_TIR); + /* + * Check for indirect address reference, + * which has to be fixed up (as the linker + * will screw it up with TIR_S_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. + * The segment was manufactured before, now we just + * dump it into the appropriate psects. + */ + if (data_siz > 0) + { + + /* + * 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 (S_GET_TYPE (vsp->Symbol) != N_DATA) + continue; + /* + * Set the Psect + Offset + */ + VMS_Set_Psect (vsp->Psect_Index, + vsp->Psect_Offset, + OBJ_S_C_TIR); + /* + * Store the data + */ + VMS_Store_Immediate_Data (Data_Segment + + S_GET_VALUE (vsp->Symbol) - + text_siz, + vsp->Size, + OBJ_S_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 (S_GET_TYPE (sp) != N_DATA) + continue; + /* + * Ignore symbol if After fixup + */ + if (S_GET_VALUE (sp) > + (fixP->fx_where + + fixP->fx_frag->fr_address)) + continue; + /* + * See if the datum is here + */ + if ((S_GET_VALUE (sp) + 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 (S_GET_RAW_TYPE (fixP->fx_subsy) != + S_GET_RAW_TYPE (fixP->fx_addsy)) + 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 ((S_GET_TYPE (fixP->fx_addsy) != N_DATA) && + (S_GET_TYPE (fixP->fx_addsy) != 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 = S_GET_VALUE (fixP->fx_addsy) - + S_GET_VALUE (fixP->fx_subsy); + /* + * 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 - + S_GET_VALUE (vsp->Symbol) + + vsp->Psect_Offset, + OBJ_S_C_TIR); + VMS_Store_Immediate_Data (&i, + fixP->fx_size, + OBJ_S_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 - + S_GET_VALUE (vsp->Symbol) + + vsp->Psect_Offset, + OBJ_S_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 = symbol_next (symbolP)) + { + /* + * Deal with STAB symbols + */ + if (S_IS_DEBUG (symbolP)) + { + /* + * Dispatch on STAB type + */ + switch ((unsigned char) S_GET_RAW_TYPE (symbolP)) + { + case N_SLINE: + if (S_GET_DESC (symbolP) > Current_File->max_line) + Current_File->max_line = S_GET_DESC (symbolP); + if (S_GET_DESC (symbolP) < Current_File->min_line) + Current_File->min_line = S_GET_DESC (symbolP); + 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 = symbol_next (symbolP)) + { + /* + * Deal with text symbols + */ + if (!S_IS_DEBUG (symbolP) && (S_GET_TYPE (symbolP) == N_TEXT)) + { + /* + * Ignore symbols starting with "L", + * as they are local symbols + */ + if (*S_GET_NAME (symbolP) == '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 = symbol_next (symbolP1)) + { + if (!S_IS_DEBUG (symbolP1)) + continue; + if (S_GET_RAW_TYPE (symbolP1) != N_FUN) + continue; + pnt = S_GET_NAME (symbolP); + pnt1 = S_GET_NAME (symbolP1); + if (*pnt++ != '_') + continue; + while (*pnt++ == *pnt1++) + { + }; + if (*pnt1 != 'F' && *pnt1 != 'f') continue; + 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 (S_IS_DEBUG (symbolP)) + { + /* + * Dispatch on STAB type + */ + switch ((unsigned char) S_GET_RAW_TYPE (symbolP)) + { + /* + * 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) && + S_GET_VALUE (symbolP) == + Current_Offset) + break; + /* calculate actual debugger source line */ + S_GET_DESC (symbolP) + += 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 ( + S_GET_DESC (symbolP), + S_GET_VALUE (symbolP), + Text_Psect, + 0); + } + else + { + if ((S_GET_DESC (symbolP) - + 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, + S_GET_VALUE (symbolP) - + Current_Offset, + 0, + -1); + VMS_TBT_Line_PC_Correlation ( + S_GET_DESC (symbolP), + S_GET_VALUE (symbolP), + Text_Psect, + 0); + } + else + { + /* + * Line delta is +ve, all is well + */ + VMS_TBT_Line_PC_Correlation ( + S_GET_DESC (symbolP) - + Current_Line_Number, + S_GET_VALUE (symbolP) - + Current_Offset, + 0, + 1); + } + } + /* + * Update the current line/PC + */ + Current_Line_Number = S_GET_DESC (symbolP); + Current_Offset = S_GET_VALUE (symbolP); + /* + * 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 - S_GET_VALUE (Current_Routine), + 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, + S_GET_VALUE (Entry_Point_Symbol)); + + /* + * All done, close the object file + */ + Close_VMS_Object_File (); +} + +/* end of obj-vms.c */ diff --git a/gnu/usr.bin/as/config/obj-vms.h b/gnu/usr.bin/as/config/obj-vms.h new file mode 100644 index 000000000000..fec056d56080 --- /dev/null +++ b/gnu/usr.bin/as/config/obj-vms.h @@ -0,0 +1,474 @@ +/* VMS object file format + Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2, +or (at your option) any later version. + +GAS is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +the GNU General Public License for more details. + +You should have received a copy of the GNU General Public +License along with GAS; see the file COPYING. If not, write +to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Tag to validate a.out object file format processing */ +#define OBJ_VMS 1 + +#include "targ-cpu.h" + +/* This flag is used to remember whether we are in the const or the + data section. By and large they are identical, but we set a no-write + bit for psects in the const section. */ + +extern char const_flag; + + +/* These are defined in obj-vms.c. */ +extern const short seg_N_TYPE[]; +extern const segT N_TYPE_seg[]; + +enum reloc_type { + NO_RELOC, RELOC_32 +}; + +#define N_BADMAG(x) (0) +#define N_TXTOFF(x) ( sizeof(struct exec) ) +#define N_DATOFF(x) ( N_TXTOFF(x) + (x).a_text ) +#define N_TROFF(x) ( N_DATOFF(x) + (x).a_data ) +#define N_DROFF(x) ( N_TROFF(x) + (x).a_trsize ) +#define N_SYMOFF(x) ( N_DROFF(x) + (x).a_drsize ) +#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms ) + +/* We use this copy of the exec header for VMS. We do not actually use it, but + what we actually do is let gas fill in the relevant slots, and when we get + around to writing an obj file, we just pick out what we need. */ + +struct exec +{ + unsigned long a_text; /* length of text, in bytes */ + unsigned long a_data; /* length of data, in bytes */ + unsigned long a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned long a_trsize; /* length of relocation info for text, in bytes */ + unsigned long a_drsize; /* length of relocation info for data, in bytes */ + unsigned long a_entry; /* start address */ + unsigned long a_syms; /* length of symbol table data in file, in bytes */ +}; + +typedef struct { + struct exec header; /* a.out header */ + long string_table_size; /* names + '\0' + sizeof(int) */ +} object_headers; + +/* A single entry in the symbol table + */ +struct nlist { + union { + char *n_name; + struct nlist *n_next; + long n_strx; /* Index into string table */ + } n_un; + unsigned char n_type; /* See below */ + char n_other; /* Used in i80960 support -- see below */ + short n_desc; + unsigned long n_value; +}; + +/* Legal values of n_type + */ +#define N_UNDF 0 /* Undefined symbol */ +#define N_ABS 2 /* Absolute symbol */ +#define N_TEXT 4 /* Text symbol */ +#define N_DATA 6 /* Data symbol */ +#define N_BSS 8 /* BSS symbol */ +#define N_FN 31 /* Filename symbol */ + +#define N_EXT 1 /* External symbol (OR'd in with one of above) */ +#define N_TYPE 036 /* Mask for all the type bits */ + +#define N_STAB 0340 /* Mask for all bits used for SDB entries */ + +#define N_GSYM 0x20 /* global symbol: name,,0,type,0 */ +#define N_FNAME 0x22 /* procedure name (f77 kludge): name,,0 */ +#define N_FUN 0x24 /* procedure: name,,0,linenumber,address */ +#define N_STSYM 0x26 /* static symbol: name,,0,type,address */ +#define N_LCSYM 0x28 /* .lcomm symbol: name,,0,type,address */ +#define N_RSYM 0x40 /* register sym: name,,0,type,register */ +#define N_SLINE 0x44 /* src line: 0,,0,linenumber,address */ +#define N_CATCH 0x54 /* */ +#define N_SSYM 0x60 /* structure elt: name,,0,type,struct_offset */ +#define N_SO 0x64 /* source file name: name,,0,0,address */ +#define N_LSYM 0x80 /* local sym: name,,0,type,offset */ +#define N_SOL 0x84 /* #included file name: name,,0,0,address */ +#define N_PSYM 0xa0 /* parameter: name,,0,type,offset */ +#define N_ENTRY 0xa4 /* alternate entry: name,linenumber,address */ +#define N_LBRAC 0xc0 /* left bracket: 0,,0,nesting level,address */ +#define N_RBRAC 0xe0 /* right bracket: 0,,0,nesting level,address */ +#define N_BCOMM 0xe2 /* begin common: name,, */ +#define N_ECOMM 0xe4 /* end common: name,, */ +#define N_ECOML 0xe8 /* end common (local name): ,,address */ +#define N_LENG 0xfe /* second stab entry with length information */ + +/* SYMBOL TABLE */ +/* Symbol table entry data type */ + +typedef struct nlist obj_symbol_type; /* Symbol table entry */ + +/* Symbol table macros and constants */ + +/* + * Macros to extract information from a symbol table entry. + * This syntaxic indirection allows independence regarding a.out or coff. + * The argument (s) of all these macros is a pointer to a symbol table entry. + */ + +/* True if the symbol is external */ +#define S_IS_EXTERNAL(s) ((s)->sy_symbol.n_type & N_EXT) + +/* True if symbol has been defined, ie is in N_{TEXT,DATA,BSS,ABS} or N_EXT */ +#define S_IS_DEFINED(s) (S_GET_TYPE(s) != N_UNDF) + +#define S_IS_REGISTER(s) ((s)->sy_symbol.n_type == N_REGISTER) + +/* True if a debug special symbol entry */ +#define S_IS_DEBUG(s) ((s)->sy_symbol.n_type & N_STAB) +/* True if a symbol is local symbol name */ +/* A symbol name whose name begin with ^A is a gas internal pseudo symbol + nameless symbols come from .stab directives. */ +#define S_IS_LOCAL(s) (S_GET_NAME(s) && \ + !S_IS_DEBUG(s) && \ + (S_GET_NAME(s)[0] == '\001' || \ + (S_LOCAL_NAME(s) && !flagseen['L']))) +/* True if a symbol is not defined in this file */ +#define S_IS_EXTERN(s) ((s)->sy_symbol.n_type & N_EXT) +/* True if the symbol has been generated because of a .stabd directive */ +#define S_IS_STABD(s) (S_GET_NAME(s) == (char *)0) + +/* Accessors */ +/* The value of the symbol */ +#define S_GET_VALUE(s) (((s)->sy_symbol.n_value)) +/* The name of the symbol */ +#define S_GET_NAME(s) ((s)->sy_symbol.n_un.n_name) +/* The pointer to the string table */ +#define S_GET_OFFSET(s) ((s)->sy_symbol.n_un.n_strx) +/* The raw type of the symbol */ +#define S_GET_RAW_TYPE(s) ((s)->sy_symbol.n_type) +/* The type of the symbol */ +#define S_GET_TYPE(s) ((s)->sy_symbol.n_type & N_TYPE) +/* The numeric value of the segment */ +#define S_GET_SEGMENT(s) (N_TYPE_seg[S_GET_TYPE(s)]) +/* The n_other expression value */ +#define S_GET_OTHER(s) ((s)->sy_symbol.n_other) +/* The n_desc expression value */ +#define S_GET_DESC(s) ((s)->sy_symbol.n_desc) + +/* Modifiers */ +/* Set the value of the symbol */ +#define S_SET_VALUE(s,v) ((s)->sy_symbol.n_value = (unsigned long) (v)) +/* Assume that a symbol cannot be simultaneously in more than on segment */ + /* set segment */ +#define S_SET_SEGMENT(s,seg) ((s)->sy_symbol.n_type &= ~N_TYPE,(s)->sy_symbol.n_type|=SEGMENT_TO_SYMBOL_TYPE(seg)) +/* The symbol is external */ +#define S_SET_EXTERNAL(s) ((s)->sy_symbol.n_type |= N_EXT) +/* The symbol is not external */ +#define S_CLEAR_EXTERNAL(s) ((s)->sy_symbol.n_type &= ~N_EXT) +/* Set the name of the symbol */ +#define S_SET_NAME(s,v) ((s)->sy_symbol.n_un.n_name = (v)) +/* Set the offset in the string table */ +#define S_SET_OFFSET(s,v) ((s)->sy_symbol.n_un.n_strx = (v)) +/* Set the n_other expression value */ +#define S_SET_OTHER(s,v) ((s)->sy_symbol.n_other = (v)) +/* Set the n_desc expression value */ +#define S_SET_DESC(s,v) ((s)->sy_symbol.n_desc = (v)) + + +/* File header macro and type definition */ + +#define H_GET_TEXT_SIZE(h) ((h)->header.a_text) +#define H_GET_DATA_SIZE(h) ((h)->header.a_data) +#define H_GET_BSS_SIZE(h) ((h)->header.a_bss) + +#define H_SET_TEXT_SIZE(h,v) ((h)->header.a_text = md_section_align(SEG_TEXT, (v))) +#define H_SET_DATA_SIZE(h,v) ((h)->header.a_data = md_section_align(SEG_DATA, (v))) +#define H_SET_BSS_SIZE(h,v) ((h)->header.a_bss = md_section_align(SEG_BSS, (v))) + +#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v)) +#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->header.a_syms = (v) * \ + sizeof(struct nlist)) + +/* + * Current means for getting the name of a segment. + * This will change for infinite-segments support (e.g. COFF). + */ +#define segment_name(seg) ( seg_name[(int)(seg)] ) +extern char *const seg_name[]; + + +/* line numbering stuff. */ +#define OBJ_EMIT_LINENO(a, b, c) {;} + +#define obj_symbol_new_hook(s) {;} + +#ifdef __STDC__ +struct fix; +void tc_aout_fix_to_chars(char *where, struct fix *fixP, relax_addressT segment_address); +#else +void tc_aout_fix_to_chars(); +#endif /* __STDC__ */ + +/* The rest of this file contains definitions for constants used within the actual + VMS object file. We do not use a $ in the symbols (as per usual VMS + convention) since System V gags on it. */ + +#define OBJ_S_C_HDR 0 +#define OBJ_S_C_HDR_MHD 0 +#define OBJ_S_C_HDR_LNM 1 +#define OBJ_S_C_HDR_SRC 2 +#define OBJ_S_C_HDR_TTL 3 +#define OBJ_S_C_HDR_CPR 4 +#define OBJ_S_C_HDR_MTC 5 +#define OBJ_S_C_HDR_GTX 6 +#define OBJ_S_C_GSD 1 +#define OBJ_S_C_GSD_PSC 0 +#define OBJ_S_C_GSD_SYM 1 +#define OBJ_S_C_GSD_EPM 2 +#define OBJ_S_C_GSD_PRO 3 +#define OBJ_S_C_GSD_SYMW 4 +#define OBJ_S_C_GSD_EPMW 5 +#define OBJ_S_C_GSD_PROW 6 +#define OBJ_S_C_GSD_IDC 7 +#define OBJ_S_C_GSD_ENV 8 +#define OBJ_S_C_GSD_LSY 9 +#define OBJ_S_C_GSD_LEPM 10 +#define OBJ_S_C_GSD_LPRO 11 +#define OBJ_S_C_GSD_SPSC 12 +#define OBJ_S_C_TIR 2 +#define OBJ_S_C_EOM 3 +#define OBJ_S_C_DBG 4 +#define OBJ_S_C_TBT 5 +#define OBJ_S_C_LNK 6 +#define OBJ_S_C_EOMW 7 +#define OBJ_S_C_MAXRECTYP 7 +#define OBJ_S_K_SUBTYP 1 +#define OBJ_S_C_SUBTYP 1 +#define OBJ_S_C_MAXRECSIZ 2048 +#define OBJ_S_C_STRLVL 0 +#define OBJ_S_C_SYMSIZ 31 +#define OBJ_S_C_STOREPLIM -1 +#define OBJ_S_C_PSCALILIM 9 + +#define MHD_S_C_MHD 0 +#define MHD_S_C_LNM 1 +#define MHD_S_C_SRC 2 +#define MHD_S_C_TTL 3 +#define MHD_S_C_CPR 4 +#define MHD_S_C_MTC 5 +#define MHD_S_C_GTX 6 +#define MHD_S_C_MAXHDRTYP 6 + +#define GSD_S_K_ENTRIES 1 +#define GSD_S_C_ENTRIES 1 +#define GSD_S_C_PSC 0 +#define GSD_S_C_SYM 1 +#define GSD_S_C_EPM 2 +#define GSD_S_C_PRO 3 +#define GSD_S_C_SYMW 4 +#define GSD_S_C_EPMW 5 +#define GSD_S_C_PROW 6 +#define GSD_S_C_IDC 7 +#define GSD_S_C_ENV 8 +#define GSD_S_C_LSY 9 +#define GSD_S_C_LEPM 10 +#define GSD_S_C_LPRO 11 +#define GSD_S_C_SPSC 12 +#define GSD_S_C_SYMV 13 +#define GSD_S_C_EPMV 14 +#define GSD_S_C_PROV 15 +#define GSD_S_C_MAXRECTYP 15 + +#define GSY_S_M_WEAK 1 +#define GSY_S_M_DEF 2 +#define GSY_S_M_UNI 4 +#define GSY_S_M_REL 8 + +#define GPS_S_M_PIC 1 +#define GPS_S_M_LIB 2 +#define GPS_S_M_OVR 4 +#define GPS_S_M_REL 8 +#define GPS_S_M_GBL 16 +#define GPS_S_M_SHR 32 +#define GPS_S_M_EXE 64 +#define GPS_S_M_RD 128 +#define GPS_S_M_WRT 256 +#define GPS_S_M_VEC 512 +#define GPS_S_K_NAME 9 +#define GPS_S_C_NAME 9 + +#define TIR_S_C_STA_GBL 0 +#define TIR_S_C_STA_SB 1 +#define TIR_S_C_STA_SW 2 +#define TIR_S_C_STA_LW 3 +#define TIR_S_C_STA_PB 4 +#define TIR_S_C_STA_PW 5 +#define TIR_S_C_STA_PL 6 +#define TIR_S_C_STA_UB 7 +#define TIR_S_C_STA_UW 8 +#define TIR_S_C_STA_BFI 9 +#define TIR_S_C_STA_WFI 10 +#define TIR_S_C_STA_LFI 11 +#define TIR_S_C_STA_EPM 12 +#define TIR_S_C_STA_CKARG 13 +#define TIR_S_C_STA_WPB 14 +#define TIR_S_C_STA_WPW 15 +#define TIR_S_C_STA_WPL 16 +#define TIR_S_C_STA_LSY 17 +#define TIR_S_C_STA_LIT 18 +#define TIR_S_C_STA_LEPM 19 +#define TIR_S_C_MAXSTACOD 19 +#define TIR_S_C_MINSTOCOD 20 +#define TIR_S_C_STO_SB 20 +#define TIR_S_C_STO_SW 21 +#define TIR_S_C_STO_L 22 +#define TIR_S_C_STO_BD 23 +#define TIR_S_C_STO_WD 24 +#define TIR_S_C_STO_LD 25 +#define TIR_S_C_STO_LI 26 +#define TIR_S_C_STO_PIDR 27 +#define TIR_S_C_STO_PICR 28 +#define TIR_S_C_STO_RSB 29 +#define TIR_S_C_STO_RSW 30 +#define TIR_S_C_STO_RL 31 +#define TIR_S_C_STO_VPS 32 +#define TIR_S_C_STO_USB 33 +#define TIR_S_C_STO_USW 34 +#define TIR_S_C_STO_RUB 35 +#define TIR_S_C_STO_RUW 36 +#define TIR_S_C_STO_B 37 +#define TIR_S_C_STO_W 38 +#define TIR_S_C_STO_RB 39 +#define TIR_S_C_STO_RW 40 +#define TIR_S_C_STO_RIVB 41 +#define TIR_S_C_STO_PIRR 42 +#define TIR_S_C_MAXSTOCOD 42 +#define TIR_S_C_MINOPRCOD 50 +#define TIR_S_C_OPR_NOP 50 +#define TIR_S_C_OPR_ADD 51 +#define TIR_S_C_OPR_SUB 52 +#define TIR_S_C_OPR_MUL 53 +#define TIR_S_C_OPR_DIV 54 +#define TIR_S_C_OPR_AND 55 +#define TIR_S_C_OPR_IOR 56 +#define TIR_S_C_OPR_EOR 57 +#define TIR_S_C_OPR_NEG 58 +#define TIR_S_C_OPR_COM 59 +#define TIR_S_C_OPR_INSV 60 +#define TIR_S_C_OPR_ASH 61 +#define TIR_S_C_OPR_USH 62 +#define TIR_S_C_OPR_ROT 63 +#define TIR_S_C_OPR_SEL 64 +#define TIR_S_C_OPR_REDEF 65 +#define TIR_S_C_OPR_DFLIT 66 +#define TIR_S_C_MAXOPRCOD 66 +#define TIR_S_C_MINCTLCOD 80 +#define TIR_S_C_CTL_SETRB 80 +#define TIR_S_C_CTL_AUGRB 81 +#define TIR_S_C_CTL_DFLOC 82 +#define TIR_S_C_CTL_STLOC 83 +#define TIR_S_C_CTL_STKDL 84 +#define TIR_S_C_MAXCTLCOD 84 + +/* + * Debugger symbol definitions: These are done by hand, as no + * machine-readable version seems + * to be available. + */ +#define DST_S_C_C 7 /* Language == "C" */ +#define DST_S_C_VERSION 153 +#define DST_S_C_SOURCE 155 /* Source file */ +#define DST_S_C_PROLOG 162 +#define DST_S_C_BLKBEG 176 /* Beginning of block */ +#define DST_S_C_BLKEND 177 /* End of block */ +#define DST_S_C_ENTRY 181 +#define DST_S_C_PSECT 184 +#define DST_S_C_LINE_NUM 185 /* Line Number */ +#define DST_S_C_LBLORLIT 186 +#define DST_S_C_LABEL 187 +#define DST_S_C_MODBEG 188 /* Beginning of module */ +#define DST_S_C_MODEND 189 /* End of module */ +#define DST_S_C_RTNBEG 190 /* Beginning of routine */ +#define DST_S_C_RTNEND 191 /* End of routine */ +#define DST_S_C_DELTA_PC_W 1 /* Incr PC */ +#define DST_S_C_INCR_LINUM 2 /* Incr Line # */ +#define DST_S_C_INCR_LINUM_W 3 /* Incr Line # */ +#define DST_S_C_SET_LINUM_INCR 4 +#define DST_S_C_SET_LINUM_INCR_W 5 +#define DST_S_C_RESET_LINUM_INCR 6 +#define DST_S_C_BEG_STMT_MODE 7 +#define DST_S_C_END_STMT_MODE 8 +#define DST_S_C_SET_LINE_NUM 9 /* Set Line # */ +#define DST_S_C_SET_PC 10 +#define DST_S_C_SET_PC_W 11 +#define DST_S_C_SET_PC_L 12 +#define DST_S_C_SET_STMTNUM 13 +#define DST_S_C_TERM 14 /* End of lines */ +#define DST_S_C_TERM_W 15 /* End of lines */ +#define DST_S_C_SET_ABS_PC 16 /* Set PC */ +#define DST_S_C_DELTA_PC_L 17 /* Incr PC */ +#define DST_S_C_INCR_LINUM_L 18 /* Incr Line # */ +#define DST_S_C_SET_LINUM_B 19 /* Set Line # */ +#define DST_S_C_SET_LINUM_L 20 /* Set Line # */ +#define DST_S_C_TERM_L 21 /* End of lines */ +/* these are used with DST_S_C_SOURCE */ +#define DST_S_C_SRC_FORMFEED 16 /* ^L counts */ +#define DST_S_C_SRC_DECLFILE 1 /* Declare file */ +#define DST_S_C_SRC_SETFILE 2 /* Set file */ +#define DST_S_C_SRC_SETREC_L 3 /* Set record */ +#define DST_S_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_S_C_UCHAR 0x02 +#define DBG_S_C_USINT 0x03 +#define DBG_S_C_ULINT 0x04 +#define DBG_S_C_SCHAR 0x06 +#define DBG_S_C_SSINT 0x07 +#define DBG_S_C_SLINT 0x08 +#define DBG_S_C_REAL4 0x0a +#define DBG_S_C_REAL8 0x0b +#define DBG_S_C_FUNCTION_ADDR 0x17 +#define DBG_S_C_ADVANCED_TYPE 0xa3 +/* These are the codes that are used to generate the definitions of struct + * union and enum records + */ +#define DBG_S_C_ENUM_ITEM 0xa4 +#define DBG_S_C_ENUM_START 0xa5 +#define DBG_S_C_ENUM_END 0xa6 +#define DBG_S_C_STRUCT_START 0xab +#define DBG_S_C_STRUCT_ITEM 0xff +#define DBG_S_C_STRUCT_END 0xac +/* These are the codes that are used in the suffix records to determine the + * actual data type + */ +#define DBG_S_C_BASIC 0x01 +#define DBG_S_C_BASIC_ARRAY 0x02 +#define DBG_S_C_STRUCT 0x03 +#define DBG_S_C_POINTER 0x04 +#define DBG_S_C_VOID 0x05 +#define DBG_S_C_COMPLEX_ARRAY 0x07 +/* These codes are used in the generation of the symbol definition records + */ +#define DBG_S_C_FUNCTION_PARAMETER 0xc9 +#define DBG_S_C_LOCAL_SYM 0xd9 +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-vms.h */ diff --git a/gnu/usr.bin/as/config/tc-a29k.c b/gnu/usr.bin/as/config/tc-a29k.c new file mode 100644 index 000000000000..84ec97a6caa6 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-a29k.c @@ -0,0 +1,1113 @@ +/* tc-a29k.c -- Assemble for the AMD 29000. + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* John Gilmore has reorganized this module somewhat, to make it easier + to convert it to new machines' assemblers as desired. There was too + much bloody rewriting required before. There still probably is. */ + +#include "as.h" + +#include "opcode/a29k.h" + +/* Make it easier to clone this machine desc into another one. */ +#define machine_opcode a29k_opcode +#define machine_opcodes a29k_opcodes +#define machine_ip a29k_ip +#define machine_it a29k_it + +const relax_typeS md_relax_table[] = { 0 }; + +#define IMMEDIATE_BIT 0x01000000 /* Turns RB into Immediate */ +#define ABSOLUTE_BIT 0x01000000 /* Turns PC-relative to Absolute */ +#define CE_BIT 0x00800000 /* Coprocessor enable in LOAD */ +#define UI_BIT 0x00000080 /* Unsigned integer in CONVERT */ + +/* handle of the OPCODE hash table */ +static struct hash_control *op_hash = NULL; + +struct machine_it { + char *error; + unsigned long opcode; + struct nlist *nlistp; + expressionS exp; + int pcrel; + int reloc_offset; /* Offset of reloc within insn */ + enum reloc_type reloc; +} the_insn; + +#if __STDC__ == 1 + +/* static int getExpression(char *str); */ +static void machine_ip(char *str); +/* static void print_insn(struct machine_it *insn); */ +static void s_data1(void); +static void s_use(void); + +#else /* not __STDC__ */ + +/* static int getExpression(); */ +static void machine_ip(); +/* static void print_insn(); */ +static void s_data1(); +static void s_use(); + +#endif /* not __STDC__ */ + +const pseudo_typeS + md_pseudo_table[] = { + { "align", s_align_bytes, 4 }, + { "block", s_space, 0 }, + { "cputype", s_ignore, 0 }, /* CPU as 29000 or 29050 */ + { "reg", s_lsym, 0 }, /* Register equate, same as equ */ + { "space", s_ignore, 0 }, /* Listing control */ + { "sect", s_ignore, 0 }, /* Creation of coff sections */ + { "use", s_use, 0 }, + { "word", cons, 4 }, + { NULL, 0, 0 }, + }; + +int md_short_jump_size = 4; +int md_long_jump_size = 4; +#if defined(BFD_HEADERS) +#ifdef RELSZ +int md_reloc_size = RELSZ; /* Coff headers */ +#else +int md_reloc_size = 12; /* something else headers */ +#endif +#else +int md_reloc_size = 12; /* Not bfdized*/ +#endif + +/* This array holds the chars that always start a comment. If the + pre-processor is disabled, these aren't very useful */ +char comment_chars[] = ";"; + +/* This array holds the chars that only start a comment at the beginning of + a line. If the line seems to have the form '# 123 filename' + .line and .file directives will appear in the pre-processed output */ +/* Note that input_file.c hand checks for '#' at the beginning of the + first line of the input file. This is because the compiler outputs + #NO_APP at the beginning of its output. */ +/* Also note that comments like this one will always work */ +char line_comment_chars[] = "#"; + +/* We needed an unused char for line separation to work around the + lack of macros, using sed and such. */ +char line_separator_chars[] = "@"; + +/* Chars that can be used to separate mant from exp in floating point nums */ +char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant */ +/* As in 0f12.456 */ +/* or 0d1.2345e12 */ +char FLT_CHARS[] = "rRsSfFdDxXpP"; + +/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be + changed in read.c. Ideally it shouldn't have to know about it at all, + but nothing is ideal around here. + */ + +static unsigned char octal[256]; +#define isoctal(c) octal[c] + static unsigned char toHex[256]; + +/* + * anull bit - causes the branch delay slot instructions to not be executed + */ +#define ANNUL (1 << 29) + +static void + s_use() +{ + + if (strncmp(input_line_pointer, ".text", 5) == 0) { + input_line_pointer += 5; + s_text(); + return; + } + if (strncmp(input_line_pointer, ".data", 5) == 0) { + input_line_pointer += 5; + s_data(); + return; + } + if (strncmp(input_line_pointer, ".data1", 6) == 0) { + input_line_pointer += 6; + s_data1(); + return; + } + /* Literals can't go in the text segment because you can't read + from instruction memory on some 29k's. So, into initialized data. */ + if (strncmp(input_line_pointer, ".lit", 4) == 0) { + input_line_pointer += 4; + subseg_new(SEG_DATA, 200); + demand_empty_rest_of_line(); + return; + } + + as_bad("Unknown segment type"); + demand_empty_rest_of_line(); + return; +} + +static void + s_data1() +{ + subseg_new(SEG_DATA, 1); + demand_empty_rest_of_line(); + return; +} + +/* Install symbol definition that maps REGNAME to REGNO. + FIXME-SOON: These are not recognized in mixed case. */ + +static void + insert_sreg (regname, regnum) +char *regname; +int regnum; +{ + /* FIXME-SOON, put something in these syms so they won't be output to the symbol + table of the resulting object file. */ + + /* Must be large enough to hold the names of the special registers. */ + char buf[80]; + int i; + + symbol_table_insert(symbol_new(regname, SEG_REGISTER, regnum, &zero_address_frag)); + for (i = 0; regname[i]; i++) + buf[i] = islower (regname[i]) ? toupper (regname[i]) : regname[i]; + buf[i] = '\0'; + + symbol_table_insert(symbol_new(buf, SEG_REGISTER, regnum, &zero_address_frag)); +} /* insert_sreg() */ + +/* Install symbol definitions for assorted special registers. + See ASM29K Ref page 2-9. */ + +void define_some_regs() { +#define SREG 256 + + /* Protected special-purpose register names */ + insert_sreg ("vab", SREG+0); + insert_sreg ("ops", SREG+1); + insert_sreg ("cps", SREG+2); + insert_sreg ("cfg", SREG+3); + insert_sreg ("cha", SREG+4); + insert_sreg ("chd", SREG+5); + insert_sreg ("chc", SREG+6); + insert_sreg ("rbp", SREG+7); + insert_sreg ("tmc", SREG+8); + insert_sreg ("tmr", SREG+9); + insert_sreg ("pc0", SREG+10); + insert_sreg ("pc1", SREG+11); + insert_sreg ("pc2", SREG+12); + insert_sreg ("mmu", SREG+13); + insert_sreg ("lru", SREG+14); + + /* Unprotected special-purpose register names */ + insert_sreg ("ipc", SREG+128); + insert_sreg ("ipa", SREG+129); + insert_sreg ("ipb", SREG+130); + insert_sreg ("q", SREG+131); + insert_sreg ("alu", SREG+132); + insert_sreg ("bp", SREG+133); + insert_sreg ("fc", SREG+134); + insert_sreg ("cr", SREG+135); + insert_sreg ("fpe", SREG+160); + insert_sreg ("inte",SREG+161); + insert_sreg ("fps", SREG+162); + /* "", SREG+163); Reserved */ + insert_sreg ("exop",SREG+164); +} /* define_some_regs() */ + +/* This function is called once, at assembler startup time. It should + set up all the tables, etc. that the MD part of the assembler will need. */ +void + md_begin() +{ + register char *retval = NULL; + int lose = 0; + register int skipnext = 0; + register unsigned int i; + register char *strend, *strend2; + + /* Hash up all the opcodes for fast use later. */ + + op_hash = hash_new(); + if (op_hash == NULL) + as_fatal("Virtual memory exhausted"); + + for (i = 0; i < num_opcodes; i++) + { + const char *name = machine_opcodes[i].name; + + if (skipnext) { + skipnext = 0; + continue; + } + + /* Hack to avoid multiple opcode entries. We pre-locate all the + variations (b/i field and P/A field) and handle them. */ + + if (!strcmp (name, machine_opcodes[i+1].name)) { + if ((machine_opcodes[i].opcode ^ machine_opcodes[i+1].opcode) + != 0x01000000) + goto bad_table; + strend = machine_opcodes[i ].args+strlen(machine_opcodes[i ].args)-1; + strend2 = machine_opcodes[i+1].args+strlen(machine_opcodes[i+1].args)-1; + switch (*strend) { + case 'b': + if (*strend2 != 'i') goto bad_table; + break; + case 'i': + if (*strend2 != 'b') goto bad_table; + break; + case 'P': + if (*strend2 != 'A') goto bad_table; + break; + case 'A': + if (*strend2 != 'P') goto bad_table; + break; + default: + bad_table: + fprintf (stderr, "internal error: can't handle opcode %s\n", name); + lose = 1; + } + + /* OK, this is an i/b or A/P pair. We skip the higher-valued one, + and let the code for operand checking handle OR-ing in the bit. */ + if (machine_opcodes[i].opcode & 1) + continue; + else + skipnext = 1; + } + + retval = hash_insert (op_hash, name, &machine_opcodes[i]); + if (retval != NULL && *retval != '\0') + { + fprintf (stderr, "internal error: can't hash `%s': %s\n", + machine_opcodes[i].name, retval); + lose = 1; + } + } + + if (lose) + as_fatal("Broken assembler. No assembly attempted."); + + for (i = '0'; i < '8'; ++i) + octal[i] = 1; + for (i = '0'; i <= '9'; ++i) + toHex[i] = i - '0'; + for (i = 'a'; i <= 'f'; ++i) + toHex[i] = i + 10 - 'a'; + for (i = 'A'; i <= 'F'; ++i) + toHex[i] = i + 10 - 'A'; + + define_some_regs (); +} + +void md_end() { + return; +} + +/* Assemble a single instruction. Its label has already been handled + by the generic front end. We just parse opcode and operands, and + produce the bytes of data and relocation. */ + +void md_assemble(str) +char *str; +{ + char *toP; + /* !!!! int rsd; */ + + know(str); + machine_ip(str); + toP = frag_more(4); + /* put out the opcode */ + md_number_to_chars(toP, the_insn.opcode, 4); + + /* put out the symbol-dependent stuff */ + if (the_insn.reloc != NO_RELOC) { + fix_new( + frag_now, /* which frag */ + (toP - frag_now->fr_literal + the_insn.reloc_offset), /* where */ + 4, /* size */ + the_insn.exp.X_add_symbol, + the_insn.exp.X_subtract_symbol, + the_insn.exp.X_add_number, + the_insn.pcrel, + the_insn.reloc + ); + } +} + +char * + parse_operand (s, operandp) +char *s; +expressionS *operandp; +{ + char *save = input_line_pointer; + char *new; + segT seg; + + input_line_pointer = s; + seg = expr (0, operandp); + new = input_line_pointer; + input_line_pointer = save; + + switch (seg) { + case SEG_ABSOLUTE: + case SEG_TEXT: + case SEG_DATA: + case SEG_BSS: + case SEG_UNKNOWN: + case SEG_DIFFERENCE: + case SEG_BIG: + case SEG_REGISTER: + return new; + + case SEG_ABSENT: + as_bad("Missing operand"); + return new; + + default: + as_bad("Don't understand operand of type %s", segment_name (seg)); + return new; + } +} + +/* Instruction parsing. Takes a string containing the opcode. + Operands are at input_line_pointer. Output is in the_insn. + Warnings or errors are generated. */ + +static void + machine_ip(str) +char *str; +{ + char *s; + const char *args; + /* !!!! char c; */ + /* !!!! unsigned long i; */ + struct machine_opcode *insn; + char *argsStart; + unsigned long opcode; + /* !!!! unsigned int mask; */ + expressionS the_operand; + expressionS *operand = &the_operand; + unsigned int reg; + + /* Must handle `div0' opcode. */ + s = str; + if (isalpha(*s)) + for (; isalnum(*s); ++s) + if (isupper (*s)) + *s = tolower (*s); + + switch (*s) { + case '\0': + break; + + case ' ': /* FIXME-SOMEDAY more whitespace */ + *s++ = '\0'; + break; + + default: + as_bad("Unknown opcode: `%s'", str); + return; + } + if ((insn = (struct machine_opcode *) hash_find(op_hash, str)) == NULL) { + as_bad("Unknown opcode `%s'.", str); + return; + } + argsStart = s; + opcode = insn->opcode; + memset(&the_insn, '\0', sizeof(the_insn)); + the_insn.reloc = NO_RELOC; + + /* + * Build the opcode, checking as we go to make + * sure that the operands match. + * + * If an operand matches, we modify the_insn or opcode appropriately, + * and do a "continue". If an operand fails to match, we "break". + */ + if (insn->args[0] != '\0') + s = parse_operand (s, operand); /* Prime the pump */ + + for (args = insn->args; ; ++args) { + switch (*args) { + + case '\0': /* end of args */ + if (*s == '\0') { + /* We are truly done. */ + the_insn.opcode = opcode; + return; + } + as_bad("Too many operands: %s", s); + break; + + case ',': /* Must match a comma */ + if (*s++ == ',') { + s = parse_operand (s, operand); /* Parse next opnd */ + continue; + } + break; + + case 'v': /* Trap numbers (immediate field) */ + if (operand->X_seg == SEG_ABSOLUTE) { + if (operand->X_add_number < 256) { + opcode |= (operand->X_add_number << 16); + continue; + } else { + as_bad("Immediate value of %d is too large", + operand->X_add_number); + continue; + } + } + the_insn.reloc = RELOC_8; + the_insn.reloc_offset = 1; /* BIG-ENDIAN Byte 1 of insn */ + the_insn.exp = *operand; + continue; + + case 'b': /* A general register or 8-bit immediate */ + case 'i': + /* We treat the two cases identically since we mashed + them together in the opcode table. */ + if (operand->X_seg == SEG_REGISTER) + goto general_reg; + + opcode |= IMMEDIATE_BIT; + if (operand->X_seg == SEG_ABSOLUTE) { + if (operand->X_add_number < 256) { + opcode |= operand->X_add_number; + continue; + } else { + as_bad("Immediate value of %d is too large", + operand->X_add_number); + continue; + } + } + the_insn.reloc = RELOC_8; + the_insn.reloc_offset = 3; /* BIG-ENDIAN Byte 3 of insn */ + the_insn.exp = *operand; + continue; + + case 'a': /* next operand must be a register */ + case 'c': + general_reg: + /* lrNNN or grNNN or %%expr or a user-def register name */ + if (operand->X_seg != SEG_REGISTER) + break; /* Only registers */ + know (operand->X_add_symbol == 0); + know (operand->X_subtract_symbol == 0); + reg = operand->X_add_number; + if (reg >= SREG) + break; /* No special registers */ + + /* + * Got the register, now figure out where + * it goes in the opcode. + */ + switch (*args) { + case 'a': + opcode |= reg << 8; + continue; + + case 'b': + case 'i': + opcode |= reg; + continue; + + case 'c': + opcode |= reg << 16; + continue; + } + as_fatal("failed sanity check."); + break; + + case 'x': /* 16 bit constant, zero-extended */ + case 'X': /* 16 bit constant, one-extended */ + if (operand->X_seg == SEG_ABSOLUTE) { + opcode |= (operand->X_add_number & 0xFF) << 0 | + ((operand->X_add_number & 0xFF00) << 8); + continue; + } + the_insn.reloc = RELOC_CONST; + the_insn.exp = *operand; + continue; + + case 'h': + if (operand->X_seg == SEG_ABSOLUTE) { + opcode |= (operand->X_add_number & 0x00FF0000) >> 16 | + (((unsigned long)operand->X_add_number + /* avoid sign ext */ & 0xFF000000) >> 8); + continue; + } + the_insn.reloc = RELOC_CONSTH; + the_insn.exp = *operand; + continue; + + case 'P': /* PC-relative jump address */ + case 'A': /* Absolute jump address */ + /* These two are treated together since we folded the + opcode table entries together. */ + if (operand->X_seg == SEG_ABSOLUTE) { + opcode |= ABSOLUTE_BIT | + (operand->X_add_number & 0x0003FC00) << 6 | + ((operand->X_add_number & 0x000003FC) >> 2); + continue; + } + the_insn.reloc = RELOC_JUMPTARG; + the_insn.exp = *operand; + the_insn.pcrel = 1; /* Assume PC-relative jump */ + /* FIXME-SOON, Do we figure out whether abs later, after know sym val? */ + continue; + + case 'e': /* Coprocessor enable bit for LOAD/STORE insn */ + if (operand->X_seg == SEG_ABSOLUTE) { + if (operand->X_add_number == 0) + continue; + if (operand->X_add_number == 1) { + opcode |= CE_BIT; + continue; + } + } + break; + + case 'n': /* Control bits for LOAD/STORE instructions */ + if (operand->X_seg == SEG_ABSOLUTE && + operand->X_add_number < 128) { + opcode |= (operand->X_add_number << 16); + continue; + } + break; + + case 's': /* Special register number */ + if (operand->X_seg != SEG_REGISTER) + break; /* Only registers */ + if (operand->X_add_number < SREG) + break; /* Not a special register */ + opcode |= (operand->X_add_number & 0xFF) << 8; + continue; + + case 'u': /* UI bit of CONVERT */ + if (operand->X_seg == SEG_ABSOLUTE) { + if (operand->X_add_number == 0) + continue; + if (operand->X_add_number == 1) { + opcode |= UI_BIT; + continue; + } + } + break; + + case 'r': /* RND bits of CONVERT */ + if (operand->X_seg == SEG_ABSOLUTE && + operand->X_add_number < 8) { + opcode |= operand->X_add_number << 4; + continue; + } + break; + + case 'd': /* FD bits of CONVERT */ + if (operand->X_seg == SEG_ABSOLUTE && + operand->X_add_number < 4) { + opcode |= operand->X_add_number << 2; + continue; + } + break; + + + case 'f': /* FS bits of CONVERT */ + if (operand->X_seg == SEG_ABSOLUTE && + operand->X_add_number < 4) { + opcode |= operand->X_add_number << 0; + continue; + } + break; + + case 'C': + if (operand->X_seg == SEG_ABSOLUTE && + operand->X_add_number < 4) { + opcode |= operand->X_add_number << 16; + continue; + } + break; + + case 'F': + if (operand->X_seg == SEG_ABSOLUTE && + operand->X_add_number < 16) { + opcode |= operand->X_add_number << 18; + continue; + } + break; + + default: + BAD_CASE (*args); + } + /* Types or values of args don't match. */ + as_bad("Invalid operands"); + return; + } +} + +/* + This is identical to the md_atof in m68k.c. I think this is right, + but I'm not sure. + + Turn a string in input_line_pointer into a floating point constant of type + type, and store the appropriate bytes in *litP. The number of LITTLENUMS + emitted is stored in *sizeP. An error message is returned, or NULL on OK. + */ + +/* Equal to MAX_PRECISION in atof-ieee.c */ +#define MAX_LITTLENUMS 6 + +char * + md_atof(type,litP,sizeP) +char type; +char *litP; +int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + + switch (type) { + + case 'f': + case 'F': + case 's': + case 'S': + prec = 2; + break; + + case 'd': + case 'D': + case 'r': + case 'R': + prec = 4; + break; + + case 'x': + case 'X': + prec = 6; + break; + + case 'p': + case 'P': + prec = 6; + break; + + default: + *sizeP=0; + return "Bad call to MD_ATOF()"; + } + t=atof_ieee(input_line_pointer,type,words); + if (t) + input_line_pointer=t; + *sizeP=prec * sizeof(LITTLENUM_TYPE); + for (wordP=words;prec--;) { + md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE)); + litP+=sizeof(LITTLENUM_TYPE); + } + return ""; /* Someone should teach Dean about null pointers */ +} + +/* + * Write out big-endian. + */ +void + md_number_to_chars(buf, val, n) +char *buf; +long val; +int n; +{ + + switch (n) { + + case 4: + *buf++ = val >> 24; + *buf++ = val >> 16; + case 2: + *buf++ = val >> 8; + case 1: + *buf = val; + break; + + default: + as_fatal("failed sanity check."); + } + return; +} + +void md_apply_fix(fixP, val) +fixS *fixP; +long val; +{ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + + fixP->fx_addnumber = val; /* Remember value for emit_reloc */ + + + know(fixP->fx_size == 4); + know(fixP->fx_r_type < NO_RELOC); + + /* + * This is a hack. There should be a better way to + * handle this. + */ + if (fixP->fx_r_type == RELOC_WDISP30 && fixP->fx_addsy) { + val += fixP->fx_where + fixP->fx_frag->fr_address; + } + + switch (fixP->fx_r_type) { + + case RELOC_32: + buf[0] = val >> 24; + buf[1] = val >> 16; + buf[2] = val >> 8; + buf[3] = val; + break; + + case RELOC_8: + buf[0] = val; + break; + + case RELOC_WDISP30: + val = (val >>= 2) + 1; + buf[0] |= (val >> 24) & 0x3f; + buf[1]= (val >> 16); + buf[2] = val >> 8; + buf[3] = val; + break; + + case RELOC_HI22: + buf[1] |= (val >> 26) & 0x3f; + buf[2] = val >> 18; + buf[3] = val >> 10; + break; + + case RELOC_LO10: + buf[2] |= (val >> 8) & 0x03; + buf[3] = val; + break; + + case RELOC_BASE13: + buf[2] |= (val >> 8) & 0x1f; + buf[3] = val; + break; + + case RELOC_WDISP22: + val = (val >>= 2) + 1; + /* FALLTHROUGH */ + case RELOC_BASE22: + buf[1] |= (val >> 16) & 0x3f; + buf[2] = val >> 8; + buf[3] = val; + break; + +#if 0 + case RELOC_PC10: + case RELOC_PC22: + case RELOC_JMP_TBL: + case RELOC_SEGOFF16: + case RELOC_GLOB_DAT: + case RELOC_JMP_SLOT: + case RELOC_RELATIVE: +#endif + case RELOC_JUMPTARG: /* 00XX00XX pattern in a word */ + buf[1] = val >> 10; /* Holds bits 0003FFFC of address */ + buf[3] = val >> 2; + break; + + case RELOC_CONST: /* 00XX00XX pattern in a word */ + buf[1] = val >> 8; /* Holds bits 0000XXXX */ + buf[3] = val; + break; + + case RELOC_CONSTH: /* 00XX00XX pattern in a word */ + buf[1] = val >> 24; /* Holds bits XXXX0000 */ + buf[3] = val >> 16; + break; + + case NO_RELOC: + default: + as_bad("bad relocation type: 0x%02x", fixP->fx_r_type); + break; + } + return; +} + +#ifdef OBJ_COFF +short tc_coff_fix2rtype(fixP) +fixS *fixP; +{ + + /* FIXME-NOW: relocation type handling is not yet written for + a29k. */ + + + switch (fixP->fx_r_type) { + case RELOC_32: return(R_WORD); + case RELOC_8: return(R_BYTE); + case RELOC_CONST: return (R_ILOHALF); + case RELOC_CONSTH: return (R_IHIHALF); + case RELOC_JUMPTARG: return (R_IREL); + default: printf("need %o3\n", fixP->fx_r_type); + abort(0); + } /* switch on type */ + + return(0); +} /* tc_coff_fix2rtype() */ +#endif /* OBJ_COFF */ + +/* should never be called for sparc */ +void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol) +char *ptr; +long from_addr, to_addr; +fragS *frag; +symbolS *to_symbol; +{ + as_fatal("a29k_create_short_jmp\n"); +} + +/* should never be called for 29k */ +void md_convert_frag(headers, fragP) +object_headers *headers; +register fragS *fragP; +{ + as_fatal("sparc_convert_frag\n"); +} + +/* should never be called for 29k */ +void md_create_long_jump(ptr, from_addr, to_addr, frag, to_symbol) +char *ptr; +long from_addr; +long to_addr; +fragS *frag; +symbolS *to_symbol; +{ + as_fatal("sparc_create_long_jump\n"); +} + +/* should never be called for a29k */ +int md_estimate_size_before_relax(fragP, segtype) +register fragS *fragP; +segT segtype; +{ + as_fatal("sparc_estimate_size_before_relax\n"); + return(0); +} + +#if 0 +/* for debugging only */ +static void + print_insn(insn) +struct machine_it *insn; +{ + char *Reloc[] = { + "RELOC_8", + "RELOC_16", + "RELOC_32", + "RELOC_DISP8", + "RELOC_DISP16", + "RELOC_DISP32", + "RELOC_WDISP30", + "RELOC_WDISP22", + "RELOC_HI22", + "RELOC_22", + "RELOC_13", + "RELOC_LO10", + "RELOC_SFA_BASE", + "RELOC_SFA_OFF13", + "RELOC_BASE10", + "RELOC_BASE13", + "RELOC_BASE22", + "RELOC_PC10", + "RELOC_PC22", + "RELOC_JMP_TBL", + "RELOC_SEGOFF16", + "RELOC_GLOB_DAT", + "RELOC_JMP_SLOT", + "RELOC_RELATIVE", + "NO_RELOC" + }; + + if (insn->error) { + fprintf(stderr, "ERROR: %s\n"); + } + fprintf(stderr, "opcode=0x%08x\n", insn->opcode); + fprintf(stderr, "reloc = %s\n", Reloc[insn->reloc]); + fprintf(stderr, "exp = {\n"); + fprintf(stderr, "\t\tX_add_symbol = %s\n", + insn->exp.X_add_symbol ? + (S_GET_NAME(insn->exp.X_add_symbol) ? + S_GET_NAME(insn->exp.X_add_symbol) : "???") : "0"); + fprintf(stderr, "\t\tX_sub_symbol = %s\n", + insn->exp.X_subtract_symbol ? + (S_GET_NAME(insn->exp.X_subtract_symbol) ? + S_GET_NAME(insn->exp.X_subtract_symbol) : "???") : "0"); + fprintf(stderr, "\t\tX_add_number = %d\n", + insn->exp.X_add_number); + fprintf(stderr, "}\n"); + return; +} +#endif + +/* Translate internal representation of relocation info to target format. + + On sparc/29k: first 4 bytes are normal unsigned long address, next three + bytes are index, most sig. byte first. Byte 7 is broken up with + bit 7 as external, bits 6 & 5 unused, and the lower + five bits as relocation type. Next 4 bytes are long addend. */ +/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */ + +#ifdef OBJ_AOUT + +void tc_aout_fix_to_chars(where, fixP, segment_address_in_file) +char *where; +fixS *fixP; +relax_addressT segment_address_in_file; +{ + long r_symbolnum; + + know(fixP->fx_r_type < NO_RELOC); + know(fixP->fx_addsy != NULL); + + md_number_to_chars(where, + fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, + 4); + + r_symbolnum = (S_IS_DEFINED(fixP->fx_addsy) + ? S_GET_TYPE(fixP->fx_addsy) + : fixP->fx_addsy->sy_number); + + where[4] = (r_symbolnum >> 16) & 0x0ff; + where[5] = (r_symbolnum >> 8) & 0x0ff; + where[6] = r_symbolnum & 0x0ff; + where[7] = (((!S_IS_DEFINED(fixP->fx_addsy)) << 7) & 0x80) | (0 & 0x60) | (fixP->fx_r_type & 0x1F); + /* Also easy */ + md_number_to_chars(&where[8], fixP->fx_addnumber, 4); + + return; +} /* tc_aout_fix_to_chars() */ + +#endif /* OBJ_AOUT */ + +int + md_parse_option(argP,cntP,vecP) +char **argP; +int *cntP; +char ***vecP; +{ + return(0); +} + + +/* Default the values of symbols known that should be "predefined". We + don't bother to predefine them unless you actually use one, since there + are a lot of them. */ + +symbolS *md_undefined_symbol (name) +char *name; +{ + long regnum; + char testbuf[5+ /*SLOP*/ 5]; + + if (name[0] == 'g' || name[0] == 'G' || name[0] == 'l' || name[0] == 'L') + { + /* Perhaps a global or local register name */ + if (name[1] == 'r' || name[1] == 'R') + { + /* Parse the number, make sure it has no extra zeroes or trailing + chars */ + regnum = atol(&name[2]); + if (regnum > 127) + return 0; + sprintf(testbuf, "%ld", regnum); + if (strcmp (testbuf, &name[2]) != 0) + return 0; /* gr007 or lr7foo or whatever */ + + /* We have a wiener! Define and return a new symbol for it. */ + if (name[0] == 'l' || name[0] == 'L') + regnum += 128; + return(symbol_new(name, SEG_REGISTER, regnum, &zero_address_frag)); + } + } + + return 0; +} + +/* Parse an operand that is machine-specific. */ + +void md_operand(expressionP) +expressionS *expressionP; +{ + + if (input_line_pointer[0] == '%' && input_line_pointer[1] == '%') + { + /* We have a numeric register expression. No biggy. */ + input_line_pointer += 2; /* Skip %% */ + (void)expression (expressionP); + if (expressionP->X_seg != SEG_ABSOLUTE + || expressionP->X_add_number > 255) + as_bad("Invalid expression after %%%%\n"); + expressionP->X_seg = SEG_REGISTER; + } + else if (input_line_pointer[0] == '&') + { + /* We are taking the 'address' of a register...this one is not + in the manual, but it *is* in traps/fpsymbol.h! What they + seem to want is the register number, as an absolute number. */ + input_line_pointer++; /* Skip & */ + (void)expression (expressionP); + if (expressionP->X_seg != SEG_REGISTER) + as_bad("Invalid register in & expression"); + else + expressionP->X_seg = SEG_ABSOLUTE; + } +} + +/* Round up a section size to the appropriate boundary. */ +long + md_section_align (segment, size) +segT segment; +long size; +{ + return size; /* Byte alignment is fine */ +} + +/* Exactly what point is a PC-relative offset relative TO? + On the 29000, they're relative to the address of the instruction, + which we have set up as the address of the fixup too. */ +long md_pcrel_from (fixP) +fixS *fixP; +{ + return fixP->fx_where + fixP->fx_frag->fr_address; +} + +/* + * Local Variables: + * comment-column: 0 + * End: + */ + +/* end of tc-a29k.c */ diff --git a/gnu/usr.bin/as/config/tc-a29k.h b/gnu/usr.bin/as/config/tc-a29k.h new file mode 100644 index 000000000000..fee1ca2b67d2 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-a29k.h @@ -0,0 +1,40 @@ +/* tc-a29k.h -- Assemble for the AMD 29000. + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define TC_A29K + +#define NO_LISTING + +#define tc_aout_pre_write_hook(x) {;} /* not used */ +#define tc_coff_symbol_emit_hook(a) {;} /* not used */ +#define tc_crawl_symbol_chain(a) {;} /* not used */ +#define tc_headers_hook(a) {;} /* not used */ + +#define AOUT_MACHTYPE 101 +#define TC_COFF_FIX2RTYPE(fix_ptr) tc_coff_fix2rtype(fix_ptr) +#define BFD_ARCH bfd_arch_a29k +#define COFF_MAGIC SIPFBOMAGIC + +/* Should the reloc be output ? + on the 29k, this is true only if there is a symbol attatched. + on the h8, this is allways true, since no fixup is done + */ +#define TC_COUNT_RELOC(x) (x->fx_addsy) + +/* end of tc-a29k.h */ diff --git a/gnu/usr.bin/as/config/tc-generic.c b/gnu/usr.bin/as/config/tc-generic.c new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-generic.c diff --git a/gnu/usr.bin/as/config/tc-generic.h b/gnu/usr.bin/as/config/tc-generic.h new file mode 100644 index 000000000000..181d4aa0b788 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-generic.h @@ -0,0 +1,37 @@ +/* This file is tc-generic.h + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * This file is tc-generic.h and is intended to be a template for target cpu + * specific header files. It is my intent that this file compile. It is also + * my intent that this file grow into something that can be used as both a + * template for porting, and a stub for testing. xoxorich. + */ + +#define TC_GENERIC 1 + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of tc-generic.h */ diff --git a/gnu/usr.bin/as/config/tc-h8300.c b/gnu/usr.bin/as/config/tc-h8300.c new file mode 100644 index 000000000000..db4786bbfac2 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-h8300.c @@ -0,0 +1,1295 @@ +/* tc-h8300.c -- Assemble code for the Hitachi H8/300 + Copyright (C) 1991, 1992 Free Software Foundation. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* + Written By Steve Chamberlain + sac@cygnus.com + */ + +#include <stdio.h> +#include "as.h" +#include "bfd.h" +#include "opcode/h8300.h" +#include <ctype.h> +#include "listing.h" + +char comment_chars[] = { ';',0 }; +char line_separator_chars[] = { '$' ,0}; + +/* This table describes all the machine specific pseudo-ops the assembler + has to support. The fields are: + pseudo-op name without dot + function to call to execute this pseudo-op + Integer arg to pass to the function + */ + +void cons(); + +const pseudo_typeS md_pseudo_table[] = { + { "int", cons, 2 }, + { 0,0,0 } +}; + +int md_reloc_size ; + +const char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant */ +/* As in 0f12.456 */ +/* or 0d1.2345e12 */ +char FLT_CHARS[] = "rRsSfFdDxXpP"; + + +const relax_typeS md_relax_table[1]; + + +static struct hash_control *opcode_hash_control; /* Opcode mnemonics */ + + +/* + This function is called once, at assembler startup time. This should + set up all the tables, etc that the MD part of the assembler needs + */ +#if 0 +/* encode the size and number into the number field + xxnnnn + 00 8 bit + 01 16 bit + 10 ccr + nnnnreg number + */ +#define WORD_REG 0x10 +#define BYTE_REG 0x00 +#define CCR_REG 0x20 +struct reg_entry +{ + char *name; + char number; +}; + +struct reg_entry reg_list[] = { + "r0",WORD_REG +0, + "r1",WORD_REG +1, + "r2",WORD_REG +2, + "r3",WORD_REG +3, + "r4",WORD_REG +4, + "r5",WORD_REG +5, + "r6",WORD_REG +6, + "r7",WORD_REG +7, + "fp",WORD_REG +6, + "sp",WORD_REG +7, + "r0h",BYTE_REG + 0, + "r0l",BYTE_REG + 1, + "r1h",BYTE_REG + 2, + "r1l",BYTE_REG + 3, + "r2h",BYTE_REG + 4, + "r2l",BYTE_REG + 5, + "r3h",BYTE_REG + 6, + "r3l",BYTE_REG + 7, + "r4h",BYTE_REG + 8, + "r4l",BYTE_REG + 9, + "r5h",BYTE_REG + 10, + "r5l",BYTE_REG + 11, + "r6h",BYTE_REG + 12, + "r6l",BYTE_REG + 13, + "r7h",BYTE_REG + 14, + "r7l",BYTE_REG + 15, + "ccr",CCR_REG, + 0,0 + } +; + + +#endif + + +void md_begin () +{ + struct h8_opcode *opcode; + const struct reg_entry *reg; + char prev_buffer[100]; + int idx = 0; + + opcode_hash_control = hash_new(); + prev_buffer[0] = 0; + + for (opcode = h8_opcodes; opcode->name; opcode++) + { + /* Strip off any . part when inserting the opcode and only enter + unique codes into the hash table + */ + char *src= opcode->name; + unsigned int len = strlen(src); + char *dst = malloc(len+1); + char *buffer = dst; + opcode->size = 0; + while (*src) { + if (*src == '.') { + *dst++ = 0; + src++; + opcode->size = *src; + break; + } + *dst++ = *src++; + } + if (strcmp(buffer, prev_buffer)) + { + hash_insert(opcode_hash_control, buffer, (char *)opcode); + strcpy(prev_buffer, buffer); + idx++; + } + opcode->idx = idx; + + + /* Find the number of operands */ + opcode->noperands = 0; + while (opcode->args.nib[opcode->noperands] != E) + opcode->noperands ++; + /* Find the length of the opcode in bytes */ + opcode->length =0; + while (opcode->data.nib[opcode->length*2] != E) + opcode->length++; + } + +} + + +struct h8_exp { + char *e_beg; + char *e_end; + expressionS e_exp; +}; +struct h8_op +{ + unsigned int dispreg; + op_type mode; + unsigned reg; + expressionS exp; +}; + + + +/* + parse operands + WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp + r0l,r0h,..r7l,r7h + @WREG + @WREG+ + @-WREG + #const + + */ + +op_type r8_sord[] = {RS8, RD8}; +op_type r16_sord[] = {RS16, RD16}; +op_type rind_sord[] = {RSIND, RDIND}; +op_type abs_sord[2] = {ABS16SRC, ABS16DST}; +op_type disp_sord[] = {DISPSRC, DISPDST}; + +/* try and parse a reg name, returns number of chars consumed */ +int + DEFUN(parse_reg,(src, mode, reg, dst), + char *src AND + op_type *mode AND + unsigned int *reg AND + int dst) +{ + if (src[0] == 's' && src[1] == 'p') + { + *mode = r16_sord[dst]; + *reg = 7; + return 2; + } + if (src[0] == 'c' && src[1] == 'c' && src[2] == 'r') + { + *mode = CCR; + *reg = 0; + return 3; + } + if (src[0] == 'f' && src[1] == 'p') + { + *mode = r16_sord[dst]; + *reg = 6; + return 2; + } + if (src[0] == 'r') + { + if (src[1] >= '0' && src[1] <= '7') + { + if (src[2] == 'l') + { + *mode = r8_sord[dst]; + *reg = (src[1] - '0') + 8; + return 3; + } + if (src[2] == 'h') + { + *mode = r8_sord[dst]; + *reg = (src[1] - '0') ; + return 3; + } + *mode = r16_sord[dst]; + *reg = (src[1] - '0'); + return 2; + } + } + return 0; +} + +char * + DEFUN(parse_exp,(s, op), + char *s AND + expressionS *op) +{ + char *save = input_line_pointer; + char *new; + segT seg; + input_line_pointer = s; + seg = expr(0,op); + new = input_line_pointer; + input_line_pointer = save; + if (SEG_NORMAL(seg)) + return new; + switch (seg) { + case SEG_ABSOLUTE: + case SEG_UNKNOWN: + case SEG_DIFFERENCE: + case SEG_BIG: + case SEG_REGISTER: + return new; + case SEG_ABSENT: + as_bad("Missing operand"); + return new; + default: + as_bad("Don't understand operand of type %s", segment_name (seg)); + return new; + } +} + +static char * + DEFUN(skip_colonthing,(ptr), + char *ptr) +{ + if (*ptr == ':') { + ptr++; + while (isdigit(*ptr)) + ptr++; + + } + return ptr; +} + +/* The many forms of operand: + + Rn Register direct + @Rn Register indirect + @(exp[:16], Rn) Register indirect with displacement + @Rn+ + @-Rn + @aa:8 absolute 8 bit + @aa:16 absolute 16 bit + @aa absolute 16 bit + + #xx[:size] immediate data + @(exp:[8], pc) pc rel + @@aa[:8] memory indirect + + */ + +static void + DEFUN(get_operand,(ptr, op, dst), + char **ptr AND + struct h8_op *op AND + unsigned int dst) +{ + char *src = *ptr; + op_type mode; + unsigned int num; + unsigned int len; + unsigned int size; + op->mode = E; + + len = parse_reg(src, &op->mode, &op->reg, dst); + if (len) { + *ptr = src + len; + return ; + } + + if (*src == '@') + { + src++; + if (*src == '@') + { + src++; + src = parse_exp(src,&op->exp); + src = skip_colonthing(src); + + *ptr = src; + + op->mode = MEMIND; + return; + + } + + + if (*src == '-') + { + src++; + len = parse_reg(src, &mode, &num, dst); + if (len == 0) + { + /* Oops, not a reg after all, must be ordinary exp */ + src--; + /* must be a symbol */ + op->mode = abs_sord[dst]; + *ptr = skip_colonthing(parse_exp(src, &op->exp)); + + return; + + + } + + if (mode != r16_sord[dst]) + { + as_bad("@- needs word register"); + } + op->mode = RDDEC; + op->reg = num; + *ptr = src + len; + return; + } + if (*src == '(' && ')') + { + /* Disp */ + src++; + src = parse_exp(src, &op->exp); + + if (*src == ')') + { + src++; + op->mode = abs_sord[dst]; + *ptr = src; + return; + } + src = skip_colonthing(src); + + if (*src != ',') + { + as_bad("expected @(exp, reg16)"); + } + src++; + len = parse_reg(src, &mode, &op->reg, dst); + if (len == 0 || mode != r16_sord[dst]) + { + as_bad("expected @(exp, reg16)"); + } + op->mode = disp_sord[dst]; + src += len; + src = skip_colonthing(src); + + if (*src != ')' && '(') + { + as_bad("expected @(exp, reg16)"); + + } + *ptr = src +1; + + return; + } + len = parse_reg(src, &mode, &num, dst); + + if (len) { + src += len; + if (*src == '+') + { + src++; + if (mode != RS16) + { + as_bad("@Rn+ needs src word register"); + } + op->mode = RSINC; + op->reg = num; + *ptr = src; + return; + } + if (mode != r16_sord[dst]) + { + as_bad("@Rn needs word register"); + } + op->mode =rind_sord[dst]; + op->reg = num; + *ptr = src; + return; + } + else + { + /* must be a symbol */ + op->mode = abs_sord[dst]; + *ptr = skip_colonthing(parse_exp(src, &op->exp)); + + return; + } + } + + + if (*src == '#') { + src++; + op->mode = IMM16; + src = parse_exp(src, &op->exp); + *ptr= skip_colonthing(src); + + return; + } + else { + *ptr = parse_exp(src, &op->exp); + op->mode = DISP8; + } +} + + +static + char * + DEFUN(get_operands,(noperands,op_end, operand), + unsigned int noperands AND + char *op_end AND + struct h8_op *operand) +{ + char *ptr = op_end; + switch (noperands) + { + case 0: + operand[0].mode = 0; + operand[1].mode = 0; + break; + + case 1: + ptr++; + get_operand(& ptr, operand +0,0); + operand[1].mode =0; + break; + + case 2: + ptr++; + get_operand(& ptr, operand +0,0); + if (*ptr == ',') ptr++; + get_operand(& ptr, operand +1, 1); + break; + + default: + abort(); + } + + + return ptr; +} + +/* Passed a pointer to a list of opcodes which use different + addressing modes, return the opcode which matches the opcodes + provided + */ +static + struct h8_opcode * + DEFUN(get_specific,(opcode, operands), + struct h8_opcode *opcode AND + struct h8_op *operands) + +{ + struct h8_opcode *this_try = opcode ; + int found = 0; + unsigned int noperands = opcode->noperands; + + unsigned int dispreg; + unsigned int this_index = opcode->idx; + while (this_index == opcode->idx && !found) + { + unsigned int i; + + this_try = opcode ++; + for (i = 0; i < noperands; i++) + { + op_type op = (this_try->args.nib[i]) & ~(B30|B31); + switch (op) + { + case Hex0: + case Hex1: + case Hex2: + case Hex3: + case Hex4: + case Hex5: + case Hex6: + case Hex7: + case Hex8: + case Hex9: + case HexA: + case HexB: + case HexC: + case HexD: + case HexE: + case HexF: + break; + case DISPSRC: + case DISPDST: + operands[0].dispreg = operands[i].reg; + case RD8: + case RS8: + case RDIND: + case RSIND: + case RD16: + case RS16: + case CCR: + case RSINC: + case RDDEC: + if (operands[i].mode != op) goto fail; + break; + case KBIT: + case IMM16: + case IMM3: + case IMM8: + if (operands[i].mode != IMM16) goto fail; + break; + case MEMIND: + if (operands[i].mode != MEMIND) goto fail; + break; + case ABS16SRC: + case ABS8SRC: + case ABS16OR8SRC: + case ABS16ORREL8SRC: + + if (operands[i].mode != ABS16SRC) goto fail; + break; + case ABS16OR8DST: + case ABS16DST: + case ABS8DST: + if (operands[i].mode != ABS16DST) goto fail; + break; + } + } + found =1; + fail: ; + } + if (found) + return this_try; + else + return 0; +} + +static void + DEFUN(check_operand,(operand, width, string), + struct h8_op *operand AND + unsigned int width AND + char *string) +{ + if (operand->exp.X_add_symbol == 0 + && operand->exp.X_subtract_symbol == 0) + { + + /* No symbol involved, let's look at offset, it's dangerous if any of + the high bits are not 0 or ff's, find out by oring or anding with + the width and seeing if the answer is 0 or all fs*/ + if ((operand->exp.X_add_number | width) != ~0 && + (operand->exp.X_add_number & ~width) != 0) + { + as_warn("operand %s0x%x out of range.", string, operand->exp.X_add_number); + } + } + +} + +/* Now we know what sort of opcodes it is, lets build the bytes - + */ +static void + DEFUN (build_bytes,(this_try, operand), + struct h8_opcode *this_try AND + struct h8_op *operand) + +{ + unsigned int i; + + char *output = frag_more(this_try->length); + char *output_ptr = output; + op_type *nibble_ptr = this_try->data.nib; + char part; + op_type c; + char high; + int nib; + top: ; + while (*nibble_ptr != E) + { + int nibble; + for (nibble = 0; nibble <2; nibble++) + { + c = *nibble_ptr & ~(B30|B31); + switch (c) + { + default: + abort(); + case KBIT: + switch (operand[0].exp.X_add_number) + { + case 1: + nib = 0; + break; + case 2: + nib = 8; + break; + default: + as_bad("Need #1 or #2 here"); + break; + } + /* stop it making a fix */ + operand[0].mode = 0; + break; + case 0: + case 1: + case 2: case 3: case 4: case 5: case 6: + case 7: case 8: case 9: case 10: case 11: + case 12: case 13: case 14: case 15: + nib = c; + break; + case DISPREG: + nib = operand[0].dispreg; + break; + case IMM8: + operand[0].mode = IMM8; + nib = 0; + break; + + case DISPDST: + nib = 0; + break; + case IMM3: + if (operand[0].exp.X_add_symbol == 0) { + operand[0].mode = 0; /* stop it making a fix */ + nib = (operand[0].exp.X_add_number); + } + else as_bad("can't have symbol for bit number"); + if (nib < 0 || nib > 7) + { + as_bad("Bit number out of range %d", nib); + } + + break; + + case ABS16DST: + nib = 0; + break; + case ABS8DST: + operand[1].mode = ABS8DST; + nib = 0; + break; + case ABS8SRC: + operand[0].mode = ABS8SRC; + nib = 0; + break; + case ABS16OR8DST: + operand[1].mode = c; + + nib = 0; + + break; + + case ABS16ORREL8SRC: + operand[0].mode = c; + nib=0; + break; + + case ABS16OR8SRC: + operand[0].mode = ABS16OR8SRC; + nib = 0; + break; + case DISPSRC: + operand[0].mode = ABS16SRC; + nib = 0; + break; + + case DISP8: + operand[0].mode = DISP8; + nib = 0; + break; + + case ABS16SRC: + case IMM16: + case IGNORE: + case MEMIND: + + nib=0; + break; + case RS8: + case RS16: + case RSIND: + case RSINC: + nib = operand[0].reg; + break; + + case RD8: + case RD16: + case RDDEC: + case RDIND: + nib = operand[1].reg; + break; + + case E: + abort(); + break; + } + if (*nibble_ptr & B31) { + nib |=0x8; + } + + if (nibble == 0) { + *output_ptr = nib << 4; + } + else { + *output_ptr |= nib; + output_ptr++; + } + nibble_ptr++; + } + + } + + /* output any fixes */ + for (i = 0; i < 2; i++) + { + switch (operand[i].mode) { + case 0: + break; + + case DISP8: + check_operand(operand+i, 0x7f,"@"); + + fix_new(frag_now, + output - frag_now->fr_literal + 1, + 1, + operand[i].exp.X_add_symbol, + operand[i].exp.X_subtract_symbol, + operand[i].exp.X_add_number -1, + 1, + R_PCRBYTE); + break; + case IMM8: + check_operand(operand+i, 0xff,"#"); + /* If there is nothing else going on we can safely + reloc in place */ + if (operand[i].exp.X_add_symbol == 0) + { + output[1] = operand[i].exp.X_add_number; + } + else + { + fix_new(frag_now, + output - frag_now->fr_literal + 1, + 1, + operand[i].exp.X_add_symbol, + operand[i].exp.X_subtract_symbol, + operand[i].exp.X_add_number, + 0, + R_RELBYTE); + } + + break; + case MEMIND: + check_operand(operand+i, 0xff,"@@"); + fix_new(frag_now, + output - frag_now->fr_literal + 1, + 1, + operand[i].exp.X_add_symbol, + operand[i].exp.X_subtract_symbol, + operand[i].exp.X_add_number, + 0, + R_RELBYTE); + break; + case ABS8DST: + case ABS8SRC: + check_operand(operand+i, 0xff,"@"); + fix_new(frag_now, + output - frag_now->fr_literal + 1, + 1, + operand[i].exp.X_add_symbol, + operand[i].exp.X_subtract_symbol, + operand[i].exp.X_add_number, + 0, + R_RELBYTE); + break; + + case ABS16OR8SRC: + case ABS16OR8DST: + check_operand(operand+i, 0xffff,"@"); + + fix_new(frag_now, + output - frag_now->fr_literal + 2, + 2, + operand[i].exp.X_add_symbol, + operand[i].exp.X_subtract_symbol, + operand[i].exp.X_add_number, + 0, + R_MOVB1); + break; + + case ABS16ORREL8SRC: + check_operand(operand+i, 0xffff,"@"); + + fix_new(frag_now, + output - frag_now->fr_literal + 2, + 2, + operand[i].exp.X_add_symbol, + operand[i].exp.X_subtract_symbol, + operand[i].exp.X_add_number, + 0, + R_JMP1); + break; + + + case ABS16SRC: + case ABS16DST: + case IMM16: + case DISPSRC: + case DISPDST: + check_operand(operand+i, 0xffff,"@"); + if (operand[i].exp.X_add_symbol == 0) + { + /* This should be done with bfd */ + output[3] = operand[i].exp.X_add_number & 0xff; + output[2] = operand[i].exp.X_add_number >> 8; + + } + else + { + + fix_new(frag_now, + output - frag_now->fr_literal + 2, + 2, + operand[i].exp.X_add_symbol, + operand[i].exp.X_subtract_symbol, + operand[i].exp.X_add_number, + 0, + R_RELWORD); + } + + break; + case RS8: + case RD8: + case RS16: + case RD16: + case RDDEC: + case KBIT: + case RSINC: + case RDIND: + case RSIND: + case CCR: + + break; + default: + abort(); + } + } + +} +/* + try and give an intelligent error message for common and simple to + detect errors + */ + +static void + DEFUN(clever_message, (opcode, operand), + struct h8_opcode *opcode AND + struct h8_op *operand) +{ + struct h8_opcode *scan = opcode; + + /* Find out if there was more than one possible opccode */ + + if ((opcode+1)->idx != opcode->idx) + { + unsigned int argn; + + /* Only one opcode of this flavour, try and guess which operand + didn't match */ + for (argn = 0; argn < opcode->noperands; argn++) + { + switch (opcode->args.nib[argn]) + { + case RD16: + if (operand[argn].mode != RD16) + { + as_bad("destination operand must be 16 bit register"); + } + return; + case RS8: + + if (operand[argn].mode != RS8) + { + as_bad("source operand must be 8 bit register"); + } + return; + case ABS16DST: + if (operand[argn].mode != ABS16DST) + { + as_bad("destination operand must be 16bit absolute address"); + return; + } + + case RD8: + if (operand[argn].mode != RD8) + { + as_bad("destination operand must be 8 bit register"); + } + return; + + case ABS16SRC: + if (operand[argn].mode != ABS16SRC) + { + as_bad("source operand must be 16bit absolute address"); + return; + } + } + } + } + as_bad("invalid operands"); +} + +/* This is the guts of the machine-dependent assembler. STR points to a + machine dependent instruction. This funciton is supposed to emit + the frags/bytes it assembles to. + */ + + + +void + DEFUN(md_assemble,(str), + char *str) +{ + char *op_start; + char *op_end; + unsigned int i; + struct h8_op operand[2]; + struct h8_opcode * opcode; + struct h8_opcode * prev_opcode; + + char *dot = 0; + char c; + /* Drop leading whitespace */ + while (*str == ' ') + str++; + + /* find the op code end */ + for (op_start = op_end = str; + *op_end != 0 && *op_end != ' '; + op_end ++) + { + if (*op_end == '.') { + dot = op_end+1; + *op_end = 0; + op_end+=2; + break; + } + } + + ; + + if (op_end == op_start) + { + as_bad("can't find opcode "); + } + c = *op_end; + + *op_end = 0; + + opcode = (struct h8_opcode *) hash_find(opcode_hash_control, + op_start); + + if (opcode == NULL) + { + as_bad("unknown opcode"); + return; + } + + + input_line_pointer = get_operands(opcode->noperands, op_end, + operand); + *op_end = c; + prev_opcode = opcode; + + opcode = get_specific(opcode, operand); + + if (opcode == 0) + { + /* Couldn't find an opcode which matched the operands */ + char *where =frag_more(2); + where[0] = 0x0; + where[1] = 0x0; + clever_message(prev_opcode, operand); + + return; + } + if (opcode->size && dot) + { + if (opcode->size != *dot) + { + as_warn("mismatch between opcode size and operand size"); + } + } + + build_bytes(opcode, operand); + +} + +void + DEFUN(tc_crawl_symbol_chain, (headers), + object_headers *headers) +{ + printf("call to tc_crawl_symbol_chain \n"); +} + +symbolS *DEFUN(md_undefined_symbol,(name), + char *name) +{ + return 0; +} + +void + DEFUN(tc_headers_hook,(headers), + object_headers *headers) +{ + printf("call to tc_headers_hook \n"); +} +void + DEFUN_VOID(md_end) +{ +} + +/* Various routines to kill one day */ +/* Equal to MAX_PRECISION in atof-ieee.c */ +#define MAX_LITTLENUMS 6 + +/* Turn a string in input_line_pointer into a floating point constant of type + type, and store the appropriate bytes in *litP. The number of LITTLENUMS + emitted is stored in *sizeP. An error message is returned, or NULL on OK. + */ +char * + md_atof(type,litP,sizeP) +char type; +char *litP; +int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + char *atof_ieee(); + + switch (type) { + case 'f': + case 'F': + case 's': + case 'S': + prec = 2; + break; + + case 'd': + case 'D': + case 'r': + case 'R': + prec = 4; + break; + + case 'x': + case 'X': + prec = 6; + break; + + case 'p': + case 'P': + prec = 6; + break; + + default: + *sizeP=0; + return "Bad call to MD_ATOF()"; + } + t=atof_ieee(input_line_pointer,type,words); + if (t) + input_line_pointer=t; + + *sizeP=prec * sizeof(LITTLENUM_TYPE); + for (wordP=words;prec--;) { + md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE)); + litP+=sizeof(LITTLENUM_TYPE); + } + return ""; /* Someone should teach Dean about null pointers */ +} + +int + md_parse_option(argP, cntP, vecP) +char **argP; +int *cntP; +char ***vecP; + +{ + return 0; + +} + +int md_short_jump_size; + +void tc_aout_fix_to_chars () { printf("call to tc_aout_fix_to_chars \n"); + abort(); } +void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol) +char *ptr; +long from_addr; +long to_addr; +fragS *frag; +symbolS *to_symbol; +{ + as_fatal("failed sanity check."); +} + +void + md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol) +char *ptr; +long from_addr, to_addr; +fragS *frag; +symbolS *to_symbol; +{ + as_fatal("failed sanity check."); +} + +void + md_convert_frag(headers, fragP) +object_headers *headers; +fragS * fragP; + +{ printf("call to md_convert_frag \n"); abort(); } + +long + DEFUN(md_section_align,(seg, size), + segT seg AND + long size) +{ + return((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg])); + +} + +void + md_apply_fix(fixP, val) +fixS *fixP; +long val; +{ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + + switch (fixP->fx_size) { + case 1: + *buf++=val; + break; + case 2: + *buf++=(val>>8); + *buf++=val; + break; + case 4: + *buf++=(val>>24); + *buf++=(val>>16); + *buf++=(val>>8); + *buf++=val; + break; + default: + abort(); + + } +} + +void DEFUN(md_operand, (expressionP),expressionS *expressionP) +{ } + +int md_long_jump_size; +int + md_estimate_size_before_relax(fragP, segment_type) +register fragS *fragP; +register segT segment_type; +{ + printf("call tomd_estimate_size_before_relax \n"); abort(); } +/* Put number into target byte order */ + +void DEFUN(md_number_to_chars,(ptr, use, nbytes), + char *ptr AND + long use AND + int nbytes) +{ + switch (nbytes) { + case 4: *ptr++ = (use >> 24) & 0xff; + case 3: *ptr++ = (use >> 16) & 0xff; + case 2: *ptr++ = (use >> 8) & 0xff; + case 1: *ptr++ = (use >> 0) & 0xff; + break; + default: + abort(); + } +} +long md_pcrel_from(fixP) +fixS *fixP; { abort(); } + +void tc_coff_symbol_emit_hook() { } + + +void tc_reloc_mangle(fix_ptr, intr, base) +fixS *fix_ptr; +struct internal_reloc *intr; +bfd_vma base; + +{ + symbolS *symbol_ptr; + + symbol_ptr = fix_ptr->fx_addsy; + + /* If this relocation is attached to a symbol then it's ok + to output it */ + if (fix_ptr->fx_r_type == RELOC_32) { + /* cons likes to create reloc32's whatever the size of the reloc.. + */ + switch (fix_ptr->fx_size) + { + + case 2: + intr->r_type = R_RELWORD; + break; + case 1: + intr->r_type = R_RELBYTE; + break; + default: + abort(); + + } + + } + else { + intr->r_type = fix_ptr->fx_r_type; + } + + intr->r_vaddr = fix_ptr->fx_frag->fr_address + fix_ptr->fx_where +base; + intr->r_offset = fix_ptr->fx_offset; + + if (symbol_ptr) + intr->r_symndx = symbol_ptr->sy_number; + else + intr->r_symndx = -1; + + +} + +/* end of tc-h8300.c */ diff --git a/gnu/usr.bin/as/config/tc-h8300.h b/gnu/usr.bin/as/config/tc-h8300.h new file mode 100644 index 000000000000..6da78969c348 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-h8300.h @@ -0,0 +1,38 @@ +/* This file is tc-h8300.h + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#define TC_H8300 + +/* This macro translates between an internal fix and an coff reloc type */ +#define TC_COFF_FIX2RTYPE(fixP) abort(); + +#define BFD_ARCH bfd_arch_h8300 +#define COFF_MAGIC 0x8300 +#define TC_COUNT_RELOC(x) (1) + + +#define TC_RELOC_MANGLE(a,b,c) tc_reloc_mangle(a,b,c) + +#define DO_NOT_STRIP 1 +#define DO_STRIP 0 +#define LISTING_HEADER "Hitachi H8/300 GAS " + +/* end of tc-h8300.h */ diff --git a/gnu/usr.bin/as/config/tc-i386.c b/gnu/usr.bin/as/config/tc-i386.c new file mode 100644 index 000000000000..18717462199a --- /dev/null +++ b/gnu/usr.bin/as/config/tc-i386.c @@ -0,0 +1,2313 @@ +/* i386.c -- Assemble code for the Intel 80386 + Copyright (C) 1989, 1991, 1992 Free Software Foundation. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + Intel 80386 machine specific gas. + Written by Eliot Dresselhaus (eliot@mgm.mit.edu). + Bugs & suggestions are completely welcome. This is free software. + Please help us make it better. + */ + +#ifndef lint +static char rcsid[] = "$Id: tc-i386.c,v 1.2 1993/11/30 20:57:41 jkh Exp $"; +#endif + +#include "as.h" + +#include "obstack.h" +#include "opcode/i386.h" + +/* 'md_assemble ()' gathers together information and puts it into a + i386_insn. */ + +typedef struct { + /* TM holds the template for the insn were currently assembling. */ + template tm; + /* SUFFIX holds the opcode suffix (e.g. 'l' for 'movl') if given. */ + char suffix; + /* Operands are coded with OPERANDS, TYPES, DISPS, IMMS, and REGS. */ + + /* OPERANDS gives the number of given operands. */ + unsigned int operands; + + /* REG_OPERANDS, DISP_OPERANDS, MEM_OPERANDS, IMM_OPERANDS give the number of + given register, displacement, memory operands and immediate operands. */ + unsigned int reg_operands, disp_operands, mem_operands, imm_operands; + + /* TYPES [i] is the type (see above #defines) which tells us how to + search through DISPS [i] & IMMS [i] & REGS [i] for the required + operand. */ + unsigned int types[MAX_OPERANDS]; + + /* Displacements (if given) for each operand. */ + expressionS *disps[MAX_OPERANDS]; + +#ifdef PIC + /* Relocation type for operand */ + enum reloc_type disp_reloc[MAX_OPERANDS]; +#endif + + /* Immediate operands (if given) for each operand. */ + expressionS *imms[MAX_OPERANDS]; + + /* Register operands (if given) for each operand. */ + reg_entry *regs[MAX_OPERANDS]; + + /* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode + the base index byte below. */ + reg_entry *base_reg; + reg_entry *index_reg; + unsigned int log2_scale_factor; + + /* SEG gives the seg_entry of this insn. It is equal to zero unless + an explicit segment override is given. */ + const seg_entry *seg; /* segment for memory operands (if given) */ + + /* PREFIX holds all the given prefix opcodes (usually null). + PREFIXES is the size of PREFIX. */ + /* richfix: really unsigned? */ + unsigned char prefix[MAX_PREFIXES]; + unsigned int prefixes; + + /* RM and IB are the modrm byte and the base index byte where the addressing + modes of this insn are encoded. */ + + modrm_byte rm; + base_index_byte bi; + +} i386_insn; + +/* This array holds the chars that always start a comment. If the + pre-processor is disabled, these aren't very useful */ +const char comment_chars[] = "#"; + +/* This array holds the chars that only start a comment at the beginning of + a line. If the line seems to have the form '# 123 filename' + .line and .file directives will appear in the pre-processed output */ +/* Note that input_file.c hand checks for '#' at the beginning of the + first line of the input file. This is because the compiler outputs + #NO_APP at the beginning of its output. */ +/* Also note that comments started like this one will always work if + '/' isn't otherwise defined. */ +const char line_comment_chars[] = "#/"; /* removed '#' xoxorich. */ + +/* Chars that can be used to separate mant from exp in floating point nums */ +const char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant */ +/* As in 0f12.456 */ +/* or 0d1.2345e12 */ +const char FLT_CHARS[] = "fFdDxX"; + +/* tables for lexical analysis */ +static char opcode_chars[256]; +static char register_chars[256]; +static char operand_chars[256]; +static char space_chars[256]; +static char identifier_chars[256]; +static char digit_chars[256]; + +/* lexical macros */ +#define is_opcode_char(x) (opcode_chars[(unsigned char) x]) +#define is_operand_char(x) (operand_chars[(unsigned char) x]) +#define is_register_char(x) (register_chars[(unsigned char) x]) +#define is_space_char(x) (space_chars[(unsigned char) x]) +#define is_identifier_char(x) (identifier_chars[(unsigned char) x]) +#define is_digit_char(x) (digit_chars[(unsigned char) x]) + +/* put here all non-digit non-letter charcters that may occur in an operand */ +static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:"; + +static char *ordinal_names[] = { "first", "second", "third" }; /* for printfs */ + +/* md_assemble() always leaves the strings it's passed unaltered. To + effect this we maintain a stack of saved characters that we've smashed + with '\0's (indicating end of strings for various sub-fields of the + assembler instruction). */ +static char save_stack[32]; +static char *save_stack_p; /* stack pointer */ +#define END_STRING_AND_SAVE(s) *save_stack_p++ = *s; *s = '\0' +#define RESTORE_END_STRING(s) *s = *--save_stack_p + + /* The instruction we're assembling. */ + static i386_insn i; + +/* Per instruction expressionS buffers: 2 displacements & 2 immediate max. */ +static expressionS disp_expressions[2], im_expressions[2]; + +/* pointers to ebp & esp entries in reg_hash hash table */ +static reg_entry *ebp, *esp; + +static int this_operand; /* current operand we are working on */ + +/* + 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}, + +}; + +#if __STDC__ == 1 + +static char *output_invalid(int c); +static int fits_in_signed_byte(long num); +static int fits_in_signed_word(long num); +static int fits_in_unsigned_byte(long num); +static int fits_in_unsigned_word(long num); +static int i386_operand(char *operand_string); +static int smallest_imm_type(long num); +static reg_entry *parse_register(char *reg_string); +static unsigned long mode_from_disp_size(unsigned long t); +static unsigned long opcode_suffix_to_type(unsigned long s); +static void s_bss(void); + +#else /* not __STDC__ */ + +static char *output_invalid(); +static int fits_in_signed_byte(); +static int fits_in_signed_word(); +static int fits_in_unsigned_byte(); +static int fits_in_unsigned_word(); +static int i386_operand(); +static int smallest_imm_type(); +static reg_entry *parse_register(); +static unsigned long mode_from_disp_size(); +static unsigned long opcode_suffix_to_type(); +static void s_bss(); + +#endif /* not __STDC__ */ + + +/* Ignore certain directives generated by gcc. This probably should + not be here. */ +void dummy () +{ + while (*input_line_pointer && *input_line_pointer != '\n') + input_line_pointer++; +} + +const pseudo_typeS md_pseudo_table[] = { + { "bss", s_bss, 0 }, + +#ifndef OLD_GAS + { "align", s_align_bytes, 0 }, +#else /* OLD_GAS */ + { "align", s_align_ptwo, 0 }, +#endif /* OLD_GAS */ + + { "ffloat", float_cons, 'f' }, + { "dfloat", float_cons, 'd' }, + { "tfloat", float_cons, 'x' }, + { "value", cons, 2 }, + { 0, 0, 0 } +}; + +/* for interface with expression () */ +extern char * input_line_pointer; + +/* obstack for constructing various things in md_begin */ +struct obstack o; + +/* hash table for opcode lookup */ +static struct hash_control *op_hash = (struct hash_control *) 0; +/* hash table for register lookup */ +static struct hash_control *reg_hash = (struct hash_control *) 0; +/* hash table for prefix lookup */ +static struct hash_control *prefix_hash = (struct hash_control *) 0; + + +void md_begin () +{ + char * hash_err; + + obstack_begin (&o,4096); + + /* initialize op_hash hash table */ + op_hash = hash_new(); /* xmalloc handles error */ + + { + register const template *optab; + register templates *core_optab; + char *prev_name; + + optab = i386_optab; /* setup for loop */ + prev_name = optab->name; + obstack_grow (&o, optab, sizeof(template)); + core_optab = (templates *) xmalloc (sizeof (templates)); + + for (optab++; optab < i386_optab_end; optab++) { + if (! strcmp (optab->name, prev_name)) { + /* same name as before --> append to current template list */ + obstack_grow (&o, optab, sizeof(template)); + } else { + /* different name --> ship out current template list; + add to hash table; & begin anew */ + /* Note: end must be set before start! since obstack_next_free changes + upon opstack_finish */ + core_optab->end = (template *) obstack_next_free(&o); + core_optab->start = (template *) obstack_finish(&o); + hash_err = hash_insert (op_hash, prev_name, (char *) core_optab); + if (hash_err && *hash_err) { + hash_error: + as_fatal("Internal Error: Can't hash %s: %s", prev_name, hash_err); + } + prev_name = optab->name; + core_optab = (templates *) xmalloc (sizeof(templates)); + obstack_grow (&o, optab, sizeof(template)); + } + } + } + + /* initialize reg_hash hash table */ + reg_hash = hash_new(); + { + register const reg_entry *regtab; + + for (regtab = i386_regtab; regtab < i386_regtab_end; regtab++) { + hash_err = hash_insert (reg_hash, regtab->reg_name, regtab); + if (hash_err && *hash_err) goto hash_error; + } + } + + esp = (reg_entry *) hash_find (reg_hash, "esp"); + ebp = (reg_entry *) hash_find (reg_hash, "ebp"); + + /* initialize reg_hash hash table */ + prefix_hash = hash_new(); + { + register const prefix_entry *prefixtab; + + for (prefixtab = i386_prefixtab; + prefixtab < i386_prefixtab_end; prefixtab++) { + hash_err = hash_insert (prefix_hash, prefixtab->prefix_name, prefixtab); + if (hash_err && *hash_err) goto hash_error; + } + } + + /* fill in lexical tables: opcode_chars, operand_chars, space_chars */ + { + register unsigned int c; + + memset(opcode_chars, '\0', sizeof(opcode_chars)); + memset(operand_chars, '\0', sizeof(operand_chars)); + memset(space_chars, '\0', sizeof(space_chars)); + memset(identifier_chars, '\0', sizeof(identifier_chars)); + memset(digit_chars, '\0', sizeof(digit_chars)); + + for (c = 0; c < 256; c++) { + if (islower(c) || isdigit(c)) { + opcode_chars[c] = c; + register_chars[c] = c; + } else if (isupper(c)) { + opcode_chars[c] = tolower(c); + register_chars[c] = opcode_chars[c]; + } else if (c == PREFIX_SEPERATOR) { + opcode_chars[c] = c; + } else if (c == ')' || c == '(') { + register_chars[c] = c; + } + + if (isupper(c) || islower(c) || isdigit(c)) + operand_chars[c] = c; + else if (c && strchr(operand_special_chars, c)) + operand_chars[c] = c; + + if (isdigit(c) || c == '-') digit_chars[c] = c; + + if (isalpha(c) || c == '_' || c == '.' || isdigit(c)) + identifier_chars[c] = c; + + if (c == ' ' || c == '\t') space_chars[c] = c; + } + } +} + +void md_end() {} /* not much to do here. */ + + +#define DEBUG386 +#ifdef DEBUG386 + +/* debugging routines for md_assemble */ +static void pi (), pte (), pt (), pe (), ps (); + +static void pi (line, x) +char * line; +i386_insn *x; +{ + register template *p; + int i; + + fprintf (stdout, "%s: template ", line); + pte (&x->tm); + fprintf (stdout, " modrm: mode %x reg %x reg/mem %x", + x->rm.mode, x->rm.reg, x->rm.regmem); + fprintf (stdout, " base %x index %x scale %x\n", + x->bi.base, x->bi.index, x->bi.scale); + for (i = 0; i < x->operands; i++) { + fprintf (stdout, " #%d: ", i+1); + pt (x->types[i]); + fprintf (stdout, "\n"); + if (x->types[i] & Reg) fprintf (stdout, "%s\n", x->regs[i]->reg_name); + if (x->types[i] & Imm) pe (x->imms[i]); + if (x->types[i] & (Disp|Abs)) pe (x->disps[i]); + } +} + +static void pte (t) +template *t; +{ + int i; + fprintf (stdout, " %d operands ", t->operands); + fprintf (stdout, "opcode %x ", + t->base_opcode); + if (t->extension_opcode != None) + fprintf (stdout, "ext %x ", t->extension_opcode); + if (t->opcode_modifier&D) + fprintf (stdout, "D"); + if (t->opcode_modifier&W) + fprintf (stdout, "W"); + fprintf (stdout, "\n"); + for (i = 0; i < t->operands; i++) { + fprintf (stdout, " #%d type ", i+1); + pt (t->operand_types[i]); + fprintf (stdout, "\n"); + } +} + +static void pe (e) +expressionS *e; +{ + fprintf (stdout, " segment %s\n", segment_name (e->X_seg)); + fprintf (stdout, " add_number %d (%x)\n", + e->X_add_number, e->X_add_number); + if (e->X_add_symbol) { + fprintf (stdout, " add_symbol "); + ps (e->X_add_symbol); + fprintf (stdout, "\n"); + } + if (e->X_subtract_symbol) { + fprintf (stdout, " sub_symbol "); + ps (e->X_subtract_symbol); + fprintf (stdout, "\n"); + } +} + +static void ps (s) +symbolS *s; +{ + fprintf (stdout, "%s type %s%s", + S_GET_NAME(s), + S_IS_EXTERNAL(s) ? "EXTERNAL " : "", + segment_name(S_GET_SEGMENT(s))); +} + +struct type_name { + unsigned int mask; + char *tname; +} type_names[] = { + { Reg8, "r8" }, { Reg16, "r16" }, { Reg32, "r32" }, { Imm8, "i8" }, + { Imm8S, "i8s" }, + { Imm16, "i16" }, { Imm32, "i32" }, { Mem8, "Mem8"}, { Mem16, "Mem16"}, + { Mem32, "Mem32"}, { BaseIndex, "BaseIndex" }, + { Abs8, "Abs8" }, { Abs16, "Abs16" }, { Abs32, "Abs32" }, + { Disp8, "d8" }, { Disp16, "d16" }, + { Disp32, "d32" }, { SReg2, "SReg2" }, { SReg3, "SReg3" }, { Acc, "Acc" }, + { InOutPortReg, "InOutPortReg" }, { ShiftCount, "ShiftCount" }, + { Imm1, "i1" }, { Control, "control reg" }, {Test, "test reg"}, + { FloatReg, "FReg"}, {FloatAcc, "FAcc"}, + { JumpAbsolute, "Jump Absolute"}, + { 0, "" } +}; + +static void pt (t) +unsigned int t; +{ + register struct type_name *ty; + + if (t == Unknown) { + fprintf (stdout, "Unknown"); + } else { + for (ty = type_names; ty->mask; ty++) + if (t & ty->mask) fprintf (stdout, "%s, ", ty->tname); + } + fflush (stdout); +} + +#endif /* DEBUG386 */ + +/* + 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. */ + memset(&i, '\0', sizeof(i)); + memset(disp_expressions, '\0', sizeof(disp_expressions)); + memset(im_expressions, '\0', sizeof(im_expressions)); + save_stack_p = save_stack; /* reset stack pointer */ + + /* Fist parse an opcode & call i386_operand for the operands. + We assume that the scrubber has arranged it so that line[0] is the valid + start of a (possibly prefixed) opcode. */ + { + register char *l = line; /* Fast place to put LINE. */ + + /* 1 if operand is pending after ','. */ + unsigned int expecting_operand = 0; + /* 1 if we found a prefix only acceptable with string insns. */ + unsigned int expecting_string_instruction = 0; + /* Non-zero if operand parens not balenced. */ + unsigned int paren_not_balenced; + char * token_start = l; + + while (! is_space_char(*l) && *l != END_OF_INSN) { + if (! is_opcode_char(*l)) { + as_bad("invalid character %s in opcode", output_invalid(*l)); + return; + } else if (*l != PREFIX_SEPERATOR) { + *l = opcode_chars[(unsigned char) *l]; /* fold case of opcodes */ + l++; + } else { /* this opcode's got a prefix */ + register unsigned int q; + register prefix_entry * prefix; + + if (l == token_start) { + as_bad("expecting prefix; got nothing"); + return; + } + END_STRING_AND_SAVE (l); + prefix = (prefix_entry *) hash_find (prefix_hash, token_start); + if (! prefix) { + as_bad("no such opcode prefix ('%s')", token_start); + return; + } + RESTORE_END_STRING (l); + /* check for repeated prefix */ + for (q = 0; q < i.prefixes; q++) + if (i.prefix[q] == prefix->prefix_code) { + as_bad("same prefix used twice; you don't really want this!"); + return; + } + if (i.prefixes == MAX_PREFIXES) { + as_bad("too many opcode prefixes"); + return; + } + i.prefix[i.prefixes++] = prefix->prefix_code; + if (prefix->prefix_code == REPE || prefix->prefix_code == REPNE) + expecting_string_instruction = 1; + /* skip past PREFIX_SEPERATOR and reset token_start */ + token_start = ++l; + } + } + END_STRING_AND_SAVE (l); + if (token_start == l) { + as_bad("expecting opcode; got nothing"); + return; + } + + /* Lookup insn in hash; try intel & att naming conventions if appropriate; + that is: we only use the opcode suffix 'b' 'w' or 'l' if we need to. */ + current_templates = (templates *) hash_find (op_hash, token_start); + if (! current_templates) { + int last_index = strlen(token_start) - 1; + char last_char = token_start[last_index]; + switch (last_char) { + case DWORD_OPCODE_SUFFIX: + case WORD_OPCODE_SUFFIX: + case BYTE_OPCODE_SUFFIX: + token_start[last_index] = '\0'; + current_templates = (templates *) hash_find (op_hash, token_start); + token_start[last_index] = last_char; + i.suffix = last_char; + } + if (!current_templates) { + as_bad("no such 386 instruction: `%s'", token_start); return; + } + } + RESTORE_END_STRING (l); + + /* check for rep/repne without a string instruction */ + if (expecting_string_instruction && + ! IS_STRING_INSTRUCTION (current_templates-> + start->base_opcode)) { + as_bad("expecting string instruction after rep/repne"); + return; + } + + /* There may be operands to parse. */ + if (*l != END_OF_INSN && + /* For string instructions, we ignore any operands if given. This + kludges, for example, 'rep/movsb %ds:(%esi), %es:(%edi)' where + the operands are always going to be the same, and are not really + encoded in machine code. */ + ! IS_STRING_INSTRUCTION (current_templates-> + start->base_opcode)) { + /* parse operands */ + do { + /* skip optional white space before operand */ + while (! is_operand_char(*l) && *l != END_OF_INSN) { + if (! is_space_char(*l)) { + as_bad("invalid character %s before %s operand", + output_invalid(*l), + ordinal_names[i.operands]); + return; + } + l++; + } + token_start = l; /* after white space */ + paren_not_balenced = 0; + while (paren_not_balenced || *l != ',') { + if (*l == END_OF_INSN) { + if (paren_not_balenced) { + as_bad("unbalenced parenthesis in %s operand.", + ordinal_names[i.operands]); + return; + } else break; /* we are done */ + } else if (! is_operand_char(*l)) { + as_bad("invalid character %s in %s operand", + output_invalid(*l), + ordinal_names[i.operands]); + return; + } + if (*l == '(') ++paren_not_balenced; + if (*l == ')') --paren_not_balenced; + l++; + } + if (l != token_start) { /* yes, we've read in another operand */ + unsigned int operand_ok; + this_operand = i.operands++; + if (i.operands > MAX_OPERANDS) { + as_bad("spurious operands; (%d operands/instruction max)", + MAX_OPERANDS); + return; + } + /* now parse operand adding info to 'i' as we go along */ + END_STRING_AND_SAVE (l); + operand_ok = i386_operand (token_start); + RESTORE_END_STRING (l); /* restore old contents */ + if (!operand_ok) return; + } else { + if (expecting_operand) { + expecting_operand_after_comma: + as_bad("expecting operand after ','; got nothing"); + return; + } + if (*l == ',') { + as_bad("expecting operand before ','; got nothing"); + return; + } + } + + /* now *l must be either ',' or END_OF_INSN */ + if (*l == ',') { + if (*++l == END_OF_INSN) { /* just skip it, if it's \n complain */ + goto expecting_operand_after_comma; + } + expecting_operand = 1; + } + } while (*l != END_OF_INSN); /* until we get end of insn */ + } + } + + /* Now we've parsed the opcode into a set of templates, and have the + operands at hand. + Next, we find a template that matches the given insn, + making sure the overlap of the given operands types is consistent + with the template operand types. */ + +#define MATCH(overlap,given_type) \ + (overlap && \ + (overlap & (JumpAbsolute|BaseIndex|Mem8)) \ + == (given_type & (JumpAbsolute|BaseIndex|Mem8))) + + /* If m0 and m1 are register matches they must be consistent + with the expected operand types t0 and t1. + That is, if both m0 & m1 are register matches + i.e. ( ((m0 & (Reg)) && (m1 & (Reg)) ) ? + then, either 1. or 2. must be true: + 1. the expected operand type register overlap is null: + (t0 & t1 & Reg) == 0 + AND + the given register overlap is null: + (m0 & m1 & Reg) == 0 + 2. the expected operand type register overlap == the given + operand type overlap: (t0 & t1 & m0 & m1 & Reg). + */ +#define CONSISTENT_REGISTER_MATCH(m0, m1, t0, t1) \ + ( ((m0 & (Reg)) && (m1 & (Reg))) ? \ + ( ((t0 & t1 & (Reg)) == 0 && (m0 & m1 & (Reg)) == 0) || \ + ((t0 & t1) & (m0 & m1) & (Reg)) \ + ) : 1) + { + register unsigned int overlap0, overlap1; + expressionS * exp; + unsigned int overlap2; + unsigned int found_reverse_match; + + overlap0 = overlap1 = overlap2 = found_reverse_match = 0; + for (t = current_templates->start; + t < current_templates->end; + t++) { + + /* must have right number of operands */ + if (i.operands != t->operands) continue; + else if (!t->operands) break; /* 0 operands always matches */ + + overlap0 = i.types[0] & t->operand_types[0]; + switch (t->operands) { + case 1: + if (! MATCH (overlap0,i.types[0])) continue; + break; + case 2: case 3: + overlap1 = i.types[1] & t->operand_types[1]; + if (! MATCH (overlap0,i.types[0]) || + ! MATCH (overlap1,i.types[1]) || + ! CONSISTENT_REGISTER_MATCH(overlap0, overlap1, + t->operand_types[0], + t->operand_types[1])) { + + /* check if other direction is valid ... */ + if (! (t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS)) + continue; + + /* try reversing direction of operands */ + overlap0 = i.types[0] & t->operand_types[1]; + overlap1 = i.types[1] & t->operand_types[0]; + if (! MATCH (overlap0,i.types[0]) || + ! MATCH (overlap1,i.types[1]) || + ! CONSISTENT_REGISTER_MATCH (overlap0, overlap1, + t->operand_types[0], + t->operand_types[1])) { + /* does not match either direction */ + continue; + } + /* found a reverse match here -- slip through */ + /* found_reverse_match holds which of D or FloatD we've found */ + found_reverse_match = t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS; + } /* endif: not forward match */ + /* found either forward/reverse 2 operand match here */ + if (t->operands == 3) { + overlap2 = i.types[2] & t->operand_types[2]; + if (! MATCH (overlap2,i.types[2]) || + ! CONSISTENT_REGISTER_MATCH (overlap0, overlap2, + t->operand_types[0], + t->operand_types[2]) || + ! CONSISTENT_REGISTER_MATCH (overlap1, overlap2, + t->operand_types[1], + t->operand_types[2])) + continue; + } + /* found either forward/reverse 2 or 3 operand match here: + slip through to break */ + } + break; /* we've found a match; break out of loop */ + } /* for (t = ... */ + if (t == current_templates->end) { /* we found no match */ + as_bad("operands given don't match any known 386 instruction"); + return; + } + + /* Copy the template we found (we may change it!). */ + memcpy(&i.tm, t, sizeof(template)); + t = &i.tm; /* alter new copy of template */ + + /* If there's no opcode suffix we try to invent one based on register + operands. */ + if (! i.suffix && i.reg_operands) { + /* We take i.suffix from the LAST register operand specified. This + assumes that the last register operands is the destination register + operand. */ + int o; + for (o = 0; o < MAX_OPERANDS; o++) + if (i.types[o] & Reg) { + i.suffix = (i.types[o] == Reg8) ? BYTE_OPCODE_SUFFIX : + (i.types[o] == Reg16) ? WORD_OPCODE_SUFFIX : + DWORD_OPCODE_SUFFIX; + } + } + + /* Make still unresolved immediate matches conform to size of immediate + given in i.suffix. Note: overlap2 cannot be an immediate! + We assume this. */ + if ((overlap0 & (Imm8|Imm8S|Imm16|Imm32)) + && overlap0 != Imm8 && overlap0 != Imm8S + && overlap0 != Imm16 && overlap0 != Imm32) { + if (! i.suffix) { + as_bad("no opcode suffix given; can't determine immediate size"); + return; + } + overlap0 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8|Imm8S) : + (i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32)); + } + if ((overlap1 & (Imm8|Imm8S|Imm16|Imm32)) + && overlap1 != Imm8 && overlap1 != Imm8S + && overlap1 != Imm16 && overlap1 != Imm32) { + if (! i.suffix) { + as_bad("no opcode suffix given; can't determine immediate size"); + return; + } + overlap1 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8|Imm8S) : + (i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32)); + } + + i.types[0] = overlap0; + i.types[1] = overlap1; + i.types[2] = overlap2; + + if (overlap0 & ImplicitRegister) i.reg_operands--; + if (overlap1 & ImplicitRegister) i.reg_operands--; + if (overlap2 & ImplicitRegister) i.reg_operands--; + if (overlap0 & Imm1) i.imm_operands = 0; /* kludge for shift insns */ + + if (found_reverse_match) { + unsigned int save; + save = t->operand_types[0]; + t->operand_types[0] = t->operand_types[1]; + t->operand_types[1] = save; + } + + /* Finalize opcode. First, we change the opcode based on the operand + size given by i.suffix: we never have to change things for byte insns, + or when no opcode suffix is need to size the operands. */ + + if (! i.suffix && (t->opcode_modifier & W)) { + as_bad("no opcode suffix given and no register operands; can't size instruction"); + return; + } + + if (i.suffix && i.suffix != BYTE_OPCODE_SUFFIX) { + /* Select between byte and word/dword operations. */ + if (t->opcode_modifier & W) + t->base_opcode |= W; + /* Now select between word & dword operations via the + operand size prefix. */ + if (i.suffix == WORD_OPCODE_SUFFIX) { + if (i.prefixes == MAX_PREFIXES) { + as_bad("%d prefixes given and 'w' opcode suffix gives too many prefixes", + MAX_PREFIXES); + return; + } + i.prefix[i.prefixes++] = WORD_PREFIX_OPCODE; + } + } + + /* For insns with operands there are more diddles to do to the opcode. */ + if (i.operands) { + /* If we found a reverse match we must alter the opcode direction bit + found_reverse_match holds bit to set (different for int & + float insns). */ + + if (found_reverse_match) { + t->base_opcode |= found_reverse_match; + } + + /* + The imul $imm, %reg instruction is converted into + imul $imm, %reg, %reg. */ + if (t->opcode_modifier & imulKludge) { + i.regs[2] = i.regs[1]; /* Pretend we saw the 3 operand case. */ + i.reg_operands = 2; + } + + /* Certain instructions expect the destination to be in the i.rm.reg + field. This is by far the exceptional case. For these instructions, + if the source operand is a register, we must reverse the i.rm.reg + and i.rm.regmem fields. We accomplish this by faking that the + two register operands were given in the reverse order. */ + if ((t->opcode_modifier & ReverseRegRegmem) && i.reg_operands == 2) { + unsigned int first_reg_operand = (i.types[0] & Reg) ? 0 : 1; + unsigned int second_reg_operand = first_reg_operand + 1; + reg_entry *tmp = i.regs[first_reg_operand]; + i.regs[first_reg_operand] = i.regs[second_reg_operand]; + i.regs[second_reg_operand] = tmp; + } + + if (t->opcode_modifier & ShortForm) { + /* The register or float register operand is in operand 0 or 1. */ + unsigned int o = (i.types[0] & (Reg|FloatReg)) ? 0 : 1; + /* Register goes in low 3 bits of opcode. */ + t->base_opcode |= i.regs[o]->reg_num; + } else if (t->opcode_modifier & ShortFormW) { + /* Short form with 0x8 width bit. Register is always dest. operand */ + t->base_opcode |= i.regs[1]->reg_num; + if (i.suffix == WORD_OPCODE_SUFFIX || + i.suffix == DWORD_OPCODE_SUFFIX) + t->base_opcode |= 0x8; + } else if (t->opcode_modifier & Seg2ShortForm) { + if (t->base_opcode == POP_SEG_SHORT && i.regs[0]->reg_num == 1) { + as_bad("you can't 'pop cs' on the 386."); + return; + } + t->base_opcode |= (i.regs[0]->reg_num << 3); + } else if (t->opcode_modifier & Seg3ShortForm) { + /* 'push %fs' is 0x0fa0; 'pop %fs' is 0x0fa1. + 'push %gs' is 0x0fa8; 'pop %fs' is 0x0fa9. + So, only if i.regs[0]->reg_num == 5 (%gs) do we need + to change the opcode. */ + if (i.regs[0]->reg_num == 5) + t->base_opcode |= 0x08; + } else if (t->opcode_modifier & Modrm) { + /* The opcode is completed (modulo t->extension_opcode which must + be put into the modrm byte. + Now, we make the modrm & index base bytes based on all the info + we've collected. */ + + /* i.reg_operands MUST be the number of real register operands; + implicit registers do not count. */ + if (i.reg_operands == 2) { + unsigned int source, dest; + source = (i.types[0] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 0 : 1; + dest = source + 1; + i.rm.mode = 3; + /* We must be careful to make sure that all segment/control/test/ + debug registers go into the i.rm.reg field (despite the whether + they are source or destination operands). */ + if (i.regs[dest]->reg_type & (SReg2|SReg3|Control|Debug|Test)) { + i.rm.reg = i.regs[dest]->reg_num; + i.rm.regmem = i.regs[source]->reg_num; + } else { + i.rm.reg = i.regs[source]->reg_num; + i.rm.regmem = i.regs[dest]->reg_num; + } + } else { /* if it's not 2 reg operands... */ + if (i.mem_operands) { + unsigned int fake_zero_displacement = 0; + unsigned int o = (i.types[0] & Mem) ? 0 : ((i.types[1] & Mem) ? 1 : 2); + + /* Encode memory operand into modrm byte and base index byte. */ + + if (i.base_reg == esp && ! i.index_reg) { + /* <disp>(%esp) becomes two byte modrm with no index register. */ + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + i.rm.mode = mode_from_disp_size(i.types[o]); + i.bi.base = ESP_REG_NUM; + i.bi.index = NO_INDEX_REGISTER; + i.bi.scale = 0; /* Must be zero! */ + } else if (i.base_reg == ebp && !i.index_reg) { + if (! (i.types[o] & Disp)) { + /* Must fake a zero byte displacement. + There is no direct way to code '(%ebp)' directly. */ + fake_zero_displacement = 1; + /* fake_zero_displacement code does not set this. */ + i.types[o] |= Disp8; + } + i.rm.mode = mode_from_disp_size(i.types[o]); + i.rm.regmem = EBP_REG_NUM; + } else if (! i.base_reg && (i.types[o] & BaseIndex)) { + /* There are three cases here. + Case 1: '<32bit disp>(,1)' -- indirect absolute. + (Same as cases 2 & 3 with NO index register) + Case 2: <32bit disp> (,<index>) -- no base register with disp + Case 3: (, <index>) --- no base register; + no disp (must add 32bit 0 disp). */ + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + i.rm.mode = 0; /* 32bit mode */ + i.bi.base = NO_BASE_REGISTER; + i.types[o] &= ~Disp; + i.types[o] |= Disp32; /* Must be 32bit! */ + if (i.index_reg) { /* case 2 or case 3 */ + i.bi.index = i.index_reg->reg_num; + i.bi.scale = i.log2_scale_factor; + if (i.disp_operands == 0) + fake_zero_displacement = 1; /* case 3 */ + } else { + i.bi.index = NO_INDEX_REGISTER; + i.bi.scale = 0; + } + } else if (i.disp_operands && !i.base_reg && !i.index_reg) { + /* Operand is just <32bit disp> */ + i.rm.regmem = EBP_REG_NUM; + i.rm.mode = 0; + i.types[o] &= ~Disp; + i.types[o] |= Disp32; + } else { + /* It's not a special case; rev'em up. */ + i.rm.regmem = i.base_reg->reg_num; + i.rm.mode = mode_from_disp_size(i.types[o]); + if (i.index_reg) { + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + i.bi.base = i.base_reg->reg_num; + i.bi.index = i.index_reg->reg_num; + i.bi.scale = i.log2_scale_factor; + if (i.base_reg == ebp && i.disp_operands == 0) { /* pace */ + fake_zero_displacement = 1; + i.types[o] |= Disp8; + i.rm.mode = mode_from_disp_size(i.types[o]); + } + } + } + if (fake_zero_displacement) { + /* Fakes a zero displacement assuming that i.types[o] holds + the correct displacement size. */ + exp = &disp_expressions[i.disp_operands++]; + i.disps[o] = exp; + exp->X_seg = SEG_ABSOLUTE; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_subtract_symbol = (symbolS *) 0; + } + + /* Select the correct segment for the memory operand. */ + if (i.seg) { + unsigned int seg_index; + const seg_entry *default_seg; + + if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING) { + seg_index = (i.rm.mode<<3) | i.bi.base; + default_seg = two_byte_segment_defaults[seg_index]; + } else { + seg_index = (i.rm.mode<<3) | i.rm.regmem; + default_seg = one_byte_segment_defaults[seg_index]; + } + /* If the specified segment is not the default, use an + opcode prefix to select it */ + if (i.seg != default_seg) { + if (i.prefixes == MAX_PREFIXES) { + as_bad("%d prefixes given and %s segment override gives too many prefixes", + MAX_PREFIXES, i.seg->seg_name); + return; + } + i.prefix[i.prefixes++] = i.seg->seg_prefix; + } + } + } + + /* Fill in i.rm.reg or i.rm.regmem field with register operand + (if any) based on t->extension_opcode. Again, we must be careful + to make sure that segment/control/debug/test registers are coded + into the i.rm.reg field. */ + if (i.reg_operands) { + unsigned int o = + (i.types[0] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 0 : + (i.types[1] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 1 : 2; + /* If there is an extension opcode to put here, the register number + must be put into the regmem field. */ + if (t->extension_opcode != None) + i.rm.regmem = i.regs[o]->reg_num; + else i.rm.reg = i.regs[o]->reg_num; + + /* Now, if no memory operand has set i.rm.mode = 0, 1, 2 + we must set it to 3 to indicate this is a register operand + int the regmem field */ + if (! i.mem_operands) i.rm.mode = 3; + } + + /* Fill in i.rm.reg field with extension opcode (if any). */ + if (t->extension_opcode != None) + i.rm.reg = t->extension_opcode; + } + } + } + } + + /* Handle conversion of 'int $3' --> special int3 insn. */ + if (t->base_opcode == INT_OPCODE && i.imms[0]->X_add_number == 3) { + t->base_opcode = INT3_OPCODE; + i.imm_operands = 0; + } + + /* We are ready to output the insn. */ + { + register char * p; + + /* Output jumps. */ + if (t->opcode_modifier & Jump) { + int n = i.disps[0]->X_add_number; + + switch (i.disps[0]->X_seg) { + case SEG_ABSOLUTE: + if (fits_in_signed_byte(n)) { + p = frag_more (2); + p[0] = t->base_opcode; + p[1] = n; +#if 0 /* leave out 16 bit jumps - pace */ + } else if (fits_in_signed_word(n)) { + p = frag_more (4); + p[0] = WORD_PREFIX_OPCODE; + p[1] = t->base_opcode; + md_number_to_chars (&p[2], n, 2); +#endif + } else { /* It's an absolute dword displacement. */ + if (t->base_opcode == JUMP_PC_RELATIVE) { /* pace */ + /* unconditional jump */ + p = frag_more (5); + p[0] = 0xe9; + md_number_to_chars (&p[1], n, 4); + } else { + /* conditional jump */ + p = frag_more (6); + p[0] = TWO_BYTE_OPCODE_ESCAPE; + p[1] = t->base_opcode + 0x10; + md_number_to_chars (&p[2], n, 4); + } + } + break; + default: + /* It's a symbol; end frag & setup for relax. + Make sure there are 6 chars left in the current frag; if not + we'll have to start a new one. */ + /* I caught it failing with obstack_room == 6, + so I changed to <= pace */ + if (obstack_room (&frags) <= 6) { + frag_wane(frag_now); + frag_new (0); + } + p = frag_more (1); + p[0] = t->base_opcode; + frag_var (rs_machine_dependent, + 6, /* 2 opcode/prefix + 4 displacement */ + 1, + ((unsigned char) *p == JUMP_PC_RELATIVE + ? ENCODE_RELAX_STATE (UNCOND_JUMP, BYTE) + : ENCODE_RELAX_STATE (COND_JUMP, BYTE)), + i.disps[0]->X_add_symbol, + n, p); +/* + * XXX - what do we do about jmp x@PLT ?? + * kludged in md_estimate_size_before_relax() below + */ + 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, i.disp_reloc[0], i.disps[0]->X_got_symbol); + break; + } + } else if (t->opcode_modifier & JumpInterSegment) { + p = frag_more (1 + 2 + 4); /* 1 opcode; 2 segment; 4 offset */ + p[0] = t->base_opcode; + if (i.imms[1]->X_seg == SEG_ABSOLUTE) + md_number_to_chars (p + 1, i.imms[1]->X_add_number, 4); + else + fix_new (frag_now, p + 1 - frag_now->fr_literal, 4, + i.imms[1]->X_add_symbol, + i.imms[1]->X_subtract_symbol, + i.imms[1]->X_add_number, 0, NO_RELOC, i.imms[1]->X_got_symbol); + 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. */ + unsigned char *q; +#ifdef PIC + /* + * Remember # of opcode bytes to put in pcrel_adjust + * for use in _GLOBAL_OFFSET_TABLE_ expressions. + */ + int nopbytes = 0; +#endif + + /* First the prefix bytes. */ + for (q = i.prefix; q < i.prefix + i.prefixes; q++) { + p = frag_more (1); + nopbytes += 1; + md_number_to_chars (p, (unsigned int) *q, 1); + } + + /* Now the opcode; be careful about word order here! */ + if (fits_in_unsigned_byte(t->base_opcode)) { + nopbytes += 1; + FRAG_APPEND_1_CHAR (t->base_opcode); + } else if (fits_in_unsigned_word(t->base_opcode)) { + p = frag_more (2); + nopbytes += 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); + nopbytes += 4; + *p++ = (t->base_opcode >> 24) & 0xff; + } else { + p = frag_more (3); + nopbytes += 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); + nopbytes += 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); + nopbytes += 1; + /* md_number_to_chars (p, i.bi, 1); */ + md_number_to_chars (p,(i.bi.base<<0 | i.bi.index<<3 | i.bi.scale<<6), 1); + } + } + + if (i.disp_operands) { + register unsigned int n; + + for (n = 0; n < i.operands; n++) { + if (i.disps[n]) { + if (i.disps[n]->X_seg == SEG_ABSOLUTE) { + if (i.types[n] & (Disp8|Abs8)) { + p = frag_more (1); + md_number_to_chars (p, i.disps[n]->X_add_number, 1); + } else if (i.types[n] & (Disp16|Abs16)) { + p = frag_more (2); + md_number_to_chars (p, i.disps[n]->X_add_number, 2); + } else { /* Disp32|Abs32 */ + p = frag_more (4); + md_number_to_chars (p, i.disps[n]->X_add_number, 4); + } + } else { /* not SEG_ABSOLUTE */ + /* need a 32-bit fixup (don't support 8bit non-absolute disps) */ + + fixS *fixP; + p = frag_more (4); + fixP = 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, i.disp_reloc[n], i.disps[n]->X_got_symbol); +#ifdef PIC + if (i.disps[n]->X_got_symbol) { + fixP->fx_pcrel_adjust = nopbytes; + } +#endif + } + } + } + } /* end displacement output */ + + /* output immediate */ + if (i.imm_operands) { + register unsigned int n; + + for (n = 0; n < i.operands; n++) { + if (i.imms[n]) { + if (i.imms[n]->X_seg == SEG_ABSOLUTE) { + if (i.types[n] & (Imm8|Imm8S)) { + p = frag_more (1); + md_number_to_chars (p, i.imms[n]->X_add_number, 1); + } else if (i.types[n] & Imm16) { + p = frag_more (2); + md_number_to_chars (p, i.imms[n]->X_add_number, 2); + } else { + p = frag_more (4); + md_number_to_chars (p, i.imms[n]->X_add_number, 4); + } + } else { /* not SEG_ABSOLUTE */ + /* need a 32-bit fixup (don't support 8bit non-absolute ims) */ + /* try to support other sizes ... */ + fixS *fixP; + 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); + fixP = fix_new (frag_now, p - frag_now->fr_literal, size, + i.imms[n]->X_add_symbol, i.imms[n]->X_subtract_symbol, + i.imms[n]->X_add_number, 0, NO_RELOC, i.imms[n]->X_got_symbol); +#ifdef PIC + if (i.imms[n]->X_got_symbol) { + fixP->fx_pcrel_adjust = nopbytes; + } +#endif + } + } + } + } /* 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. */ + +static int i386_operand (operand_string) +char *operand_string; +{ + register char *op_string = operand_string; + + /* Address of '\0' at end of operand_string. */ + char * end_of_operand_string = operand_string + strlen(operand_string); + + /* Start and end of displacement string expression (if found). */ + char *displacement_string_start = NULL; + char *displacement_string_end = NULL; + + /* We check for an absolute prefix (differentiating, + for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */ + if (*op_string == ABSOLUTE_PREFIX) { + op_string++; + i.types[this_operand] |= JumpAbsolute; + } + + /* Check if operand is a register. */ + if (*op_string == REGISTER_PREFIX) { + register reg_entry *r; + if (!(r = parse_register (op_string))) { + as_bad("bad register name ('%s')", op_string); + return 0; + } + /* Check for segment override, rather than segment register by + searching for ':' after %<x>s where <x> = s, c, d, e, f, g. */ + if ((r->reg_type & (SReg2|SReg3)) && op_string[3] == ':') { + switch (r->reg_num) { + case 0: + i.seg = (seg_entry *) &es; break; + case 1: + i.seg = (seg_entry *) &cs; break; + case 2: + i.seg = (seg_entry *) &ss; break; + case 3: + i.seg = (seg_entry *) &ds; break; + case 4: + i.seg = (seg_entry *) &fs; break; + case 5: + i.seg = (seg_entry *) &gs; break; + } + op_string += 4; /* skip % <x> s : */ + operand_string = op_string; /* Pretend given string starts here. */ + if (!is_digit_char(*op_string) && !is_identifier_char(*op_string) + && *op_string != '(' && *op_string != ABSOLUTE_PREFIX) { + as_bad("bad memory operand after segment override"); + return 0; + } + /* Handle case of %es:*foo. */ + if (*op_string == ABSOLUTE_PREFIX) { + op_string++; + i.types[this_operand] |= JumpAbsolute; + } + goto do_memory_reference; + } + i.types[this_operand] |= r->reg_type; + i.regs[this_operand] = r; + i.reg_operands++; + } else if (*op_string == IMMEDIATE_PREFIX) { /* ... or an immediate */ + char *save_input_line_pointer; + segT exp_seg = SEG_GOOF; + expressionS *exp; + + if (i.imm_operands == MAX_IMMEDIATE_OPERANDS) { + as_bad("only 1 or 2 immediate operands are allowed"); + return 0; + } + + exp = &im_expressions[i.imm_operands++]; + i.imms[this_operand] = exp; + save_input_line_pointer = input_line_pointer; + /* must advance op_string! */ + input_line_pointer = ++op_string; + + exp_seg = expression(exp); + input_line_pointer = save_input_line_pointer; + + switch (exp_seg) { + case SEG_ABSENT: /* missing or bad expr becomes absolute 0 */ + as_bad("missing or invalid immediate expression '%s' taken as 0", + operand_string); + exp->X_seg = SEG_ABSOLUTE; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_subtract_symbol = (symbolS *) 0; + i.types[this_operand] |= Imm; + break; + case SEG_ABSOLUTE: + i.types[this_operand] |= smallest_imm_type(exp->X_add_number); + break; + case SEG_TEXT: case SEG_DATA: case SEG_BSS: case SEG_UNKNOWN: + case SEG_DIFFERENCE: + i.types[this_operand] |= Imm32; /* this is an address ==> 32bit */ + break; + default: + seg_unimplemented: + as_bad("Unimplemented segment type %d in parse_operand", exp_seg); + return 0; + } + /* shorten this type of this operand if the instruction wants + * fewer bits than are present in the immediate. The bit field + * code can put out 'andb $0xffffff, %al', for example. pace + * also 'movw $foo,(%eax)' + */ + switch (i.suffix) { + case WORD_OPCODE_SUFFIX: + i.types[this_operand] |= Imm16; + break; + case BYTE_OPCODE_SUFFIX: + i.types[this_operand] |= Imm16 | Imm8 | Imm8S; + break; + } + } else if (is_digit_char(*op_string) || is_identifier_char(*op_string) + || *op_string == '(') { + /* This is a memory reference of some sort. */ + register char * base_string; + unsigned int found_base_index_form; + + do_memory_reference: + if (i.mem_operands == MAX_MEMORY_OPERANDS) { + as_bad("more than 1 memory reference in instruction"); + return 0; + } + i.mem_operands++; + + /* Determine type of memory operand from opcode_suffix; + no opcode suffix implies general memory references. */ + switch (i.suffix) { + case BYTE_OPCODE_SUFFIX: + i.types[this_operand] |= Mem8; + break; + case WORD_OPCODE_SUFFIX: + i.types[this_operand] |= Mem16; + break; + case DWORD_OPCODE_SUFFIX: + default: + i.types[this_operand] |= Mem32; + } + + /* Check for base index form. We detect the base index form by + looking for an ')' at the end of the operand, searching + for the '(' matching it, and finding a REGISTER_PREFIX or ',' + after it. */ + base_string = end_of_operand_string - 1; + found_base_index_form = 0; + if (*base_string == ')') { + unsigned int parens_balenced = 1; + /* We've already checked that the number of left & right ()'s are equal, + so this loop will not be infinite. */ + do { + base_string--; + if (*base_string == ')') parens_balenced++; + if (*base_string == '(') parens_balenced--; + } while (parens_balenced); + base_string++; /* Skip past '('. */ + if (*base_string == REGISTER_PREFIX || *base_string == ',') + found_base_index_form = 1; + } + + /* If we can't parse a base index register expression, we've found + a pure displacement expression. We set up displacement_string_start + and displacement_string_end for the code below. */ + if (! found_base_index_form) { + displacement_string_start = op_string; + displacement_string_end = end_of_operand_string; + } else { + char *base_reg_name, *index_reg_name, *num_string; + int num; + + i.types[this_operand] |= BaseIndex; + + /* If there is a displacement set-up for it to be parsed later. */ + if (base_string != op_string + 1) { + displacement_string_start = op_string; + displacement_string_end = base_string - 1; + } + + /* Find base register (if any). */ + if (*base_string != ',') { + base_reg_name = base_string++; + /* skip past register name & parse it */ + while (isalpha(*base_string)) base_string++; + if (base_string == base_reg_name+1) { + as_bad("can't find base register name after '(%c'", + REGISTER_PREFIX); + return 0; + } + END_STRING_AND_SAVE (base_string); + if (! (i.base_reg = parse_register (base_reg_name))) { + as_bad("bad base register name ('%s')", base_reg_name); + return 0; + } + RESTORE_END_STRING (base_string); + } + + /* Now check seperator; must be ',' ==> index reg + OR num ==> no index reg. just scale factor + OR ')' ==> end. (scale factor = 1) */ + if (*base_string != ',' && *base_string != ')') { + as_bad("expecting ',' or ')' after base register in `%s'", + operand_string); + return 0; + } + + /* There may index reg here; and there may be a scale factor. */ + if (*base_string == ',' && *(base_string+1) == REGISTER_PREFIX) { + index_reg_name = ++base_string; + while (isalpha(*++base_string)); + END_STRING_AND_SAVE (base_string); + if (! (i.index_reg = parse_register(index_reg_name))) { + as_bad("bad index register name ('%s')", index_reg_name); + return 0; + } + RESTORE_END_STRING (base_string); + } + + /* Check for scale factor. */ + if (*base_string == ',' && isdigit(*(base_string+1))) { + num_string = ++base_string; + while (is_digit_char(*base_string)) base_string++; + if (base_string == num_string) { + as_bad("can't find a scale factor after ','"); + return 0; + } + END_STRING_AND_SAVE (base_string); + /* We've got a scale factor. */ + if (! sscanf (num_string, "%d", &num)) { + as_bad("can't parse scale factor from '%s'", num_string); + return 0; + } + RESTORE_END_STRING (base_string); + switch (num) { /* must be 1 digit scale */ + case 1: i.log2_scale_factor = 0; break; + case 2: i.log2_scale_factor = 1; break; + case 4: i.log2_scale_factor = 2; break; + case 8: i.log2_scale_factor = 3; break; + default: + as_bad("expecting scale factor of 1, 2, 4, 8; got %d", num); + return 0; + } + } else { + if (! i.index_reg && *base_string == ',') { + as_bad("expecting index register or scale factor after ','; got '%c'", + *(base_string+1)); + return 0; + } + } + } + + /* If there's an expression begining the operand, parse it, + assuming displacement_string_start and displacement_string_end + are meaningful. */ + if (displacement_string_start) { + register expressionS *exp; + segT exp_seg = SEG_GOOF; + char *save_input_line_pointer; + exp = &disp_expressions[i.disp_operands]; + i.disps[this_operand] = exp; + i.disp_reloc[this_operand] = NO_RELOC; + i.disp_operands++; + save_input_line_pointer = input_line_pointer; + input_line_pointer = displacement_string_start; + END_STRING_AND_SAVE (displacement_string_end); +#ifdef PIC + { + /* + * We can have operands of the form + * <symbol>@GOTOFF+<nnn> + * Take the easy way out here and copy everything + * into a temporary buffer... + */ + register char *cp; + if (flagseen['k'] && + (cp = strchr(input_line_pointer,'@'))) { + char tmpbuf[BUFSIZ]; + + if (strncmp(cp+1, "PLT", 3) == 0) { + i.disp_reloc[this_operand] = RELOC_JMP_TBL; + *cp = '\0'; + strcpy(tmpbuf, input_line_pointer); + strcat(tmpbuf, cp+1+3); + *cp = '@'; + } else if (strncmp(cp+1, "GOTOFF", 6) == 0) { + i.disp_reloc[this_operand] = RELOC_GOTOFF; + *cp = '\0'; + strcpy(tmpbuf, input_line_pointer); + strcat(tmpbuf, cp+1+6); + *cp = '@'; + } else if (strncmp(cp+1, "GOT", 3) == 0) { + i.disp_reloc[this_operand] = RELOC_GOT; + *cp = '\0'; + strcpy(tmpbuf, input_line_pointer); + strcat(tmpbuf, cp+1+3); + *cp = '@'; + } else + as_bad("Bad reloc specifier '%s' in expression", cp+1); + input_line_pointer = tmpbuf; + } + } +#endif + exp_seg = expression(exp); +#ifdef PIC + if (i.disp_reloc[this_operand] == RELOC_GOTOFF) + exp->X_add_symbol->sy_forceout = 1; +#endif + if (*input_line_pointer) + as_bad("Ignoring junk '%s' after expression",input_line_pointer); + RESTORE_END_STRING (displacement_string_end); + input_line_pointer = save_input_line_pointer; + switch (exp_seg) { + case SEG_ABSENT: + /* missing expr becomes absolute 0 */ + as_bad("missing or invalid displacement '%s' taken as 0", + operand_string); + i.types[this_operand] |= (Disp|Abs); + exp->X_seg = SEG_ABSOLUTE; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_subtract_symbol = (symbolS *) 0; + break; + case SEG_ABSOLUTE: + i.types[this_operand] |= SMALLEST_DISP_TYPE (exp->X_add_number); + break; + case SEG_TEXT: case SEG_DATA: case SEG_BSS: + case SEG_UNKNOWN: /* must be 32 bit displacement (i.e. address) */ + i.types[this_operand] |= Disp32; + break; + default: + goto seg_unimplemented; + } + } + + /* Make sure the memory operand we've been dealt is valid. */ + if (i.base_reg && i.index_reg && + ! (i.base_reg->reg_type & i.index_reg->reg_type & Reg)) { + as_bad("register size mismatch in (base,index,scale) expression"); + return 0; + } + /* + * special case for (%dx) while doing input/output op + */ + if ((i.base_reg && + (i.base_reg->reg_type == (Reg16|InOutPortReg)) && + (i.index_reg == 0))) + return 1; + if ((i.base_reg && (i.base_reg->reg_type & Reg32) == 0) || + (i.index_reg && (i.index_reg->reg_type & Reg32) == 0)) { + as_bad("base/index register must be 32 bit register"); + return 0; + } + if (i.index_reg && i.index_reg == esp) { + as_bad("%s may not be used as an index register", esp->reg_name); + return 0; + } + } else { /* it's not a memory operand; argh! */ + as_bad("invalid char %s begining %s operand '%s'", + output_invalid(*op_string), ordinal_names[this_operand], + op_string); + return 0; + } + return 1; /* normal return */ +} + +/* + * md_estimate_size_before_relax() + * + * Called just before relax(). + * Any symbol that is now undefined will not become defined. + * Return the correct fr_subtype in the frag. + * Return the initial "guess for fr_var" to caller. + * The guess for fr_var is ACTUALLY the growth beyond fr_fix. + * Whatever we do to grow fr_fix or fr_var contributes to our returned value. + * Although it may not be explicit in the frag, pretend fr_var starts with a + * 0 value. + */ +int + md_estimate_size_before_relax (fragP, segment) +register fragS * fragP; +register segT segment; +{ + register unsigned char * opcode; + register int old_fr_fix; + + old_fr_fix = fragP->fr_fix; + opcode = (unsigned char *) fragP->fr_opcode; + /* We've already got fragP->fr_subtype right; all we have to do is check + for un-relaxable symbols. */ + if (S_GET_SEGMENT(fragP->fr_symbol) != segment) { + /* symbol is undefined in this segment */ + switch (opcode[0]) { + case JUMP_PC_RELATIVE: /* make jmp (0xeb) a dword displacement jump */ + opcode[0] = 0xe9; /* dword disp jmp */ + fragP->fr_fix += 4; + fix_new (fragP, old_fr_fix, 4, + fragP->fr_symbol, + (symbolS *) 0, + fragP->fr_offset, 1, +#ifdef PIC +/* XXX - oops, the JMP_TBL relocation info should have percolated through + * here, define a field in frag to this? + */ + (flagseen['k'] && S_GET_SEGMENT(fragP->fr_symbol) == SEG_UNKNOWN)? + RELOC_JMP_TBL : +#endif + NO_RELOC, (symbolS *)0); + 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, +#ifdef PIC +/*XXX*/ (flagseen['k'] && S_GET_SEGMENT(fragP->fr_symbol) == SEG_UNKNOWN)? + RELOC_JMP_TBL : +#endif + NO_RELOC, (symbolS *)0); + 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 (headers, fragP) +object_headers *headers; +register fragS * fragP; +{ + register unsigned char *opcode; + unsigned char *where_to_put_displacement = NULL; + unsigned int target_address; + unsigned int opcode_address; + unsigned int extension = 0; + int displacement_from_opcode_start; + + opcode = (unsigned char *) fragP->fr_opcode; + + /* Address we want to reach in file space. */ + target_address = S_GET_VALUE(fragP->fr_symbol) + fragP->fr_offset; + + /* Address opcode resides at in file space. */ + opcode_address = fragP->fr_address + fragP->fr_fix; + + /* Displacement from opcode start to fill into instruction. */ + displacement_from_opcode_start = target_address - opcode_address; + + switch (fragP->fr_subtype) { + case ENCODE_RELAX_STATE (COND_JUMP, BYTE): + case ENCODE_RELAX_STATE (UNCOND_JUMP, BYTE): + /* don't have to change opcode */ + extension = 1; /* 1 opcode + 1 displacement */ + where_to_put_displacement = &opcode[1]; + break; + + case ENCODE_RELAX_STATE (COND_JUMP, WORD): + opcode[1] = TWO_BYTE_OPCODE_ESCAPE; + opcode[2] = opcode[0] + 0x10; + opcode[0] = WORD_PREFIX_OPCODE; + extension = 4; /* 3 opcode + 2 displacement */ + where_to_put_displacement = &opcode[3]; + break; + + case ENCODE_RELAX_STATE (UNCOND_JUMP, WORD): + opcode[1] = 0xe9; + opcode[0] = WORD_PREFIX_OPCODE; + extension = 3; /* 2 opcode + 2 displacement */ + where_to_put_displacement = &opcode[2]; + break; + + case ENCODE_RELAX_STATE (COND_JUMP, DWORD): + opcode[1] = opcode[0] + 0x10; + opcode[0] = TWO_BYTE_OPCODE_ESCAPE; + extension = 5; /* 2 opcode + 4 displacement */ + where_to_put_displacement = &opcode[2]; + break; + + case ENCODE_RELAX_STATE (UNCOND_JUMP, DWORD): + opcode[0] = 0xe9; + extension = 4; /* 1 opcode + 4 displacement */ + where_to_put_displacement = &opcode[1]; + break; + + default: + BAD_CASE(fragP->fr_subtype); + break; +} + /* now put displacement after opcode */ + md_number_to_chars ((char *) where_to_put_displacement, + 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 */ +int md_reloc_size = 8; /* Size of relocation record */ + +void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol) +char *ptr; +long from_addr, to_addr; +fragS *frag; +symbolS *to_symbol; +{ + long offset; + + offset = to_addr - (from_addr + 2); + md_number_to_chars (ptr, (long) 0xeb, 1); /* opcode for byte-disp jump */ + md_number_to_chars (ptr + 1, offset, 1); +} + +void md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) +char *ptr; +long from_addr, to_addr; +fragS *frag; +symbolS *to_symbol; +{ + long offset; + + if (flagseen['m']) { + offset = to_addr - S_GET_VALUE(to_symbol); + md_number_to_chars (ptr, 0xe9, 1); /* opcode for long jmp */ + md_number_to_chars (ptr + 1, offset, 4); + fix_new (frag, (ptr+1) - frag->fr_literal, 4, + to_symbol, (symbolS *) 0, (long) 0, 0, NO_RELOC, (symbolS *)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; +{ +#ifdef PIC + if (argP && *argP && **argP == 'k') { +#if 00 + char *tmp = xmalloc(3+1+strlen(operand_special_chars)); + strcpy(tmp, operand_special_chars); + strcat(tmp, "@[]"); + operand_special_chars = tmp; +#endif + /* Allow `[', `]' in expressions and `@' in operands */ + operand_chars['@'] = '@'; + operand_chars['['] = '['; + operand_chars[']'] = ']'; + + /* Disallow `[' as a name beginner */ + lex_type['['] = 0; + + /* Predefine GOT symbol */ + GOT_symbol = symbol_find_or_make("__GLOBAL_OFFSET_TABLE_"); + } +#endif + return 1; +} + + /* write out in little endian. */ +void /* Knows about order of bytes in address. */ + md_number_to_chars(con, value, nbytes) +char con[]; /* Return 'nbytes' of chars here. */ +long value; /* The value of the bits. */ +int nbytes; /* Number of bytes in the output. */ +{ + register char * p = con; + + switch (nbytes) { + case 1: + p[0] = value & 0xff; + break; + case 2: + p[0] = value & 0xff; + p[1] = (value >> 8) & 0xff; + break; + case 4: + p[0] = value & 0xff; + p[1] = (value>>8) & 0xff; + p[2] = (value>>16) & 0xff; + p[3] = (value>>24) & 0xff; + break; + default: + BAD_CASE (nbytes); + } +} + + +/* Apply a fixup (fixS) to segment data, once it has been determined + by our caller that we have all the info we need to fix it up. + + On the 386, immediates, displacements, and data pointers are all in + the same (little-endian) format, so we don't need to care about which + we are handling. */ + +void + md_apply_fix (fixP, value) +fixS * fixP; /* The fix we're to put in */ +long value; /* The value of the bits. */ +{ + register char * p = fixP->fx_where + fixP->fx_frag->fr_literal; + + switch (fixP->fx_size) { + case 1: + *p = value; + break; + case 2: + *p++ = value; + *p = (value>>8); + break; + case 4: + *p++ = value; + *p++ = (value>>8); + *p++ = (value>>16); + *p = (value>>24); + break; + default: + BAD_CASE (fixP->fx_size); + } +} + +long /* Knows about the byte order in a word. */ + md_chars_to_number (con, nbytes) +unsigned char con[]; /* Low order byte 1st. */ +int nbytes; /* Number of bytes in the input. */ +{ + long retval; + for (retval=0, con+=nbytes-1; nbytes--; con--) + { + retval <<= BITS_PER_CHAR; + retval |= *con; + } + return retval; +} + +/* Not needed for coff since relocation structure does not + contain bitfields. */ +#if defined(OBJ_AOUT) | defined(OBJ_BOUT) +#ifdef comment +/* Output relocation information in the target's format. */ +void + md_ri_to_chars(the_bytes, ri) +char *the_bytes; +struct reloc_info_generic *ri; +{ + /* this is easy */ + md_number_to_chars(the_bytes, ri->r_address, 4); + /* now the fun stuff */ + the_bytes[6] = (ri->r_symbolnum >> 16) & 0x0ff; + the_bytes[5] = (ri->r_symbolnum >> 8) & 0x0ff; + the_bytes[4] = ri->r_symbolnum & 0x0ff; + the_bytes[7] = (((ri->r_extern << 3) & 0x08) | ((ri->r_length << 1) & 0x06) | + ((ri->r_pcrel << 0) & 0x01)) & 0x0F; +} +#endif /* comment */ + +void tc_aout_fix_to_chars(where, fixP, segment_address_in_file) +char *where; +fixS *fixP; +relax_addressT segment_address_in_file; +{ + /* + * In: length of relocation (or of address) in chars: 1, 2 or 4. + * Out: GNU LD relocation length code: 0, 1, or 2. + */ + + static unsigned char nbytes_r_length[] = { 42, 0, 1, 42, 2 }; + long r_symbolnum; + + know(fixP->fx_addsy != NULL); + + md_number_to_chars(where, + fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, + 4); + + r_symbolnum = (S_IS_DEFINED(fixP->fx_addsy) + ? S_GET_TYPE(fixP->fx_addsy) + : fixP->fx_addsy->sy_number); + +#ifdef PIC + { + int extra_bits = 0; + int extrn_bit = !S_IS_DEFINED(fixP->fx_addsy); + + switch (fixP->fx_r_type) { + case NO_RELOC: + break; + case RELOC_32: + if (!flagseen['k'] || !S_IS_EXTERNAL(fixP->fx_addsy)) + break; + r_symbolnum = fixP->fx_addsy->sy_number; + extrn_bit = 1; + break; + case RELOC_GOT: + extra_bits = (1 << 4) & 0x10; /* r_baserel */ + r_symbolnum = fixP->fx_addsy->sy_number; + if (!extrn_bit && !S_IS_EXTERNAL(fixP->fx_addsy)) + as_warn("GOT relocation burb: `%s' should be global", + S_GET_NAME(fixP->fx_addsy)); + extrn_bit = 1; + break; + case RELOC_GOTOFF: + extra_bits = (1 << 4) & 0x10; /* r_baserel */ + r_symbolnum = fixP->fx_addsy->sy_number; + if (extrn_bit || S_IS_EXTERNAL(fixP->fx_addsy)) + as_warn("GOT relocation burb: `%s' should be static", + S_GET_NAME(fixP->fx_addsy)); + break; + case RELOC_JMP_TBL: + extra_bits = (1 << 5) & 0x20; /* r_jmptable */ + break; + case RELOC_RELATIVE: + /* consider using this bit (together with r_baserel) for + * GOTOFFs, so ld can check + */ + as_fatal("relocation botch"); + extra_bits = (1 << 6) & 0x40; /* r_relative */ + break; + } + where[6] = (r_symbolnum >> 16) & 0x0ff; + where[5] = (r_symbolnum >> 8) & 0x0ff; + where[4] = r_symbolnum & 0x0ff; + where[7] = ( ((extrn_bit << 3) & 0x08) + | ((nbytes_r_length[fixP->fx_size] << 1) & 0x06) + | ((fixP->fx_pcrel << 0) & 0x01) + | (extra_bits) + ); + } +#else + where[6] = (r_symbolnum >> 16) & 0x0ff; + where[5] = (r_symbolnum >> 8) & 0x0ff; + where[4] = r_symbolnum & 0x0ff; + where[7] = ((((!S_IS_DEFINED(fixP->fx_addsy)) << 3) & 0x08) + | ((nbytes_r_length[fixP->fx_size] << 1) & 0x06) + | (((fixP->fx_pcrel << 0) & 0x01) & 0x0f)); +#endif + + return; +} /* tc_aout_fix_to_chars() */ + +#endif /* OBJ_AOUT or OBJ_BOUT */ + + +#define MAX_LITTLENUMS 6 + +/* Turn the string pointed to by litP into a floating point constant of type + type, and emit the appropriate bytes. The number of LITTLENUMS emitted + is stored in *sizeP. An error message is returned, or NULL on OK. + */ +char * + md_atof(type,litP,sizeP) +char type; +char *litP; +int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + + switch (type) { + case 'f': + case 'F': + prec = 2; + break; + + case 'd': + case 'D': + prec = 4; + break; + + case 'x': + case 'X': + prec = 5; + break; + + default: + *sizeP=0; + return "Bad call to md_atof ()"; + } + t = atof_ieee (input_line_pointer,type,words); + if (t) + input_line_pointer=t; + + *sizeP = prec * sizeof(LITTLENUM_TYPE); + /* this loops outputs the LITTLENUMs in REVERSE order; in accord with + the bigendian 386 */ + for (wordP = words + prec - 1;prec--;) { + md_number_to_chars (litP, (long) (*wordP--), sizeof(LITTLENUM_TYPE)); + litP += sizeof(LITTLENUM_TYPE); + } + return ""; /* Someone should teach Dean about null pointers */ +} + +char output_invalid_buf[8]; + +static char * output_invalid (c) +char c; +{ + if (isprint(c)) sprintf (output_invalid_buf, "'%c'", c); + else sprintf (output_invalid_buf, "(0x%x)", (unsigned) c); + return output_invalid_buf; +} + +static reg_entry *parse_register (reg_string) +char *reg_string; /* reg_string starts *before* REGISTER_PREFIX */ +{ + register char *s = reg_string; + register char *p; + char reg_name_given[MAX_REG_NAME_SIZE]; + + s++; /* skip REGISTER_PREFIX */ + for (p = reg_name_given; is_register_char (*s); p++, s++) { + *p = register_chars[*s]; + if (p >= reg_name_given + MAX_REG_NAME_SIZE) + return (reg_entry *) 0; + } + *p = '\0'; + return (reg_entry *) hash_find (reg_hash, reg_name_given); +} + + +/* We have no need to default values of symbols. */ + +/* ARGSUSED */ +symbolS * + md_undefined_symbol (name) +char *name; +{ +#ifdef PIC + /* HACK: + * Sun's ld expects __GLOBAL_OFFSET_TABLE_, + * gcc generates _GLOBAL_OFFSET_TABLE_ + * should probably fix ld - new SVR4 style?? + */ + if (*name == '_' && *(name+1) == 'G' && + strcmp(name, "_GLOBAL_OFFSET_TABLE_") == 0) + return symbol_find("__GLOBAL_OFFSET_TABLE_"); +#endif + return 0; +} + +/* Parse an operand that is machine-specific. + We just return without modifying the expression if we have nothing + to do. */ + +/* ARGSUSED */ +void + md_operand (expressionP) +expressionS *expressionP; +{ +} + +/* Round up a section size to the appropriate boundary. */ +long + md_section_align (segment, size) +segT segment; +long size; +{ + return size; /* Byte alignment is fine */ +} + +/* Exactly what point is a PC-relative offset relative TO? + On the i386, they're relative to the address of the offset, plus + its size. (??? Is this right? FIXME-SOON!) */ +long + md_pcrel_from (fixP) +fixS *fixP; +{ +#ifdef PIC + /* + * _GLOBAL_OFFSET_TABLE_ refs are relative to the offset of the + * current instruction. fx_pcrel_adjust has been setup to account + * for the number of opcode bytes preceding the fixup location, + * it is zero for eg. .long pseudo-ops. + */ + if (fixP->fx_gotsy) + return fixP->fx_where + fixP->fx_frag->fr_address - fixP->fx_pcrel_adjust; + else +#endif + return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; +} + + /* these were macros, but I don't trust macros that eval their + arguments more than once. Besides, gcc can static inline them. + xoxorich. */ + +static unsigned long mode_from_disp_size(t) +unsigned long t; +{ + return((t & (Disp8)) + ? 1 + : ((t & (Disp32)) ? 2 : 0)); +} /* mode_from_disp_size() */ + +/* convert opcode suffix ('b' 'w' 'l' typically) into type specifyer */ + +static unsigned long opcode_suffix_to_type(s) +unsigned long s; +{ + return(s == BYTE_OPCODE_SUFFIX + ? Byte : (s == WORD_OPCODE_SUFFIX + ? Word : DWord)); +} /* opcode_suffix_to_type() */ + +static int fits_in_signed_byte(num) +long num; +{ + return((num >= -128) && (num <= 127)); +} /* fits_in_signed_byte() */ + +static int fits_in_unsigned_byte(num) +long num; +{ + return((num & 0xff) == num); +} /* fits_in_unsigned_byte() */ + +static int fits_in_unsigned_word(num) +long num; +{ + return((num & 0xffff) == num); +} /* fits_in_unsigned_word() */ + +static int fits_in_signed_word(num) +long num; +{ + return((-32768 <= num) && (num <= 32767)); +} /* fits_in_signed_word() */ + +static int smallest_imm_type(num) +long num; +{ + return((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))))); +} /* smallest_imm_type() */ + +static void s_bss() +{ + register int temp; + + temp = get_absolute_expression (); + subseg_new (SEG_BSS, (subsegT)temp); + demand_empty_rest_of_line(); +} + +/* + * Local Variables: + * comment-column: 0 + * End: + */ + +/* end of tc-i386.c */ diff --git a/gnu/usr.bin/as/config/tc-i386.h b/gnu/usr.bin/as/config/tc-i386.h new file mode 100644 index 000000000000..9f7de01106be --- /dev/null +++ b/gnu/usr.bin/as/config/tc-i386.h @@ -0,0 +1,254 @@ +/* tc-i386.h -- Header file for tc-i386.c + Copyright (C) 1989, 1992 Free Software Foundation. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * $Id: tc-i386.h,v 1.1 1993/11/03 00:54:25 paul Exp $ + */ + +#ifndef TC_I386 +#define TC_I386 1 + +#if 0 +#define AOUT_MACHTYPE 100 +#endif +#define REVERSE_SORT_RELOCS + +#define LOCAL_LABELS_FB + +#define NO_LISTING + +#define tc_coff_symbol_emit_hook(a) ; /* not used */ + + /* Local labels starts with .L */ + /* fixme-now: this is for testing against old gas */ +/* #define LOCAL_LABEL(name) ((name)[0] == '.' && (name)[1] == 'L') */ +#define tc_aout_pre_write_hook(x) {;} /* not used */ +#define tc_crawl_symbol_chain(a) {;} /* not used */ +#define tc_headers_hook(a) {;} /* not used */ + +#define MAX_OPERANDS 3 /* max operands per insn */ +#define MAX_PREFIXES 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 + +#ifndef OLD_GAS +#define NOP_OPCODE 0x90 +#else /* OLD_GAS */ +#define NOP_OPCODE 0x00 +#endif /* OLD_GAS */ + +/* 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 Byte (Reg8|Imm8|Imm8S) +#define Word (Reg16|Imm16) +#define DWord (Reg32|Imm32) + +#define SMALLEST_DISP_TYPE(num) \ + fits_in_signed_byte(num) ? (Disp8|Disp32|Abs8|Abs32) : (Disp32|Abs32) + +typedef struct { + /* instruction name sans width suffix ("mov" for movl insns) */ + char *name; + + /* how many operands */ + unsigned int operands; + + /* base_opcode is the fundamental opcode byte with a optional prefix(es). */ + unsigned int base_opcode; + + /* extension_opcode is the 3 bit extension for group <n> insns. + If this template has no extension opcode (the usual case) use None */ + unsigned char extension_opcode; +#define None 0xff /* If no extension_opcode is possible. */ + + /* the bits in opcode_modifier are used to generate the final opcode from + the base_opcode. These bits also are used to detect alternate forms of + the same instruction */ + unsigned int opcode_modifier; + + /* opcode_modifier bits: */ +#define W 0x1 /* set if operands are words or dwords */ +#define D 0x2 /* D = 0 if Reg --> Regmem; D = 1 if Regmem --> Reg */ + /* direction flag for floating insns: MUST BE 0x400 */ +#define FloatD 0x400 + /* shorthand */ +#define DW (D|W) +#define ShortForm 0x10 /* register is in low 3 bits of opcode */ +#define ShortFormW 0x20 /* ShortForm and W bit is 0x8 */ +#define Seg2ShortForm 0x40 /* encoding of load segment reg insns */ +#define Seg3ShortForm 0x80 /* fs/gs segment register insns. */ +#define Jump 0x100 /* special case for jump insns. */ +#define JumpInterSegment 0x200 /* special case for intersegment leaps/calls */ + /* 0x400 CANNOT BE USED since it's already used by FloatD above */ +#define DONT_USE 0x400 +#define NoModrm 0x800 +#define Modrm 0x1000 +#define imulKludge 0x2000 +#define JumpByte 0x4000 +#define JumpDword 0x8000 +#define ReverseRegRegmem 0x10000 + + /* (opcode_modifier & COMES_IN_ALL_SIZES) is true if the + instuction comes in byte, word, and dword sizes and is encoded into + machine code in the canonical way. */ +#define COMES_IN_ALL_SIZES (W) + + /* (opcode_modifier & COMES_IN_BOTH_DIRECTIONS) indicates that the + source and destination operands can be reversed by setting either + the D (for integer insns) or the FloatD (for floating insns) bit + in base_opcode. */ +#define COMES_IN_BOTH_DIRECTIONS (D|FloatD) + + /* operand_types[i] describes the type of operand i. This is made + by OR'ing together all of the possible type masks. (e.g. + 'operand_types[i] = Reg|Imm' specifies that operand i can be + either a register or an immediate operand */ + unsigned int operand_types[3]; +} template; + +/* + 'templates' is for grouping together 'template' structures for opcodes + of the same name. This is only used for storing the insns in the grand + ole hash table of insns. + The templates themselves start at START and range up to (but not including) + END. + */ +typedef struct { + template *start; + template *end; +} templates; + +/* these are for register name --> number & type hash lookup */ +typedef struct { + char *reg_name; + unsigned int reg_type; + unsigned int reg_num; +} reg_entry; + +typedef struct { + char *seg_name; + unsigned int seg_prefix; +} seg_entry; + +/* these are for prefix name --> prefix code hash lookup */ +typedef struct { + char *prefix_name; + unsigned char prefix_code; +} prefix_entry; + +/* 386 operand encoding bytes: see 386 book for details of this. */ +typedef struct { + unsigned regmem:3; /* codes register or memory operand */ + unsigned reg:3; /* codes register operand (or extended opcode) */ + unsigned mode:2; /* how to interpret regmem & reg */ +} modrm_byte; + +/* 386 opcode byte to code indirect addressing. */ +typedef struct { + unsigned base:3; + unsigned index:3; + unsigned scale:2; +} base_index_byte; + +#endif /* TC_I386 */ + +/* end of tc-i386.h */ diff --git a/gnu/usr.bin/as/config/tc-i860.c b/gnu/usr.bin/as/config/tc-i860.c new file mode 100644 index 000000000000..012313841698 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-i860.c @@ -0,0 +1,1295 @@ +/* tc-i860.c -- Assemble for the I860 + Copyright (C) 1989, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "as.h" + +#include "opcode/i860.h" + +void md_begin(); +void md_end(); +void md_number_to_chars(); +void md_assemble(); +char *md_atof(); +void md_convert_frag(); +void md_create_short_jump(); +void md_create_long_jump(); +int md_estimate_size_before_relax(); +void md_number_to_imm(); +void md_number_to_disp(); +void md_number_to_field(); +void md_ri_to_chars(); +static void i860_ip(); + +const relax_typeS md_relax_table[] = { 0 }; + +/* handle of the OPCODE hash table */ +static struct hash_control *op_hash = NULL; + +static void s_dual(), s_enddual(); +static void s_atmp(); + +const pseudo_typeS + md_pseudo_table[] = { + { "dual", s_dual, 4 }, + { "enddual", s_enddual, 4 }, + { "atmp", s_atmp, 4 }, + { NULL, 0, 0 }, + }; + +int md_short_jump_size = 4; +int md_long_jump_size = 4; + +/* This array holds the chars that always start a comment. If the + pre-processor is disabled, these aren't very useful */ +char comment_chars[] = "!/"; /* JF removed '|' from comment_chars */ + +/* This array holds the chars that only start a comment at the beginning of + a line. If the line seems to have the form '# 123 filename' + .line and .file directives will appear in the pre-processed output */ +/* Note that input_file.c hand checks for '#' at the beginning of the + first line of the input file. This is because the compiler outputs + #NO_APP at the beginning of its output. */ +/* Also note that comments like this one will always work. */ +char line_comment_chars[] = "#/"; + +/* Chars that can be used to separate mant from exp in floating point nums */ +char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant */ +/* As in 0f12.456 */ +/* or 0d1.2345e12 */ +char FLT_CHARS[] = "rRsSfFdDxXpP"; + +/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be + changed in read.c. Ideally it shouldn't have to know about it at all, + but nothing is ideal around here. + */ +int size_reloc_info = sizeof(struct relocation_info); + +static unsigned char octal[256]; +#define isoctal(c) octal[c] + static unsigned char toHex[256]; + +struct i860_it { + char *error; + unsigned long opcode; + struct nlist *nlistp; + expressionS exp; + int pcrel; + enum expand_type expand; + enum highlow_type highlow; + enum reloc_type reloc; +} the_insn; + +#if __STDC__ == 1 + +#ifdef comment +static void print_insn(struct i860_it *insn); +#endif /* comment */ + +static int getExpression(char *str); + +#else /* not __STDC__ */ + +#ifdef comment +static void print_insn(); +#endif /* comment */ + +static int getExpression(); + +#endif /* not __STDC__ */ + +static char *expr_end; +static char last_expand; /* error if expansion after branch */ + +enum dual +{ + DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT, +}; +static enum dual dual_mode = DUAL_OFF; /* dual-instruction mode */ + +static void + s_dual() /* floating point instructions have dual set */ +{ + dual_mode = DUAL_ON; +} + +static void + s_enddual() /* floating point instructions have dual set */ +{ + dual_mode = DUAL_OFF; +} + +static int atmp = 31; /* temporary register for pseudo's */ + +static void + s_atmp() +{ + register int temp; + if (strncmp(input_line_pointer, "sp", 2) == 0) { + input_line_pointer += 2; + atmp = 2; + } + else if (strncmp(input_line_pointer, "fp", 2) == 0) { + input_line_pointer += 2; + atmp = 3; + } + else if (strncmp(input_line_pointer, "r", 1) == 0) { + input_line_pointer += 1; + temp = get_absolute_expression(); + if (temp >= 0 && temp <= 31) + atmp = temp; + else + as_bad("Unknown temporary pseudo register"); + } + else { + as_bad("Unknown temporary pseudo register"); + } + demand_empty_rest_of_line(); + return; +} + +/* This function is called once, at assembler startup time. It should + set up all the tables, etc. that the MD part of the assembler will need. */ +void + md_begin() +{ + register char *retval = NULL; + int lose = 0; + register unsigned int i = 0; + + op_hash = hash_new(); + if (op_hash == NULL) + as_fatal("Virtual memory exhausted"); + + while (i < NUMOPCODES) + { + const char *name = i860_opcodes[i].name; + retval = hash_insert(op_hash, name, &i860_opcodes[i]); + if (retval != NULL && *retval != '\0') + { + fprintf (stderr, "internal error: can't hash `%s': %s\n", + i860_opcodes[i].name, retval); + lose = 1; + } + do + { + if (i860_opcodes[i].match & i860_opcodes[i].lose) + { + fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n", + i860_opcodes[i].name, i860_opcodes[i].args); + lose = 1; + } + ++i; + } while (i < NUMOPCODES + && !strcmp(i860_opcodes[i].name, name)); + } + + if (lose) + as_fatal("Broken assembler. No assembly attempted."); + + for (i = '0'; i < '8'; ++i) + octal[i] = 1; + for (i = '0'; i <= '9'; ++i) + toHex[i] = i - '0'; + for (i = 'a'; i <= 'f'; ++i) + toHex[i] = i + 10 - 'a'; + for (i = 'A'; i <= 'F'; ++i) + toHex[i] = i + 10 - 'A'; +} + +void + md_end() +{ + return; +} + +void + md_assemble(str) +char *str; +{ + char *toP; +/* int rsd; FIXME: remove this line. */ + int no_opcodes = 1; + int i; + struct i860_it pseudo[3]; + + assert(str); + i860_ip(str); + + /* check for expandable flag to produce pseudo-instructions */ + if (the_insn.expand != 0 && the_insn.highlow == NO_SPEC) { + for (i = 0; i < 3; i++) + pseudo[i] = the_insn; + + switch (the_insn.expand) { + + case E_DELAY: + no_opcodes = 1; + break; + + case E_MOV: + if (the_insn.exp.X_add_symbol == NULL && + the_insn.exp.X_subtract_symbol == NULL && + (the_insn.exp.X_add_number < (1 << 15) && + the_insn.exp.X_add_number >= -(1 << 15))) + break; + /* or l%const,r0,ireg_dest */ + pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000; + pseudo[0].highlow = PAIR; + /* orh h%const,ireg_dest,ireg_dest */ + pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 | + ((the_insn.opcode & 0x001f0000) << 5); + pseudo[1].highlow = HIGH; + no_opcodes = 2; + break; + + case E_ADDR: + if (the_insn.exp.X_add_symbol == NULL && + the_insn.exp.X_subtract_symbol == NULL) + break; + /* orh ha%addr_expr,r0,r31 */ + pseudo[0].opcode = 0xec000000 | (atmp<<16); + pseudo[0].highlow = HIGHADJ; + pseudo[0].reloc = LOW0; /* must overwrite */ + /* l%addr_expr(r31),ireg_dest */ + pseudo[1].opcode = (the_insn.opcode & ~0x003e0000) | (atmp << 21); + pseudo[1].highlow = PAIR; + no_opcodes = 2; + break; + + case E_U32: /* 2nd version emulates Intel as, not doc. */ + if (the_insn.exp.X_add_symbol == NULL && + the_insn.exp.X_subtract_symbol == NULL && + (the_insn.exp.X_add_number < (1 << 16) && + the_insn.exp.X_add_number >= 0)) + break; + /* $(opcode)h h%const,ireg_src2,ireg_dest + pseudo[0].opcode = (the_insn.opcode & 0xf3ffffff) | 0x0c000000; */ + /* $(opcode)h h%const,ireg_src2,r31 */ + pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 | + (atmp << 16); + pseudo[0].highlow = HIGH; + /* $(opcode) l%const,ireg_dest,ireg_dest + pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 | + ((the_insn.opcode & 0x001f0000) << 5); */ + /* $(opcode) l%const,r31,ireg_dest */ + pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 | + (atmp << 21); + pseudo[1].highlow = PAIR; + no_opcodes = 2; + break; + + case E_AND: /* 2nd version emulates Intel as, not doc. */ + if (the_insn.exp.X_add_symbol == NULL && + the_insn.exp.X_subtract_symbol == NULL && + (the_insn.exp.X_add_number < (1 << 16) && + the_insn.exp.X_add_number >= 0)) + break; + /* andnot h%const,ireg_src2,ireg_dest + pseudo[0].opcode = (the_insn.opcode & 0x03ffffff) | 0xd4000000; */ + /* andnot h%const,ireg_src2,r31 */ + pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000 | + (atmp << 16); + pseudo[0].highlow = HIGH; + pseudo[0].exp.X_add_number = -1 - the_insn.exp.X_add_number; + /* andnot l%const,ireg_dest,ireg_dest + pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 | + ((the_insn.opcode & 0x001f0000) << 5); */ + /* andnot l%const,r31,ireg_dest */ + pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 | + (atmp << 21); + pseudo[1].highlow = PAIR; + pseudo[1].exp.X_add_number = -1 - the_insn.exp.X_add_number; + no_opcodes = 2; + break; + + case E_S32: + if (the_insn.exp.X_add_symbol == NULL && + the_insn.exp.X_subtract_symbol == NULL && + (the_insn.exp.X_add_number < (1 << 15) && + the_insn.exp.X_add_number >= -(1 << 15))) + break; + /* orh h%const,r0,r31 */ + pseudo[0].opcode = 0xec000000 | (atmp << 16); + pseudo[0].highlow = HIGH; + /* or l%const,r31,r31 */ + pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16); + pseudo[1].highlow = PAIR; + /* r31,ireg_src2,ireg_dest */ + pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11); + pseudo[2].reloc = NO_RELOC; + no_opcodes = 3; + break; + + default: + as_fatal("failed sanity check."); + } + + the_insn = pseudo[0]; + /* check for expanded opcode after branch or in dual */ + if (no_opcodes > 1 && last_expand == 1) + as_warn("Expanded opcode after delayed branch: `%s'", str); + if (no_opcodes > 1 && dual_mode != DUAL_OFF) + as_warn("Expanded opcode in dual mode: `%s'", str); + } + + i = 0; + do { /* always produce at least one opcode */ + toP = frag_more(4); + /* put out the opcode */ + md_number_to_chars(toP, the_insn.opcode, 4); + + /* check for expanded opcode after branch or in dual */ + last_expand = the_insn.pcrel; + + /* put out the symbol-dependent stuff */ + if (the_insn.reloc != NO_RELOC) { + fix_new(frag_now, /* which frag */ + (toP - frag_now->fr_literal), /* where */ + 4, /* size */ + the_insn.exp.X_add_symbol, + the_insn.exp.X_subtract_symbol, + the_insn.exp.X_add_number, + the_insn.pcrel, + /* merge bit fields into one argument */ + (int)(((the_insn.highlow & 0x3) << 4) | (the_insn.reloc & 0xf))); + } + the_insn = pseudo[++i]; + } while (--no_opcodes > 0); + +} + +static void + i860_ip(str) +char *str; +{ + char *s; + const char *args; + char c; +/* unsigned long i; FIXME: remove this line. */ + struct i860_opcode *insn; + char *argsStart; + unsigned long opcode; + unsigned int mask; + int match = 0; + int comma = 0; + + + for (s = str; islower(*s) || *s == '.' || *s == '3'; ++s) + ; + switch (*s) { + + case '\0': + break; + + case ',': + comma = 1; + + /*FALLTHROUGH*/ + + case ' ': + *s++ = '\0'; + break; + + default: + as_bad("Unknown opcode: `%s'", str); + exit(1); + } + + if (strncmp(str, "d.", 2) == 0) { /* check for d. opcode prefix */ + if (dual_mode == DUAL_ON) + dual_mode = DUAL_ONDDOT; + else + dual_mode = DUAL_DDOT; + str += 2; + } + + if ((insn = (struct i860_opcode *) hash_find(op_hash, str)) == NULL) { + if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT) + str -= 2; + as_bad("Unknown opcode: `%s'", str); + return; + } + if (comma) { + *--s = ','; + } + argsStart = s; + for (;;) { + opcode = insn->match; + memset(&the_insn, '\0', sizeof(the_insn)); + the_insn.reloc = NO_RELOC; + + /* + * Build the opcode, checking as we go to make + * sure that the operands match + */ + for (args = insn->args; ; ++args) { + switch (*args) { + + case '\0': /* end of args */ + if (*s == '\0') { + match = 1; + } + break; + + case '+': + case '(': /* these must match exactly */ + case ')': + case ',': + case ' ': + if (*s++ == *args) + continue; + break; + + case '#': /* must be at least one digit */ + if (isdigit(*s++)) { + while (isdigit(*s)) { + ++s; + } + continue; + } + break; + + case '1': /* next operand must be a register */ + case '2': + case 'd': + switch (*s) { + + case 'f': /* frame pointer */ + s++; + if (*s++ == 'p') { + mask = 0x3; + break; + } + goto error; + + case 's': /* stack pointer */ + s++; + if (*s++ == 'p') { + mask= 0x2; + break; + } + goto error; + + case 'r': /* any register */ + s++; + if (!isdigit(c = *s++)) { + goto error; + } + if (isdigit(*s)) { + if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) { + goto error; + } + } else { + c -= '0'; + } + mask= c; + break; + + default: /* not this opcode */ + goto error; + } + /* + * Got the register, now figure out where + * it goes in the opcode. + */ + switch (*args) { + + case '1': + opcode |= mask << 11; + continue; + + case '2': + opcode |= mask << 21; + continue; + + case 'd': + opcode |= mask << 16; + continue; + + } + break; + + case 'e': /* next operand is a floating point register */ + case 'f': + case 'g': + if (*s++ == 'f' && isdigit(*s)) { + mask = *s++; + if (isdigit(*s)) { + mask = 10 * (mask - '0') + (*s++ - '0'); + if (mask >= 32) { + break; + } + } else { + mask -= '0'; + } + switch (*args) { + + case 'e': + opcode |= mask << 11; + continue; + + case 'f': + opcode |= mask << 21; + continue; + + case 'g': + opcode |= mask << 16; + if (dual_mode != DUAL_OFF) + opcode |= (1 << 9); /* dual mode instruction */ + if (dual_mode == DUAL_DDOT) + dual_mode = DUAL_OFF; + if (dual_mode == DUAL_ONDDOT) + dual_mode = DUAL_ON; + if ((opcode & (1 << 10)) && (mask == ((opcode >> 11) & 0x1f))) + as_warn("Fsr1 equals fdest with Pipelining"); + continue; + } + } + break; + + case 'c': /* next operand must be a control register */ + if (strncmp(s, "fir", 3) == 0) { + opcode |= 0x0 << 21; + s += 3; + continue; + } + if (strncmp(s, "psr", 3) == 0) { + opcode |= 0x1 << 21; + s += 3; + continue; + } + if (strncmp(s, "dirbase", 7) == 0) { + opcode |= 0x2 << 21; + s += 7; + continue; + } + if (strncmp(s, "db", 2) == 0) { + opcode |= 0x3 << 21; + s += 2; + continue; + } + if (strncmp(s, "fsr", 3) == 0) { + opcode |= 0x4 << 21; + s += 3; + continue; + } + if (strncmp(s, "epsr", 4) == 0) { + opcode |= 0x5 << 21; + s += 4; + continue; + } + break; + + case '5': /* 5 bit immediate in src1 */ + memset(&the_insn, '\0', sizeof(the_insn)); + if ( !getExpression(s)) { + s = expr_end; + if (the_insn.exp.X_add_number & ~0x1f) + as_bad("5-bit immediate too large"); + opcode |= (the_insn.exp.X_add_number & 0x1f) << 11; + memset(&the_insn, '\0', sizeof(the_insn)); + the_insn.reloc = NO_RELOC; + continue; + } + break; + + case 'l': /* 26 bit immediate, relative branch */ + the_insn.reloc = BRADDR; + the_insn.pcrel = 1; + goto immediate; + + case 's': /* 16 bit immediate, split relative branch */ + /* upper 5 bits of offset in dest field */ + the_insn.pcrel = 1; + the_insn.reloc = SPLIT0; + goto immediate; + + case 'S': /* 16 bit immediate, split (st), aligned */ + if (opcode & (1 << 28)) + if (opcode & 0x1) + the_insn.reloc = SPLIT2; + else + the_insn.reloc = SPLIT1; + else + the_insn.reloc = SPLIT0; + goto immediate; + + case 'I': /* 16 bit immediate, aligned */ + if (opcode & (1 << 28)) + if (opcode & 0x1) + the_insn.reloc = LOW2; + else + the_insn.reloc = LOW1; + else + the_insn.reloc = LOW0; + goto immediate; + + case 'i': /* 16 bit immediate */ + the_insn.reloc = LOW0; + + /*FALLTHROUGH*/ + + immediate: + if (*s == ' ') + s++; + if (strncmp(s, "ha%", 3) == 0) { + the_insn.highlow = HIGHADJ; + s += 3; + } else if (strncmp(s, "h%", 2) == 0) { + the_insn.highlow = HIGH; + s += 2; + } else if (strncmp(s, "l%", 2) == 0) { + the_insn.highlow = PAIR; + s += 2; + } + the_insn.expand = insn->expand; + + /* Note that if the getExpression() fails, we will still have + created U entries in the symbol table for the 'symbols' + in the input string. Try not to create U symbols for + registers, etc. */ + + if ( !getExpression(s)) { + s = expr_end; + continue; + } + break; + + default: + as_fatal("failed sanity check."); + } + break; + } + error: + if (match == 0) + { + /* Args don't match. */ + if (&insn[1] - i860_opcodes < NUMOPCODES + && !strcmp(insn->name, insn[1].name)) + { + ++insn; + s = argsStart; + continue; + } + else + { + as_bad("Illegal operands"); + return; + } + } + break; + } + + the_insn.opcode = opcode; + return; +} + +static int + getExpression(str) +char *str; +{ + char *save_in; + segT seg; + + save_in = input_line_pointer; + input_line_pointer = str; + switch (seg = expression(&the_insn.exp)) { + + case SEG_ABSOLUTE: + case SEG_TEXT: + case SEG_DATA: + case SEG_BSS: + case SEG_UNKNOWN: + case SEG_DIFFERENCE: + case SEG_BIG: + case SEG_ABSENT: + break; + + default: + the_insn.error = "bad segment"; + expr_end = input_line_pointer; + input_line_pointer=save_in; + return 1; + } + expr_end = input_line_pointer; + input_line_pointer = save_in; + return 0; +} + + +/* + This is identical to the md_atof in m68k.c. I think this is right, + but I'm not sure. + + Turn a string in input_line_pointer into a floating point constant of type + type, and store the appropriate bytes in *litP. The number of LITTLENUMS + emitted is stored in *sizeP. An error message is returned, or NULL on OK. + */ + +/* Equal to MAX_PRECISION in atof-ieee.c */ +#define MAX_LITTLENUMS 6 + +char * + md_atof(type,litP,sizeP) +char type; +char *litP; +int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + char *atof_ieee(); + + switch (type) { + + case 'f': + case 'F': + case 's': + case 'S': + prec = 2; + break; + + case 'd': + case 'D': + case 'r': + case 'R': + prec = 4; + break; + + case 'x': + case 'X': + prec = 6; + break; + + case 'p': + case 'P': + prec = 6; + break; + + default: + *sizeP=0; + return "Bad call to MD_ATOF()"; + } + t=atof_ieee(input_line_pointer,type,words); + if (t) + input_line_pointer=t; + *sizeP=prec * sizeof(LITTLENUM_TYPE); + for (wordP=words;prec--;) { + md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE)); + litP+=sizeof(LITTLENUM_TYPE); + } + return ""; /* Someone should teach Dean about null pointers */ +} + +/* + * Write out big-endian. + */ +void + md_number_to_chars(buf, val, n) +char *buf; +long val; +int n; +{ + switch (n) { + + case 4: + *buf++ = val >> 24; + *buf++ = val >> 16; + case 2: + *buf++ = val >> 8; + case 1: + *buf = val; + break; + + default: + as_fatal("failed sanity check."); + } + return; +} + +void md_number_to_imm(buf, val, n, fixP) +char *buf; +long val; +int n; +fixS *fixP; +{ + enum reloc_type reloc = fixP->fx_r_type & 0xf; + enum highlow_type highlow = (fixP->fx_r_type >> 4) & 0x3; + + assert(buf); + assert(n == 4); /* always on i860 */ + + switch (highlow) { + + case HIGHADJ: /* adjusts the high-order 16-bits */ + if (val & (1 << 15)) + val += (1 << 16); + + /*FALLTHROUGH*/ + + case HIGH: /* selects the high-order 16-bits */ + val >>= 16; + break; + + case PAIR: /* selects the low-order 16-bits */ + val = val & 0xffff; + break; + + default: + break; + } + + switch (reloc) { + + case BRADDR: /* br, call, bc, bc.t, bnc, bnc.t w/26-bit immediate */ + if (fixP->fx_pcrel != 1) + as_bad("26-bit branch w/o pc relative set: 0x%08x", val); + val >>= 2; /* align pcrel offset, see manual */ + + if (val >= (1 << 25) || val < -(1 << 25)) /* check for overflow */ + as_bad("26-bit branch offset overflow: 0x%08x", val); + buf[0] = (buf[0] & 0xfc) | ((val >> 24) & 0x3); + buf[1] = val >> 16; + buf[2] = val >> 8; + buf[3] = val; + break; + + case SPLIT2: /* 16 bit immediate, 4-byte aligned */ + if (val & 0x3) + as_bad("16-bit immediate 4-byte alignment error: 0x%08x", val); + val &= ~0x3; /* 4-byte align value */ + /*FALLTHROUGH*/ + case SPLIT1: /* 16 bit immediate, 2-byte aligned */ + if (val & 0x1) + as_bad("16-bit immediate 2-byte alignment error: 0x%08x", val); + val &= ~0x1; /* 2-byte align value */ + /*FALLTHROUGH*/ + case SPLIT0: /* st,bla,bte,btne w/16-bit immediate */ + if (fixP->fx_pcrel == 1) + val >>= 2; /* align pcrel offset, see manual */ + /* check for bounds */ + if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15))) + as_bad("16-bit branch offset overflow: 0x%08x", val); + buf[1] = (buf[1] & ~0x1f) | ((val >> 11) & 0x1f); + buf[2] = (buf[2] & ~0x7) | ((val >> 8) & 0x7); + buf[3] |= val; /* perserve bottom opcode bits */ + break; + + case LOW4: /* fld,pfld,pst,flush 16-byte aligned */ + if (val & 0xf) + as_bad("16-bit immediate 16-byte alignment error: 0x%08x", val); + val &= ~0xf; /* 16-byte align value */ + /*FALLTHROUGH*/ + case LOW3: /* fld,pfld,pst,flush 8-byte aligned */ + if (val & 0x7) + as_bad("16-bit immediate 8-byte alignment error: 0x%08x", val); + val &= ~0x7; /* 8-byte align value */ + /*FALLTHROUGH*/ + case LOW2: /* 16 bit immediate, 4-byte aligned */ + if (val & 0x3) + as_bad("16-bit immediate 4-byte alignment error: 0x%08x", val); + val &= ~0x3; /* 4-byte align value */ + /*FALLTHROUGH*/ + case LOW1: /* 16 bit immediate, 2-byte aligned */ + if (val & 0x1) + as_bad("16-bit immediate 2-byte alignment error: 0x%08x", val); + val &= ~0x1; /* 2-byte align value */ + /*FALLTHROUGH*/ + case LOW0: /* 16 bit immediate, byte aligned */ + /* check for bounds */ + if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15))) + as_bad("16-bit immediate overflow: 0x%08x", val); + buf[2] = val >> 8; + buf[3] |= val; /* perserve bottom opcode bits */ + break; + + case RELOC_32: + md_number_to_chars(buf, val, 4); + break; + + case NO_RELOC: + default: + as_bad("bad relocation type: 0x%02x", reloc); + break; + } + return; +} + +/* should never be called for i860 */ +void + md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol) +char *ptr; +long from_addr, to_addr; +fragS *frag; +symbolS *to_symbol; +{ + as_fatal("i860_create_short_jmp\n"); +} + +/* should never be called for i860 */ +void + md_number_to_disp(buf, val, n) +char *buf; +long val; +int n; +{ + as_fatal("md_number_to_disp\n"); +} + +/* should never be called for i860 */ +void + md_number_to_field(buf,val,fix) +char *buf; +long val; +void *fix; +{ + as_fatal("i860_number_to_field\n"); +} + +/* the bit-field entries in the relocation_info struct plays hell + with the byte-order problems of cross-assembly. So as a hack, + I added this mach. dependent ri twiddler. Ugly, but it gets + you there. -KWK */ +/* on i860: first 4 bytes are normal unsigned long address, next three + bytes are index, most sig. byte first. Byte 7 is broken up with + bit 7 as pcrel, bit 6 as extern, and the lower six bits as + relocation type (highlow 5-4). Next 4 bytes are long addend. */ +/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */ +void + md_ri_to_chars(ri_p, ri) +struct relocation_info *ri_p, ri; +{ +#if 0 + unsigned char the_bytes[sizeof(*ri_p)]; + + /* this is easy */ + md_number_to_chars(the_bytes, ri.r_address, sizeof(ri.r_address)); + /* now the fun stuff */ + the_bytes[4] = (ri.r_index >> 16) & 0x0ff; + the_bytes[5] = (ri.r_index >> 8) & 0x0ff; + the_bytes[6] = ri.r_index & 0x0ff; + the_bytes[7] = ((ri.r_extern << 7) & 0x80) | (0 & 0x60) | (ri.r_type & 0x1F); + /* Also easy */ + md_number_to_chars(&the_bytes[8], ri.r_addend, sizeof(ri.r_addend)); + /* now put it back where you found it, Junior... */ + memcpy((char *) ri_p, the_bytes, sizeof(*ri_p)); +#endif +} + +/* should never be called for i860 */ +void + md_convert_frag(headers, fragP) +object_headers *headers; +register fragS *fragP; +{ + as_fatal("i860_convert_frag\n"); +} + +/* should never be called for i860 */ +void + md_create_long_jump(ptr, from_addr, to_addr, frag, to_symbol) +char *ptr; +long from_addr, + to_addr; +fragS *frag; +symbolS *to_symbol; +{ + as_fatal("i860_create_long_jump\n"); +} + +/* should never be called for i860 */ +int + md_estimate_size_before_relax(fragP, segtype) +register fragS *fragP; +segT segtype; +{ + as_fatal("i860_estimate_size_before_relax\n"); + return(0); +} + +#ifdef comment +/* for debugging only, must match enum reloc_type */ +static char *Reloc[] = { + "NO_RELOC", + "BRADDR", + "LOW0", + "LOW1", + "LOW2", + "LOW3", + "LOW4", + "SPLIT0", + "SPLIT1", + "SPLIT2", + "RELOC_32", +}; +static char *Highlow[] = { + "NO_SPEC", + "PAIR", + "HIGH", + "HIGHADJ", +}; + +static void + print_insn(insn) +struct i860_it *insn; +{ + if (insn->error) { + fprintf(stderr, "ERROR: %s\n", insn->error); + } + fprintf(stderr, "opcode=0x%08x\t", insn->opcode); + fprintf(stderr, "expand=0x%08x\t", insn->expand); + fprintf(stderr, "reloc = %s\t", Reloc[insn->reloc]); + fprintf(stderr, "highlow = %s\n", Highlow[insn->highlow]); + fprintf(stderr, "exp = {\n"); + fprintf(stderr, "\t\tX_add_symbol = %s\n", + insn->exp.X_add_symbol ? + (S_GET_NAME(insn->exp.X_add_symbol) ? + S_GET_NAME(insn->exp.X_add_symbol) : "???") : "0"); + fprintf(stderr, "\t\tX_sub_symbol = %s\n", + insn->exp.X_subtract_symbol ? + (S_GET_NAME(insn->exp.X_subtract_symbol) ? + S_GET_NAME(insn->exp.X_subtract_symbol) : "???") : "0"); + fprintf(stderr, "\t\tX_add_number = %d\n", + insn->exp.X_add_number); + fprintf(stderr, "}\n"); + return; +} +#endif /* comment */ + +int + md_parse_option(argP,cntP,vecP) +char **argP; +int *cntP; +char ***vecP; +{ + return 1; +} + +#ifdef comment +/* + * I860 relocations are completely different, so it needs + * this machine dependent routine to emit them. + */ +void + emit_machine_reloc(fixP, segment_address_in_file) +register fixS *fixP; +relax_addressT segment_address_in_file; +{ + struct reloc_info_i860 ri; + register symbolS *symbolP; + extern char *next_object_file_charP; + long add_number; + + memset((char *) &ri, '\0', sizeof(ri)); + for (; fixP; fixP = fixP->fx_next) { + + if (fixP->fx_r_type & ~0x3f) { + as_fatal("fixP->fx_r_type = %d\n", fixP->fx_r_type); + } + ri.r_pcrel = fixP->fx_pcrel; + ri.r_type = fixP->fx_r_type; + + if ((symbolP = fixP->fx_addsy) != NULL) { + ri.r_address = fixP->fx_frag->fr_address + + fixP->fx_where - segment_address_in_file; + if (!S_IS_DEFINED(symbolP)) { + ri.r_extern = 1; + ri.r_symbolnum = symbolP->sy_number; + } else { + ri.r_extern = 0; + ri.r_symbolnum = S_GET_TYPE(symbolP); + } + if (symbolP && symbolP->sy_frag) { + ri.r_addend = symbolP->sy_frag->fr_address; + } + ri.r_type = fixP->fx_r_type; + if (fixP->fx_pcrel) { + /* preserve actual offset vs. pc + 4 */ + ri.r_addend -= (ri.r_address + 4); + } else { + ri.r_addend = fixP->fx_addnumber; + } + + md_ri_to_chars((char *) &ri, ri); + append(&next_object_file_charP, (char *)& ri, sizeof(ri)); + } + } + return; +} +#endif /* comment */ + +#ifdef OBJ_AOUT + +/* on i860: first 4 bytes are normal unsigned long address, next three + bytes are index, most sig. byte first. Byte 7 is broken up with + bit 7 as pcrel, bit 6 as extern, and the lower six bits as + relocation type (highlow 5-4). Next 4 bytes are long addend. + + ie, + + struct reloc_info_i860 { + unsigned long r_address; + unsigned int r_symbolnum : 24; + unsigned int r_pcrel : 1; + unsigned int r_extern : 1; + unsigned int r_type : 6; + long r_addend; + } + + */ + +int md_reloc_size = 12; + +void tc_aout_fix_to_chars(where, fixP, segment_address_in_file) +char *where; +fixS *fixP; +relax_addressT segment_address_in_file; +{ + long r_index; + long r_extern; + long r_addend = 0; + long r_address; + + know(fixP->fx_addsy); + know(!(fixP->fx_r_type & ~0x3f)); + + if (!S_IS_DEFINED(fixP->fx_addsy)) { + r_extern = 1; + r_index = fixP->fx_addsy->sy_number; + } else { + r_extern = 0; + r_index = S_GET_TYPE(fixP->fx_addsy); + } + + md_number_to_chars(where, + r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, + 4); + + where[4] = (r_index >> 16) & 0x0ff; + where[5] = (r_index >> 8) & 0x0ff; + where[6] = r_index & 0x0ff; + where[7] = (((fixP->fx_pcrel << 7) & 0x80) + | ((r_extern << 6) & 0x40) + | (fixP->fx_r_type & 0x3F)); + + if (fixP->fx_addsy->sy_frag) { + r_addend = fixP->fx_addsy->sy_frag->fr_address; + } + + if (fixP->fx_pcrel) { + /* preserve actual offset vs. pc + 4 */ + r_addend -= (r_address + 4); + } else { + r_addend = fixP->fx_addnumber; + } + + md_number_to_chars(&where[8], r_addend, 4); + + return; +} /* tc_aout_fix_to_chars() */ + +#endif /* OBJ_AOUT */ + +/* Parse an operand that is machine-specific. + We just return without modifying the expression if we have nothing + to do. */ + +/* ARGSUSED */ +void + md_operand (expressionP) +expressionS *expressionP; +{ +} + +/* We have no need to default values of symbols. */ + +/* ARGSUSED */ +symbolS * + md_undefined_symbol (name) +char *name; +{ + return 0; +} + +/* Round up a section size to the appropriate boundary. */ +long + md_section_align (segment, size) +segT segment; +long size; +{ + return size; /* Byte alignment is fine */ +} + +/* Exactly what point is a PC-relative offset relative TO? + On the i860, they're relative to the address of the offset, plus + its size. (??? Is this right? FIXME-SOON!) */ +long + md_pcrel_from (fixP) +fixS *fixP; +{ + return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; +} + +void + md_apply_fix(fixP, val) +fixS *fixP; +long val; +{ + char *place = fixP->fx_where + fixP->fx_frag->fr_literal; + + /* fixme-soon: looks to me like i860 never has bit fixes. Let's see. xoxorich. */ + know(fixP->fx_bit_fixP == NULL); + if (!fixP->fx_bit_fixP) { + + /* fixme-soon: also looks like fx_im_disp is always 0. Let's see. xoxorich. */ + know(fixP->fx_im_disp == 0); + switch (fixP->fx_im_disp) { + case 0: + fixP->fx_addnumber = val; + md_number_to_imm(place, val, fixP->fx_size, fixP); + break; + case 1: + md_number_to_disp(place, + fixP->fx_pcrel ? val + fixP->fx_pcrel_adjust : val, + fixP->fx_size); + break; + case 2: /* fix requested for .long .word etc */ + md_number_to_chars(place, val, fixP->fx_size); + break; + default: + as_fatal("Internal error in md_apply_fix() in file \"%s\"", __FILE__); + } /* OVE: maybe one ought to put _imm _disp _chars in one md-func */ + } else { + md_number_to_field(place, val, fixP->fx_bit_fixP); + } + + return; +} /* md_apply_fix() */ + +/* + * Local Variables: + * fill-column: 131 + * comment-column: 0 + * End: + */ + +/* end of tc-i860.c */ diff --git a/gnu/usr.bin/as/config/tc-i860.h b/gnu/usr.bin/as/config/tc-i860.h new file mode 100644 index 000000000000..adc0d8f89e7b --- /dev/null +++ b/gnu/usr.bin/as/config/tc-i860.h @@ -0,0 +1,24 @@ +/* + * This file is tc-i860.h. + */ + +#define TC_I860 1 + +#define NO_LISTING + +#ifdef OLD_GAS +#define REVERSE_SORT_RELOCS +#endif /* OLD_GAS */ + +#define tc_headers_hook(a) {;} /* not used */ +#define tc_crawl_symbol_chain(a) {;} /* not used */ +#define tc_aout_pre_write_hook(x) {;} /* not used */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of tc-i860.h */ diff --git a/gnu/usr.bin/as/config/tc-i960.c b/gnu/usr.bin/as/config/tc-i960.c new file mode 100644 index 000000000000..8f9091ce5f06 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-i960.c @@ -0,0 +1,2759 @@ +/* tc-i960.c - All the i80960-specific stuff + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* See comment on md_parse_option for 80960-specific invocation options. */ + +/****************************************************************************** + * i80690 NOTE!!!: + * Header, symbol, and relocation info will be used on the host machine + * only -- only executable code is actually downloaded to the i80960. + * Therefore, leave all such information in host byte order. + * + * (That's a slight lie -- we DO download some header information, but + * the downloader converts the file format and corrects the byte-ordering + * of the relevant fields while doing so.) + * + ***************************************************************************** */ + +/* There are 4 different lengths of (potentially) symbol-based displacements + * in the 80960 instruction set, each of which could require address fix-ups + * and (in the case of external symbols) emission of relocation directives: + * + * 32-bit (MEMB) + * This is a standard length for the base assembler and requires no + * special action. + * + * 13-bit (COBR) + * This is a non-standard length, but the base assembler has a hook for + * bit field address fixups: the fixS structure can point to a descriptor + * of the field, in which case our md_number_to_field() routine gets called + * to process it. + * + * I made the hook a little cleaner by having fix_new() (in the base + * assembler) return a pointer to the fixS in question. And I made it a + * little simpler by storing the field size (in this case 13) instead of + * of a pointer to another structure: 80960 displacements are ALWAYS + * stored in the low-order bits of a 4-byte word. + * + * Since the target of a COBR cannot be external, no relocation directives + * for this size displacement have to be generated. But the base assembler + * had to be modified to issue error messages if the symbol did turn out + * to be external. + * + * 24-bit (CTRL) + * Fixups are handled as for the 13-bit case (except that 24 is stored + * in the fixS). + * + * The relocation directive generated is the same as that for the 32-bit + * displacement, except that it's PC-relative (the 32-bit displacement + * never is). The i80960 version of the linker needs a mod to + * distinguish and handle the 24-bit case. + * + * 12-bit (MEMA) + * MEMA formats are always promoted to MEMB (32-bit) if the displacement + * is based on a symbol, because it could be relocated at link time. + * The only time we use the 12-bit format is if an absolute value of + * less than 4096 is specified, in which case we need neither a fixup nor + * a relocation directive. + */ + +#include <stdio.h> +#include <ctype.h> + +#include "as.h" + +#include "obstack.h" + +#include "opcode/i960.h" + +extern char *input_line_pointer; +extern struct hash_control *po_hash; +extern char *next_object_file_charP; + +#ifdef OBJ_COFF +int md_reloc_size = sizeof(struct reloc); +#else /* OBJ_COFF */ +int md_reloc_size = sizeof(struct relocation_info); +#endif /* OBJ_COFF */ + +/*************************** + * Local i80960 routines * + ************************** */ + +static void brcnt_emit(); /* Emit branch-prediction instrumentation code */ +static char * brlab_next(); /* Return next branch local label */ +void brtab_emit(); /* Emit br-predict instrumentation table */ +static void cobr_fmt(); /* Generate COBR instruction */ +static void ctrl_fmt(); /* Generate CTRL instruction */ +static char * emit(); /* Emit (internally) binary */ +static int get_args(); /* Break arguments out of comma-separated list */ +static void get_cdisp(); /* Handle COBR or CTRL displacement */ +static char * get_ispec(); /* Find index specification string */ +static int get_regnum(); /* Translate text to register number */ +static int i_scan(); /* Lexical scan of instruction source */ +static void mem_fmt(); /* Generate MEMA or MEMB instruction */ +static void mema_to_memb(); /* Convert MEMA instruction to MEMB format */ +static segT parse_expr(); /* Parse an expression */ +static int parse_ldconst();/* Parse and replace a 'ldconst' pseudo-op */ +static void parse_memop(); /* Parse a memory operand */ +static void parse_po(); /* Parse machine-dependent pseudo-op */ +static void parse_regop(); /* Parse a register operand */ +static void reg_fmt(); /* Generate a REG format instruction */ +void reloc_callj(); /* Relocate a 'callj' instruction */ +static void relax_cobr(); /* "De-optimize" cobr into compare/branch */ +static void s_leafproc(); /* Process '.leafproc' pseudo-op */ +static void s_sysproc(); /* Process '.sysproc' pseudo-op */ +static int shift_ok(); /* Will a 'shlo' substiture for a 'ldconst'? */ +static void syntax(); /* Give syntax error */ +static int targ_has_sfr(); /* Target chip supports spec-func register? */ +static int targ_has_iclass();/* Target chip supports instruction set? */ +/* static void unlink_sym(); */ /* Remove a symbol from the symbol list */ + +/* See md_parse_option() for meanings of these options */ +static char norelax = 0; /* True if -norelax switch seen */ +static char instrument_branches = 0; /* True if -b switch seen */ + +/* Characters that always start a comment. + * If the pre-processor is disabled, these aren't very useful. + */ +char comment_chars[] = "#"; + +/* Characters that only start a comment at the beginning of + * a line. If the line seems to have the form '# 123 filename' + * .line and .file directives will appear in the pre-processed output. + * + * Note that input_file.c hand checks for '#' at the beginning of the + * first line of the input file. This is because the compiler outputs + * #NO_APP at the beginning of its output. + */ + +/* Also note that comments started like this one will always work. */ + +char line_comment_chars[] = ""; + +/* Chars that can be used to separate mant from exp in floating point nums */ +char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant, + * as in 0f12.456 or 0d1.2345e12 + */ +char FLT_CHARS[] = "fFdDtT"; + + +/* Table used by base assembler to relax addresses based on varying length + * instructions. The fields are: + * 1) most positive reach of this state, + * 2) most negative reach of this state, + * 3) how many bytes this mode will add to the size of the current frag + * 4) which index into the table to try if we can't fit into this one. + * + * For i80960, the only application is the (de-)optimization of cobr + * instructions into separate compare and branch instructions when a 13-bit + * displacement won't hack it. + */ +const relax_typeS + md_relax_table[] = { + {0, 0, 0,0}, /* State 0 => no more relaxation possible */ + {4088, -4096, 0,2}, /* State 1: conditional branch (cobr) */ + {0x800000-8,-0x800000,4,0}, /* State 2: compare (reg) & branch (ctrl) */ + }; + + +/* These are the machine dependent pseudo-ops. + * + * This table describes all the machine specific pseudo-ops the assembler + * has to support. The fields are: + * pseudo-op name without dot + * function to call to execute this pseudo-op + * integer arg to pass to the function + */ +#define S_LEAFPROC 1 +#define S_SYSPROC 2 + +const pseudo_typeS + md_pseudo_table[] = { + + { "bss", s_lcomm, 1 }, + { "extended", float_cons, 't' }, + { "leafproc", parse_po, S_LEAFPROC }, + { "sysproc", parse_po, S_SYSPROC }, + + { "word", cons, 4 }, + { "quad", big_cons, 16 }, + + { 0, 0, 0 } + }; + +/* Macros to extract info from an 'expressionS' structure 'e' */ +#define adds(e) e.X_add_symbol +#define subs(e) e.X_subtract_symbol +#define offs(e) e.X_add_number +#define segs(e) e.X_seg + + + /* Branch-prediction bits for CTRL/COBR format opcodes */ +#define BP_MASK 0x00000002 /* Mask for branch-prediction bit */ +#define BP_TAKEN 0x00000000 /* Value to OR in to predict branch */ +#define BP_NOT_TAKEN 0x00000002 /* Value to OR in to predict no branch */ + + + /* Some instruction opcodes that we need explicitly */ +#define BE 0x12000000 +#define BG 0x11000000 +#define BGE 0x13000000 +#define BL 0x14000000 +#define BLE 0x16000000 +#define BNE 0x15000000 +#define BNO 0x10000000 +#define BO 0x17000000 +#define CHKBIT 0x5a002700 +#define CMPI 0x5a002080 +#define CMPO 0x5a002000 + +#define B 0x08000000 +#define BAL 0x0b000000 +#define CALL 0x09000000 +#define CALLS 0x66003800 +#define RET 0x0a000000 + + + /* These masks are used to build up a set of MEMB mode bits. */ +#define A_BIT 0x0400 +#define I_BIT 0x0800 +#define MEMB_BIT 0x1000 +#define D_BIT 0x2000 + + + /* Mask for the only mode bit in a MEMA instruction (if set, abase reg is used) */ +#define MEMA_ABASE 0x2000 + + /* Info from which a MEMA or MEMB format instruction can be generated */ + typedef struct { + long opcode; /* (First) 32 bits of instruction */ + int disp; /* 0-(none), 12- or, 32-bit displacement needed */ + char *e; /* The expression in the source instruction from + * which the displacement should be determined + */ + } memS; + + +/* The two pieces of info we need to generate a register operand */ +struct regop { + int mode; /* 0 =>local/global/spec reg; 1=> literal or fp reg */ + int special; /* 0 =>not a sfr; 1=> is a sfr (not valid w/mode=0) */ + int n; /* Register number or literal value */ +}; + + +/* Number and assembler mnemonic for all registers that can appear in operands */ +static struct { + char *reg_name; + int reg_num; +} regnames[] = { + { "pfp", 0 }, { "sp", 1 }, { "rip", 2 }, { "r3", 3 }, + { "r4", 4 }, { "r5", 5 }, { "r6", 6 }, { "r7", 7 }, + { "r8", 8 }, { "r9", 9 }, { "r10", 10 }, { "r11", 11 }, + { "r12", 12 }, { "r13", 13 }, { "r14", 14 }, { "r15", 15 }, + { "g0", 16 }, { "g1", 17 }, { "g2", 18 }, { "g3", 19 }, + { "g4", 20 }, { "g5", 21 }, { "g6", 22 }, { "g7", 23 }, + { "g8", 24 }, { "g9", 25 }, { "g10", 26 }, { "g11", 27 }, + { "g12", 28 }, { "g13", 29 }, { "g14", 30 }, { "fp", 31 }, + + /* Numbers for special-function registers are for assembler internal + * use only: they are scaled back to range [0-31] for binary output. + */ +# define SF0 32 + + { "sf0", 32 }, { "sf1", 33 }, { "sf2", 34 }, { "sf3", 35 }, + { "sf4", 36 }, { "sf5", 37 }, { "sf6", 38 }, { "sf7", 39 }, + { "sf8", 40 }, { "sf9", 41 }, { "sf10",42 }, { "sf11",43 }, + { "sf12",44 }, { "sf13",45 }, { "sf14",46 }, { "sf15",47 }, + { "sf16",48 }, { "sf17",49 }, { "sf18",50 }, { "sf19",51 }, + { "sf20",52 }, { "sf21",53 }, { "sf22",54 }, { "sf23",55 }, + { "sf24",56 }, { "sf25",57 }, { "sf26",58 }, { "sf27",59 }, + { "sf28",60 }, { "sf29",61 }, { "sf30",62 }, { "sf31",63 }, + + /* Numbers for floating point registers are for assembler internal use + * only: they are scaled back to [0-3] for binary output. + */ +# define FP0 64 + + { "fp0", 64 }, { "fp1", 65 }, { "fp2", 66 }, { "fp3", 67 }, + + { NULL, 0 }, /* END OF LIST */ +}; + +#define IS_RG_REG(n) ((0 <= (n)) && ((n) < SF0)) +#define IS_SF_REG(n) ((SF0 <= (n)) && ((n) < FP0)) +#define IS_FP_REG(n) ((n) >= FP0) + +/* Number and assembler mnemonic for all registers that can appear as 'abase' + * (indirect addressing) registers. + */ +static struct { + char *areg_name; + int areg_num; +} aregs[] = { + { "(pfp)", 0 }, { "(sp)", 1 }, { "(rip)", 2 }, { "(r3)", 3 }, + { "(r4)", 4 }, { "(r5)", 5 }, { "(r6)", 6 }, { "(r7)", 7 }, + { "(r8)", 8 }, { "(r9)", 9 }, { "(r10)", 10 }, { "(r11)", 11 }, + { "(r12)", 12 }, { "(r13)", 13 }, { "(r14)", 14 }, { "(r15)", 15 }, + { "(g0)", 16 }, { "(g1)", 17 }, { "(g2)", 18 }, { "(g3)", 19 }, + { "(g4)", 20 }, { "(g5)", 21 }, { "(g6)", 22 }, { "(g7)", 23 }, + { "(g8)", 24 }, { "(g9)", 25 }, { "(g10)", 26 }, { "(g11)", 27 }, + { "(g12)", 28 }, { "(g13)", 29 }, { "(g14)", 30 }, { "(fp)", 31 }, + +# define IPREL 32 + /* for assembler internal use only: this number never appears in binary + * output. + */ + { "(ip)", IPREL }, + + { NULL, 0 }, /* END OF LIST */ +}; + + +/* Hash tables */ +static struct hash_control *op_hash = NULL; /* Opcode mnemonics */ +static struct hash_control *reg_hash = NULL; /* Register name hash table */ +static struct hash_control *areg_hash = NULL; /* Abase register hash table */ + + +/* Architecture for which we are assembling */ +#define ARCH_ANY 0 /* Default: no architecture checking done */ +#define ARCH_KA 1 +#define ARCH_KB 2 +#define ARCH_MC 3 +#define ARCH_CA 4 +int architecture = ARCH_ANY; /* Architecture requested on invocation line */ +int iclasses_seen = 0; /* OR of instruction classes (I_* constants) + * for which we've actually assembled + * instructions. + */ + + +/* BRANCH-PREDICTION INSTRUMENTATION + * + * The following supports generation of branch-prediction instrumentation + * (turned on by -b switch). The instrumentation collects counts + * of branches taken/not-taken for later input to a utility that will + * set the branch prediction bits of the instructions in accordance with + * the behavior observed. (Note that the KX series does not have + * brach-prediction.) + * + * The instrumentation consists of: + * + * (1) before and after each conditional branch, a call to an external + * routine that increments and steps over an inline counter. The + * counter itself, initialized to 0, immediately follows the call + * instruction. For each branch, the counter following the branch + * is the number of times the branch was not taken, and the difference + * between the counters is the number of times it was taken. An + * example of an instrumented conditional branch: + * + * call BR_CNT_FUNC + * .word 0 + * LBRANCH23: be label + * call BR_CNT_FUNC + * .word 0 + * + * (2) a table of pointers to the instrumented branches, so that an + * external postprocessing routine can locate all of the counters. + * the table begins with a 2-word header: a pointer to the next in + * a linked list of such tables (initialized to 0); and a count + * of the number of entries in the table (exclusive of the header. + * + * Note that input source code is expected to already contain calls + * an external routine that will link the branch local table into a + * list of such tables. + */ + +static int br_cnt = 0; /* Number of branches instrumented so far. + * Also used to generate unique local labels + * for each instrumented branch + */ + +#define BR_LABEL_BASE "LBRANCH" +/* Basename of local labels on instrumented + * branches, to avoid conflict with compiler- + * generated local labels. + */ + +#define BR_CNT_FUNC "__inc_branch" +/* Name of the external routine that will + * increment (and step over) an inline counter. + */ + +#define BR_TAB_NAME "__BRANCH_TABLE__" +/* Name of the table of pointers to branches. + * A local (i.e., non-external) symbol. + */ + +/***************************************************************************** + * md_begin: One-time initialization. + * + * Set up hash tables. + * + **************************************************************************** */ +void + md_begin() +{ + int i; /* Loop counter */ + const struct i960_opcode *oP; /* Pointer into opcode table */ + char *retval; /* Value returned by hash functions */ + + if (((op_hash = hash_new()) == 0) + || ((reg_hash = hash_new()) == 0) + || ((areg_hash = hash_new()) == 0)) { + as_fatal("virtual memory exceeded"); + } + + retval = ""; /* For some reason, the base assembler uses an empty + * string for "no error message", instead of a NULL + * pointer. + */ + + for (oP=i960_opcodes; oP->name && !*retval; oP++) { + retval = hash_insert(op_hash, oP->name, oP); + } + + for (i=0; regnames[i].reg_name && !*retval; i++) { + retval = hash_insert(reg_hash, regnames[i].reg_name, + ®names[i].reg_num); + } + + for (i=0; aregs[i].areg_name && !*retval; i++){ + retval = hash_insert(areg_hash, aregs[i].areg_name, + &aregs[i].areg_num); + } + + if (*retval) { + as_fatal("Hashing returned \"%s\".", retval); + } +} /* md_begin() */ + +/***************************************************************************** + * md_end: One-time final cleanup + * + * None necessary + * + **************************************************************************** */ +void + md_end() +{ +} + +/***************************************************************************** + * md_assemble: Assemble an instruction + * + * Assumptions about the passed-in text: + * - all comments, labels removed + * - text is an instruction + * - all white space compressed to single blanks + * - all character constants have been replaced with decimal + * + **************************************************************************** */ +void + md_assemble(textP) +char *textP; /* Source text of instruction */ +{ + char *args[4]; /* Parsed instruction text, containing NO whitespace: + * arg[0]->opcode mnemonic + * arg[1-3]->operands, with char constants + * replaced by decimal numbers + */ + int n_ops; /* Number of instruction operands */ + + struct i960_opcode *oP; + /* Pointer to instruction description */ + int branch_predict; + /* TRUE iff opcode mnemonic included branch-prediction + * suffix (".f" or ".t") + */ + long bp_bits; /* Setting of branch-prediction bit(s) to be OR'd + * into instruction opcode of CTRL/COBR format + * instructions. + */ + int n; /* Offset of last character in opcode mnemonic */ + + static const char bp_error_msg[] = "branch prediction invalid on this opcode"; + + + /* Parse instruction into opcode and operands */ + memset(args, '\0', sizeof(args)); + n_ops = i_scan(textP, args); + if (n_ops == -1){ + return; /* Error message already issued */ + } + + /* Do "macro substitution" (sort of) on 'ldconst' pseudo-instruction */ + if (!strcmp(args[0],"ldconst")){ + n_ops = parse_ldconst(args); + if (n_ops == -1){ + return; + } + } + + /* Check for branch-prediction suffix on opcode mnemonic, strip it off */ + n = strlen(args[0]) - 1; + branch_predict = 0; + bp_bits = 0; + if (args[0][n-1] == '.' && (args[0][n] == 't' || args[0][n] == 'f')){ + /* We could check here to see if the target architecture + * supports branch prediction, but why bother? The bit + * will just be ignored by processors that don't use it. + */ + branch_predict = 1; + bp_bits = (args[0][n] == 't') ? BP_TAKEN : BP_NOT_TAKEN; + args[0][n-1] = '\0'; /* Strip suffix from opcode mnemonic */ + } + + /* Look up opcode mnemonic in table and check number of operands. + * Check that opcode is legal for the target architecture. + * If all looks good, assemble instruction. + */ + oP = (struct i960_opcode *) hash_find(op_hash, args[0]); + if (!oP || !targ_has_iclass(oP->iclass)) { + as_bad("invalid opcode, \"%s\".", args[0]); + + } else if (n_ops != oP->num_ops) { + as_bad("improper number of operands. expecting %d, got %d", oP->num_ops, n_ops); + + } else { + switch (oP->format){ + case FBRA: + case CTRL: + ctrl_fmt(args[1], oP->opcode | bp_bits, oP->num_ops); + if (oP->format == FBRA){ + /* Now generate a 'bno' to same arg */ + ctrl_fmt(args[1], BNO | bp_bits, 1); + } + break; + case COBR: + case COJ: + cobr_fmt(args, oP->opcode | bp_bits, oP); + break; + case REG: + if (branch_predict){ + as_warn(bp_error_msg); + } + reg_fmt(args, oP); + break; + case MEM1: + case MEM2: + case MEM4: + case MEM8: + case MEM12: + case MEM16: + if (branch_predict){ + as_warn(bp_error_msg); + } + mem_fmt(args, oP); + break; + case CALLJ: + if (branch_predict){ + as_warn(bp_error_msg); + } + /* Output opcode & set up "fixup" (relocation); + * flag relocation as 'callj' type. + */ + know(oP->num_ops == 1); + get_cdisp(args[1], "CTRL", oP->opcode, 24, 0, 1); + break; + default: + BAD_CASE(oP->format); + break; + } + } +} /* md_assemble() */ + +/***************************************************************************** + * md_number_to_chars: convert a number to target byte order + * + **************************************************************************** */ +void + md_number_to_chars(buf, value, n) +char *buf; /* Put output here */ +long value; /* The integer to be converted */ +int n; /* Number of bytes to output (significant bytes + * in 'value') + */ +{ + while (n--){ + *buf++ = value; + value >>= 8; + } + + /* XXX line number probably botched for this warning message. */ + if (value != 0 && value != -1){ + as_bad("Displacement too long for instruction field length."); + } + + return; +} /* md_number_to_chars() */ + +/***************************************************************************** + * md_chars_to_number: convert from target byte order to host byte order. + * + **************************************************************************** */ +int + md_chars_to_number(val, n) +unsigned char *val; /* Value in target byte order */ +int n; /* Number of bytes in the input */ +{ + int retval; + + for (retval=0; n--;){ + retval <<= 8; + retval |= val[n]; + } + return retval; +} + + +#define MAX_LITTLENUMS 6 +#define LNUM_SIZE sizeof(LITTLENUM_TYPE) + +/***************************************************************************** + * md_atof: convert ascii to floating point + * + * Turn a string at input_line_pointer into a floating point constant of type + * 'type', and store the appropriate bytes at *litP. The number of LITTLENUMS + * emitted is returned at 'sizeP'. An error message is returned, or a pointer + * to an empty message if OK. + * + * Note we call the i386 floating point routine, rather than complicating + * things with more files or symbolic links. + * + **************************************************************************** */ +char * md_atof(type, litP, sizeP) +int type; +char *litP; +int *sizeP; +{ + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + int prec; + char *t; + char *atof_ieee(); + + switch (type) { + case 'f': + case 'F': + prec = 2; + break; + + case 'd': + case 'D': + prec = 4; + break; + + case 't': + case 'T': + prec = 5; + type = 'x'; /* That's what atof_ieee() understands */ + break; + + default: + *sizeP=0; + return "Bad call to md_atof()"; + } + + t = atof_ieee(input_line_pointer, type, words); + if (t){ + input_line_pointer = t; + } + + *sizeP = prec * LNUM_SIZE; + + /* Output the LITTLENUMs in REVERSE order in accord with i80960 + * word-order. (Dunno why atof_ieee doesn't do it in the right + * order in the first place -- probably because it's a hack of + * atof_m68k.) + */ + + for (wordP = words + prec - 1; prec--;){ + md_number_to_chars(litP, (long) (*wordP--), LNUM_SIZE); + litP += sizeof(LITTLENUM_TYPE); + } + + return ""; /* Someone should teach Dean about null pointers */ +} + + +/***************************************************************************** + * md_number_to_imm + * + **************************************************************************** */ +void + md_number_to_imm(buf, val, n) +char *buf; +long val; +int n; +{ + md_number_to_chars(buf, val, n); +} + + +/***************************************************************************** + * md_number_to_disp + * + **************************************************************************** */ +void + md_number_to_disp(buf, val, n) +char *buf; +long val; +int n; +{ + md_number_to_chars(buf, val, n); +} + +/***************************************************************************** + * md_number_to_field: + * + * Stick a value (an address fixup) into a bit field of + * previously-generated instruction. + * + **************************************************************************** */ +void + md_number_to_field(instrP, val, bfixP) +char *instrP; /* Pointer to instruction to be fixed */ +long val; /* Address fixup value */ +bit_fixS *bfixP; /* Description of bit field to be fixed up */ +{ + int numbits; /* Length of bit field to be fixed */ + long instr; /* 32-bit instruction to be fixed-up */ + long sign; /* 0 or -1, according to sign bit of 'val' */ + + /* Convert instruction back to host byte order + */ + instr = md_chars_to_number(instrP, 4); + + /* Surprise! -- we stored the number of bits + * to be modified rather than a pointer to a structure. + */ + numbits = (int)bfixP; + if (numbits == 1){ + /* This is a no-op, stuck here by reloc_callj() */ + return; + } + + know ((numbits == 13) || (numbits == 24)); + + /* Propagate sign bit of 'val' for the given number of bits. + * Result should be all 0 or all 1 + */ + sign = val >> ((int)numbits - 1); + if (((val < 0) && (sign != -1)) + || ((val > 0) && (sign != 0))){ + as_bad("Fixup of %d too large for field width of %d", + val, numbits); + } else { + /* Put bit field into instruction and write back in target + * byte order. + */ + val &= ~(-1 << (int)numbits); /* Clear unused sign bits */ + instr |= val; + md_number_to_chars(instrP, instr, 4); + } +} /* md_number_to_field() */ + + +/***************************************************************************** + * md_parse_option + * Invocation line includes a switch not recognized by the base assembler. + * See if it's a processor-specific option. For the 960, these are: + * + * -norelax: + * Conditional branch instructions that require displacements + * greater than 13 bits (or that have external targets) should + * generate errors. The default is to replace each such + * instruction with the corresponding compare (or chkbit) and + * branch instructions. Note that the Intel "j" cobr directives + * are ALWAYS "de-optimized" in this way when necessary, + * regardless of the setting of this option. + * + * -b: + * Add code to collect information about branches taken, for + * later optimization of branch prediction bits by a separate + * tool. COBR and CNTL format instructions have branch + * prediction bits (in the CX architecture); if "BR" represents + * an instruction in one of these classes, the following rep- + * resents the code generated by the assembler: + * + * call <increment routine> + * .word 0 # pre-counter + * Label: BR + * call <increment routine> + * .word 0 # post-counter + * + * A table of all such "Labels" is also generated. + * + * + * -AKA, -AKB, -AKC, -ASA, -ASB, -AMC, -ACA: + * Select the 80960 architecture. Instructions or features not + * supported by the selected architecture cause fatal errors. + * The default is to generate code for any instruction or feature + * that is supported by SOME version of the 960 (even if this + * means mixing architectures!). + * + **************************************************************************** */ +int + md_parse_option(argP, cntP, vecP) +char **argP; +int *cntP; +char ***vecP; +{ + char *p; + struct tabentry { char *flag; int arch; }; + static struct tabentry arch_tab[] = { + "KA", ARCH_KA, + "KB", ARCH_KB, + "SA", ARCH_KA, /* Synonym for KA */ + "SB", ARCH_KB, /* Synonym for KB */ + "KC", ARCH_MC, /* Synonym for MC */ + "MC", ARCH_MC, + "CA", ARCH_CA, + NULL, 0 + }; + struct tabentry *tp; + + if (!strcmp(*argP,"norelax")){ + norelax = 1; + + } else if (**argP == 'b'){ + instrument_branches = 1; + + } else if (**argP == 'A'){ + p = (*argP) + 1; + + for (tp = arch_tab; tp->flag != NULL; tp++){ + if (!strcmp(p,tp->flag)){ + break; + } + } + + if (tp->flag == NULL){ + as_bad("unknown architecture: %s", p); + } else { + architecture = tp->arch; + } + } else { + /* Unknown option */ + (*argP)++; + return 0; + } + **argP = '\0'; /* Done parsing this switch */ + return 1; +} + +/***************************************************************************** + * md_convert_frag: + * Called by base assembler after address relaxation is finished: modify + * variable fragments according to how much relaxation was done. + * + * If the fragment substate is still 1, a 13-bit displacement was enough + * to reach the symbol in question. Set up an address fixup, but otherwise + * leave the cobr instruction alone. + * + * If the fragment substate is 2, a 13-bit displacement was not enough. + * Replace the cobr with a two instructions (a compare and a branch). + * + **************************************************************************** */ +void + md_convert_frag(headers, fragP) +object_headers *headers; +fragS * fragP; +{ + fixS *fixP; /* Structure describing needed address fix */ + + switch (fragP->fr_subtype){ + case 1: + /* LEAVE SINGLE COBR INSTRUCTION */ + fixP = fix_new(fragP, + fragP->fr_opcode-fragP->fr_literal, + 4, + fragP->fr_symbol, + 0, + fragP->fr_offset, + 1, + 0); + + fixP->fx_bit_fixP = (bit_fixS *) 13; /* size of bit field */ + break; + case 2: + /* REPLACE COBR WITH COMPARE/BRANCH INSTRUCTIONS */ + relax_cobr(fragP); + break; + default: + BAD_CASE(fragP->fr_subtype); + break; + } +} + +/***************************************************************************** + * md_estimate_size_before_relax: How much does it look like *fragP will grow? + * + * Called by base assembler just before address relaxation. + * Return the amount by which the fragment will grow. + * + * Any symbol that is now undefined will not become defined; cobr's + * based on undefined symbols will have to be replaced with a compare + * instruction and a branch instruction, and the code fragment will grow + * by 4 bytes. + * + **************************************************************************** */ +int + md_estimate_size_before_relax(fragP, segment_type) +register fragS *fragP; +register segT segment_type; +{ + /* If symbol is undefined in this segment, go to "relaxed" state + * (compare and branch instructions instead of cobr) right now. + */ + if (S_GET_SEGMENT(fragP->fr_symbol) != segment_type) { + relax_cobr(fragP); + return 4; + } + return 0; +} /* md_estimate_size_before_relax() */ + + +/***************************************************************************** + * md_ri_to_chars: + * This routine exists in order to overcome machine byte-order problems + * when dealing with bit-field entries in the relocation_info struct. + * + * But relocation info will be used on the host machine only (only + * executable code is actually downloaded to the i80960). Therefore, + * we leave it in host byte order. + * + **************************************************************************** */ +void md_ri_to_chars(where, ri) +char *where; +struct relocation_info *ri; +{ + *((struct relocation_info *) where) = *ri; /* structure assignment */ +} /* md_ri_to_chars() */ + +#ifndef WORKING_DOT_WORD + +int md_short_jump_size = 0; +int md_long_jump_size = 0; + +void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol) +char *ptr; +long from_addr; +long to_addr; +fragS *frag; +symbolS *to_symbol; +{ + as_fatal("failed sanity check."); +} + +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; +{ + as_fatal("failed sanity check."); +} +#endif + +/************************************************************* + * * + * FOLLOWING ARE THE LOCAL ROUTINES, IN ALPHABETICAL ORDER * + * * + ************************************************************ */ + + + +/***************************************************************************** + * brcnt_emit: Emit code to increment inline branch counter. + * + * See the comments above the declaration of 'br_cnt' for details on + * branch-prediction instrumentation. + **************************************************************************** */ +static void + brcnt_emit() +{ + ctrl_fmt(BR_CNT_FUNC,CALL,1);/* Emit call to "increment" routine */ + emit(0); /* Emit inline counter to be incremented */ +} + +/***************************************************************************** + * brlab_next: generate the next branch local label + * + * See the comments above the declaration of 'br_cnt' for details on + * branch-prediction instrumentation. + **************************************************************************** */ +static char * + brlab_next() +{ + static char buf[20]; + + sprintf(buf, "%s%d", BR_LABEL_BASE, br_cnt++); + return buf; +} + +/***************************************************************************** + * brtab_emit: generate the fetch-prediction branch table. + * + * See the comments above the declaration of 'br_cnt' for details on + * branch-prediction instrumentation. + * + * The code emitted here would be functionally equivalent to the following + * example assembler source. + * + * .data + * .align 2 + * BR_TAB_NAME: + * .word 0 # link to next table + * .word 3 # length of table + * .word LBRANCH0 # 1st entry in table proper + * .word LBRANCH1 + * .word LBRANCH2 + ***************************************************************************** */ +void + brtab_emit() +{ + int i; + char buf[20]; + char *p; /* Where the binary was output to */ + fixS *fixP; /*->description of deferred address fixup */ + + if (!instrument_branches){ + return; + } + + subseg_new(SEG_DATA,0); /* .data */ + frag_align(2,0); /* .align 2 */ + record_alignment(now_seg,2); + colon(BR_TAB_NAME); /* BR_TAB_NAME: */ + emit(0); /* .word 0 #link to next table */ + emit(br_cnt); /* .word n #length of table */ + + for (i=0; i<br_cnt; i++){ + sprintf(buf, "%s%d", BR_LABEL_BASE, i); + p = emit(0); + fixP = fix_new(frag_now, + p - frag_now->fr_literal, + 4, + symbol_find(buf), + 0, + 0, + 0, + 0); + fixP->fx_im_disp = 2; /* 32-bit displacement fix */ + } +} + +/***************************************************************************** + * cobr_fmt: generate a COBR-format instruction + * + **************************************************************************** */ +static + void + cobr_fmt(arg, opcode, oP) +char *arg[]; /* arg[0]->opcode mnemonic, arg[1-3]->operands (ascii) */ +long opcode; /* Opcode, with branch-prediction bits already set + * if necessary. + */ +struct i960_opcode *oP; +/*->description of instruction */ +{ + long instr; /* 32-bit instruction */ + struct regop regop; /* Description of register operand */ + int n; /* Number of operands */ + int var_frag; /* 1 if varying length code fragment should + * be emitted; 0 if an address fix + * should be emitted. + */ + + instr = opcode; + n = oP->num_ops; + + if (n >= 1) { + /* First operand (if any) of a COBR is always a register + * operand. Parse it. + */ + parse_regop(®op, arg[1], oP->operand[0]); + instr |= (regop.n << 19) | (regop.mode << 13); + } + if (n >= 2) { + /* Second operand (if any) of a COBR is always a register + * operand. Parse it. + */ + parse_regop(®op, arg[2], oP->operand[1]); + instr |= (regop.n << 14) | regop.special; + } + + + if (n < 3){ + emit(instr); + + } else { + if (instrument_branches){ + brcnt_emit(); + colon(brlab_next()); + } + + /* A third operand to a COBR is always a displacement. + * Parse it; if it's relaxable (a cobr "j" directive, or any + * cobr other than bbs/bbc when the "-norelax" option is not in + * use) set up a variable code fragment; otherwise set up an + * address fix. + */ + var_frag = !norelax || (oP->format == COJ); /* TRUE or FALSE */ + get_cdisp(arg[3], "COBR", instr, 13, var_frag, 0); + + if (instrument_branches){ + brcnt_emit(); + } + } +} /* cobr_fmt() */ + + +/***************************************************************************** + * ctrl_fmt: generate a CTRL-format instruction + * + **************************************************************************** */ +static + void + ctrl_fmt(targP, opcode, num_ops) +char *targP; /* Pointer to text of lone operand (if any) */ +long opcode; /* Template of instruction */ +int num_ops; /* Number of operands */ +{ + int instrument; /* TRUE iff we should add instrumentation to track + * how often the branch is taken + */ + + + if (num_ops == 0){ + emit(opcode); /* Output opcode */ + } else { + + instrument = instrument_branches && (opcode != CALL) + && (opcode != B) && (opcode != RET) && (opcode != BAL); + + if (instrument){ + brcnt_emit(); + colon(brlab_next()); + } + + /* The operand MUST be an ip-relative displacment. Parse it + * and set up address fix for the instruction we just output. + */ + get_cdisp(targP, "CTRL", opcode, 24, 0, 0); + + if (instrument){ + brcnt_emit(); + } + } + +} + + +/***************************************************************************** + * emit: output instruction binary + * + * Output instruction binary, in target byte order, 4 bytes at a time. + * Return pointer to where it was placed. + * + **************************************************************************** */ +static + char * + emit(instr) +long instr; /* Word to be output, host byte order */ +{ + char *toP; /* Where to output it */ + + toP = frag_more(4); /* Allocate storage */ + md_number_to_chars(toP, instr, 4); /* Convert to target byte order */ + return toP; +} + + +/***************************************************************************** + * get_args: break individual arguments out of comma-separated list + * + * Input assumptions: + * - all comments and labels have been removed + * - all strings of whitespace have been collapsed to a single blank. + * - all character constants ('x') have been replaced with decimal + * + * Output: + * args[0] is untouched. args[1] points to first operand, etc. All args: + * - are NULL-terminated + * - contain no whitespace + * + * Return value: + * Number of operands (0,1,2, or 3) or -1 on error. + * + **************************************************************************** */ +static int get_args(p, args) +register char *p; /* Pointer to comma-separated operands; MUCKED BY US */ +char *args[]; /* Output arg: pointers to operands placed in args[1-3]. + * MUST ACCOMMODATE 4 ENTRIES (args[0-3]). + */ +{ + register int n; /* Number of operands */ + register char *to; + /* char buf[4]; */ + /* int len; */ + + + /* Skip lead white space */ + while (*p == ' '){ + p++; + } + + if (*p == '\0'){ + return 0; + } + + n = 1; + args[1] = p; + + /* Squeze blanks out by moving non-blanks toward start of string. + * Isolate operands, whenever comma is found. + */ + to = p; + while (*p != '\0'){ + + if (*p == ' '){ + p++; + + } else if (*p == ','){ + + /* Start of operand */ + if (n == 3){ + as_bad("too many operands"); + return -1; + } + *to++ = '\0'; /* Terminate argument */ + args[++n] = to; /* Start next argument */ + p++; + + } else { + *to++ = *p++; + } + } + *to = '\0'; + return n; +} + + +/***************************************************************************** + * get_cdisp: handle displacement for a COBR or CTRL instruction. + * + * Parse displacement for a COBR or CTRL instruction. + * + * If successful, output the instruction opcode and set up for it, + * depending on the arg 'var_frag', either: + * o an address fixup to be done when all symbol values are known, or + * o a varying length code fragment, with address fixup info. This + * will be done for cobr instructions that may have to be relaxed + * in to compare/branch instructions (8 bytes) if the final address + * displacement is greater than 13 bits. + * + **************************************************************************** */ +static + void + get_cdisp(dispP, ifmtP, instr, numbits, var_frag, callj) +char *dispP; /*->displacement as specified in source instruction */ +char *ifmtP; /*->"COBR" or "CTRL" (for use in error message) */ +long instr; /* Instruction needing the displacement */ +int numbits; /* # bits of displacement (13 for COBR, 24 for CTRL) */ +int var_frag; /* 1 if varying length code fragment should be emitted; + * 0 if an address fix should be emitted. + */ +int callj; /* 1 if callj relocation should be done; else 0 */ +{ + expressionS e; /* Parsed expression */ + fixS *fixP; /* Structure describing needed address fix */ + char *outP; /* Where instruction binary is output to */ + + fixP = NULL; + + switch (parse_expr(dispP,&e)) { + + case SEG_GOOF: + as_bad("expression syntax error"); + break; + + case SEG_TEXT: + case SEG_UNKNOWN: + if (var_frag) { + outP = frag_more(8); /* Allocate worst-case storage */ + md_number_to_chars(outP, instr, 4); + frag_variant(rs_machine_dependent, 4, 4, 1, + adds(e), offs(e), outP, 0, 0); + } else { + /* Set up a new fix structure, so address can be updated + * when all symbol values are known. + */ + outP = emit(instr); + fixP = fix_new(frag_now, + outP - frag_now->fr_literal, + 4, + adds(e), + 0, + offs(e), + 1, + 0); + + fixP->fx_callj = callj; + + /* We want to modify a bit field when the address is + * known. But we don't need all the garbage in the + * bit_fix structure. So we're going to lie and store + * the number of bits affected instead of a pointer. + */ + fixP->fx_bit_fixP = (bit_fixS *) numbits; + } + break; + + case SEG_DATA: + case SEG_BSS: + as_bad("attempt to branch into different segment"); + break; + + default: + as_bad("target of %s instruction must be a label", ifmtP); + break; + } +} + + +/***************************************************************************** + * get_ispec: parse a memory operand for an index specification + * + * Here, an "index specification" is taken to be anything surrounded + * by square brackets and NOT followed by anything else. + * + * If it's found, detach it from the input string, remove the surrounding + * square brackets, and return a pointer to it. Otherwise, return NULL. + * + **************************************************************************** */ +static + char * + get_ispec(textP) +char *textP; /*->memory operand from source instruction, no white space */ +{ + char *start; /*->start of index specification */ + char *end; /*->end of index specification */ + + /* Find opening square bracket, if any + */ + start = strchr(textP, '['); + + if (start != NULL){ + + /* Eliminate '[', detach from rest of operand */ + *start++ = '\0'; + + end = strchr(start, ']'); + + if (end == NULL){ + as_bad("unmatched '['"); + + } else { + /* Eliminate ']' and make sure it was the last thing + * in the string. + */ + *end = '\0'; + if (*(end+1) != '\0'){ + as_bad("garbage after index spec ignored"); + } + } + } + return start; +} + +/***************************************************************************** + * get_regnum: + * + * Look up a (suspected) register name in the register table and return the + * associated register number (or -1 if not found). + * + **************************************************************************** */ +static + int + get_regnum(regname) +char *regname; /* Suspected register name */ +{ + int *rP; + + rP = (int *) hash_find(reg_hash, regname); + return (rP == NULL) ? -1 : *rP; +} + + +/***************************************************************************** + * i_scan: perform lexical scan of ascii assembler instruction. + * + * Input assumptions: + * - input string is an i80960 instruction (not a pseudo-op) + * - all comments and labels have been removed + * - all strings of whitespace have been collapsed to a single blank. + * + * Output: + * args[0] points to opcode, other entries point to operands. All strings: + * - are NULL-terminated + * - contain no whitespace + * - have character constants ('x') replaced with a decimal number + * + * Return value: + * Number of operands (0,1,2, or 3) or -1 on error. + * + **************************************************************************** */ +static int i_scan(iP, args) +register char *iP; /* Pointer to ascii instruction; MUCKED BY US. */ +char *args[]; /* Output arg: pointers to opcode and operands placed + * here. MUST ACCOMMODATE 4 ENTRIES. + */ +{ + + /* Isolate opcode */ + if (*(iP) == ' ') { + iP++; + } /* Skip lead space, if any */ + args[0] = iP; + for (; *iP != ' '; iP++) { + if (*iP == '\0') { + /* There are no operands */ + if (args[0] == iP) { + /* We never moved: there was no opcode either! */ + as_bad("missing opcode"); + return -1; + } + return 0; + } + } + *iP++ = '\0'; /* Terminate opcode */ + return(get_args(iP, args)); +} /* i_scan() */ + + +/***************************************************************************** + * mem_fmt: generate a MEMA- or MEMB-format instruction + * + **************************************************************************** */ +static void mem_fmt(args, oP) +char *args[]; /* args[0]->opcode mnemonic, args[1-3]->operands */ +struct i960_opcode *oP; /* Pointer to description of instruction */ +{ + int i; /* Loop counter */ + struct regop regop; /* Description of register operand */ + char opdesc; /* Operand descriptor byte */ + memS instr; /* Description of binary to be output */ + char *outP; /* Where the binary was output to */ + expressionS expr; /* Parsed expression */ + fixS *fixP; /*->description of deferred address fixup */ + + memset(&instr, '\0', sizeof(memS)); + instr.opcode = oP->opcode; + + /* Process operands. */ + for (i = 1; i <= oP->num_ops; i++){ + opdesc = oP->operand[i-1]; + + if (MEMOP(opdesc)){ + parse_memop(&instr, args[i], oP->format); + } else { + parse_regop(®op, args[i], opdesc); + instr.opcode |= regop.n << 19; + } + } + + /* Output opcode */ + outP = emit(instr.opcode); + + if (instr.disp == 0){ + return; + } + + /* Parse and process the displacement */ + switch (parse_expr(instr.e,&expr)){ + + case SEG_GOOF: + as_bad("expression syntax error"); + break; + + case SEG_ABSOLUTE: + if (instr.disp == 32){ + (void) emit(offs(expr)); /* Output displacement */ + } else { + /* 12-bit displacement */ + if (offs(expr) & ~0xfff){ + /* Won't fit in 12 bits: convert already-output + * instruction to MEMB format, output + * displacement. + */ + mema_to_memb(outP); + (void) emit(offs(expr)); + } else { + /* WILL fit in 12 bits: OR into opcode and + * overwrite the binary we already put out + */ + instr.opcode |= offs(expr); + md_number_to_chars(outP, instr.opcode, 4); + } + } + break; + + case SEG_DIFFERENCE: + case SEG_TEXT: + case SEG_DATA: + case SEG_BSS: + case SEG_UNKNOWN: + if (instr.disp == 12){ + /* Displacement is dependent on a symbol, whose value + * may change at link time. We HAVE to reserve 32 bits. + * Convert already-output opcode to MEMB format. + */ + mema_to_memb(outP); + } + + /* Output 0 displacement and set up address fixup for when + * this symbol's value becomes known. + */ + outP = emit((long) 0); + fixP = fix_new(frag_now, + outP - frag_now->fr_literal, + 4, + adds(expr), + subs(expr), + offs(expr), + 0, + 0); + fixP->fx_im_disp = 2; /* 32-bit displacement fix */ + break; + + default: + BAD_CASE(segs(expr)); + break; + } +} /* memfmt() */ + + +/***************************************************************************** + * mema_to_memb: convert a MEMA-format opcode to a MEMB-format opcode. + * + * There are 2 possible MEMA formats: + * - displacement only + * - displacement + abase + * + * They are distinguished by the setting of the MEMA_ABASE bit. + * + **************************************************************************** */ +static void mema_to_memb(opcodeP) +char *opcodeP; /* Where to find the opcode, in target byte order */ +{ + long opcode; /* Opcode in host byte order */ + long mode; /* Mode bits for MEMB instruction */ + + opcode = md_chars_to_number(opcodeP, 4); + know(!(opcode & MEMB_BIT)); + + mode = MEMB_BIT | D_BIT; + if (opcode & MEMA_ABASE){ + mode |= A_BIT; + } + + opcode &= 0xffffc000; /* Clear MEMA offset and mode bits */ + opcode |= mode; /* Set MEMB mode bits */ + + md_number_to_chars(opcodeP, opcode, 4); +} /* mema_to_memb() */ + + +/***************************************************************************** + * parse_expr: parse an expression + * + * Use base assembler's expression parser to parse an expression. + * It, unfortunately, runs off a global which we have to save/restore + * in order to make it work for us. + * + * An empty expression string is treated as an absolute 0. + * + * Return "segment" to which the expression evaluates. + * Return SEG_GOOF regardless of expression evaluation if entire input + * string is not consumed in the evaluation -- tolerate no dangling junk! + * + **************************************************************************** */ +static + segT + parse_expr(textP, expP) +char *textP; /* Text of expression to be parsed */ +expressionS *expP; /* Where to put the results of parsing */ +{ + char *save_in; /* Save global here */ + segT seg; /* Segment to which expression evaluates */ + symbolS *symP; + + know(textP); + + if (*textP == '\0') { + /* Treat empty string as absolute 0 */ + expP->X_add_symbol = expP->X_subtract_symbol = NULL; + expP->X_add_number = 0; + seg = expP->X_seg = SEG_ABSOLUTE; + + } else { + save_in = input_line_pointer; /* Save global */ + input_line_pointer = textP; /* Make parser work for us */ + + seg = expression(expP); + if (input_line_pointer - textP != strlen(textP)) { + /* Did not consume all of the input */ + seg = SEG_GOOF; + } + symP = expP->X_add_symbol; + if (symP && (hash_find(reg_hash, S_GET_NAME(symP)))) { + /* Register name in an expression */ + seg = SEG_GOOF; + } + + input_line_pointer = save_in; /* Restore global */ + } + return seg; +} + + +/***************************************************************************** + * parse_ldcont: + * Parse and replace a 'ldconst' pseudo-instruction with an appropriate + * i80960 instruction. + * + * Assumes the input consists of: + * arg[0] opcode mnemonic ('ldconst') + * arg[1] first operand (constant) + * arg[2] name of register to be loaded + * + * Replaces opcode and/or operands as appropriate. + * + * Returns the new number of arguments, or -1 on failure. + * + **************************************************************************** */ +static + int + parse_ldconst(arg) +char *arg[]; /* See above */ +{ + int n; /* Constant to be loaded */ + int shift; /* Shift count for "shlo" instruction */ + static char buf[5]; /* Literal for first operand */ + static char buf2[5]; /* Literal for second operand */ + expressionS e; /* Parsed expression */ + + + arg[3] = NULL; /* So we can tell at the end if it got used or not */ + + switch (parse_expr(arg[1],&e)){ + + case SEG_TEXT: + case SEG_DATA: + case SEG_BSS: + case SEG_UNKNOWN: + case SEG_DIFFERENCE: + /* We're dependent on one or more symbols -- use "lda" */ + arg[0] = "lda"; + break; + + case SEG_ABSOLUTE: + /* Try the following mappings: + * ldconst 0,<reg> ->mov 0,<reg> + * ldconst 31,<reg> ->mov 31,<reg> + * ldconst 32,<reg> ->addo 1,31,<reg> + * ldconst 62,<reg> ->addo 31,31,<reg> + * ldconst 64,<reg> ->shlo 8,3,<reg> + * ldconst -1,<reg> ->subo 1,0,<reg> + * ldconst -31,<reg>->subo 31,0,<reg> + * + * anthing else becomes: + * lda xxx,<reg> + */ + n = offs(e); + if ((0 <= n) && (n <= 31)){ + arg[0] = "mov"; + + } else if ((-31 <= n) && (n <= -1)){ + arg[0] = "subo"; + arg[3] = arg[2]; + sprintf(buf, "%d", -n); + arg[1] = buf; + arg[2] = "0"; + + } else if ((32 <= n) && (n <= 62)){ + arg[0] = "addo"; + arg[3] = arg[2]; + arg[1] = "31"; + sprintf(buf, "%d", n-31); + arg[2] = buf; + + } else if ((shift = shift_ok(n)) != 0){ + arg[0] = "shlo"; + arg[3] = arg[2]; + sprintf(buf, "%d", shift); + arg[1] = buf; + sprintf(buf2, "%d", n >> shift); + arg[2] = buf2; + + } else { + arg[0] = "lda"; + } + break; + + default: + as_bad("invalid constant"); + return -1; + break; + } + return (arg[3] == 0) ? 2: 3; +} + +/***************************************************************************** + * parse_memop: parse a memory operand + * + * This routine is based on the observation that the 4 mode bits of the + * MEMB format, taken individually, have fairly consistent meaning: + * + * M3 (bit 13): 1 if displacement is present (D_BIT) + * M2 (bit 12): 1 for MEMB instructions (MEMB_BIT) + * M1 (bit 11): 1 if index is present (I_BIT) + * M0 (bit 10): 1 if abase is present (A_BIT) + * + * So we parse the memory operand and set bits in the mode as we find + * things. Then at the end, if we go to MEMB format, we need only set + * the MEMB bit (M2) and our mode is built for us. + * + * Unfortunately, I said "fairly consistent". The exceptions: + * + * DBIA + * 0100 Would seem illegal, but means "abase-only". + * + * 0101 Would seem to mean "abase-only" -- it means IP-relative. + * Must be converted to 0100. + * + * 0110 Would seem to mean "index-only", but is reserved. + * We turn on the D bit and provide a 0 displacement. + * + * The other thing to observe is that we parse from the right, peeling + * things * off as we go: first any index spec, then any abase, then + * the displacement. + * + **************************************************************************** */ +static + void + parse_memop(memP, argP, optype) +memS *memP; /* Where to put the results */ +char *argP; /* Text of the operand to be parsed */ +int optype; /* MEM1, MEM2, MEM4, MEM8, MEM12, or MEM16 */ +{ + char *indexP; /* Pointer to index specification with "[]" removed */ + char *p; /* Temp char pointer */ + char iprel_flag;/* True if this is an IP-relative operand */ + int regnum; /* Register number */ + int scale; /* Scale factor: 1,2,4,8, or 16. Later converted + * to internal format (0,1,2,3,4 respectively). + */ + int mode; /* MEMB mode bits */ + int *intP; /* Pointer to register number */ + + /* The following table contains the default scale factors for each + * type of memory instruction. It is accessed using (optype-MEM1) + * as an index -- thus it assumes the 'optype' constants are assigned + * consecutive values, in the order they appear in this table + */ + static int def_scale[] = { + 1, /* MEM1 */ + 2, /* MEM2 */ + 4, /* MEM4 */ + 8, /* MEM8 */ + -1, /* MEM12 -- no valid default */ + 16 /* MEM16 */ + }; + + + iprel_flag = mode = 0; + + /* Any index present? */ + indexP = get_ispec(argP); + if (indexP) { + p = strchr(indexP, '*'); + if (p == NULL) { + /* No explicit scale -- use default for this + *instruction type. + */ + scale = def_scale[ optype - MEM1 ]; + } else { + *p++ = '\0'; /* Eliminate '*' */ + + /* Now indexP->a '\0'-terminated register name, + * and p->a scale factor. + */ + + if (!strcmp(p,"16")){ + scale = 16; + } else if (strchr("1248",*p) && (p[1] == '\0')){ + scale = *p - '0'; + } else { + scale = -1; + } + } + + regnum = get_regnum(indexP); /* Get index reg. # */ + if (!IS_RG_REG(regnum)){ + as_bad("invalid index register"); + return; + } + + /* Convert scale to its binary encoding */ + switch (scale){ + case 1: scale = 0 << 7; break; + case 2: scale = 1 << 7; break; + case 4: scale = 2 << 7; break; + case 8: scale = 3 << 7; break; + case 16: scale = 4 << 7; break; + default: as_bad("invalid scale factor"); return; + }; + + memP->opcode |= scale | regnum; /* Set index bits in opcode */ + mode |= I_BIT; /* Found a valid index spec */ + } + + /* Any abase (Register Indirect) specification present? */ + if ((p = strrchr(argP,'(')) != NULL) { + /* "(" is there -- does it start a legal abase spec? + * (If not it could be part of a displacement expression.) + */ + intP = (int *) hash_find(areg_hash, p); + if (intP != NULL){ + /* Got an abase here */ + regnum = *intP; + *p = '\0'; /* discard register spec */ + if (regnum == IPREL){ + /* We have to specialcase ip-rel mode */ + iprel_flag = 1; + } else { + memP->opcode |= regnum << 14; + mode |= A_BIT; + } + } + } + + /* Any expression present? */ + memP->e = argP; + if (*argP != '\0'){ + mode |= D_BIT; + } + + /* Special-case ip-relative addressing */ + if (iprel_flag){ + if (mode & I_BIT){ + syntax(); + } else { + memP->opcode |= 5 << 10; /* IP-relative mode */ + memP->disp = 32; + } + return; + } + + /* Handle all other modes */ + switch (mode){ + case D_BIT | A_BIT: + /* Go with MEMA instruction format for now (grow to MEMB later + * if 12 bits is not enough for the displacement). + * MEMA format has a single mode bit: set it to indicate + * that abase is present. + */ + memP->opcode |= MEMA_ABASE; + memP->disp = 12; + break; + + case D_BIT: + /* Go with MEMA instruction format for now (grow to MEMB later + * if 12 bits is not enough for the displacement). + */ + memP->disp = 12; + break; + + case A_BIT: + /* For some reason, the bit string for this mode is not + * consistent: it should be 0 (exclusive of the MEMB bit), + * so we set it "by hand" here. + */ + memP->opcode |= MEMB_BIT; + break; + + case A_BIT | I_BIT: + /* set MEMB bit in mode, and OR in mode bits */ + memP->opcode |= mode | MEMB_BIT; + break; + + case I_BIT: + /* Treat missing displacement as displacement of 0 */ + mode |= D_BIT; + /*********************** + * Fall into next case * + ********************** */ + case D_BIT | A_BIT | I_BIT: + case D_BIT | I_BIT: + /* set MEMB bit in mode, and OR in mode bits */ + memP->opcode |= mode | MEMB_BIT; + memP->disp = 32; + break; + + default: + syntax(); + break; + } +} + +/***************************************************************************** + * parse_po: parse machine-dependent pseudo-op + * + * This is a top-level routine for machine-dependent pseudo-ops. It slurps + * up the rest of the input line, breaks out the individual arguments, + * and dispatches them to the correct handler. + **************************************************************************** */ +static + void + parse_po(po_num) +int po_num; /* Pseudo-op number: currently S_LEAFPROC or S_SYSPROC */ +{ + char *args[4]; /* Pointers operands, with no embedded whitespace. + * arg[0] unused. + * arg[1-3]->operands + */ + int n_ops; /* Number of operands */ + char *p; /* Pointer to beginning of unparsed argument string */ + char eol; /* Character that indicated end of line */ + + extern char is_end_of_line[]; + + /* Advance input pointer to end of line. */ + p = input_line_pointer; + while (!is_end_of_line[ *input_line_pointer ]){ + input_line_pointer++; + } + eol = *input_line_pointer; /* Save end-of-line char */ + *input_line_pointer = '\0'; /* Terminate argument list */ + + /* Parse out operands */ + n_ops = get_args(p, args); + if (n_ops == -1){ + return; + } + + /* Dispatch to correct handler */ + switch (po_num){ + case S_SYSPROC: s_sysproc(n_ops, args); break; + case S_LEAFPROC: s_leafproc(n_ops, args); break; + default: BAD_CASE(po_num); break; + } + + /* Restore eol, so line numbers get updated correctly. Base assembler + * assumes we leave input pointer pointing at char following the eol. + */ + *input_line_pointer++ = eol; +} + +/***************************************************************************** + * parse_regop: parse a register operand. + * + * In case of illegal operand, issue a message and return some valid + * information so instruction processing can continue. + **************************************************************************** */ +static + void + parse_regop(regopP, optext, opdesc) +struct regop *regopP; /* Where to put description of register operand */ +char *optext; /* Text of operand */ +char opdesc; /* Descriptor byte: what's legal for this operand */ +{ + int n; /* Register number */ + expressionS e; /* Parsed expression */ + + /* See if operand is a register */ + n = get_regnum(optext); + if (n >= 0){ + if (IS_RG_REG(n)){ + /* global or local register */ + if (!REG_ALIGN(opdesc,n)){ + as_bad("unaligned register"); + } + regopP->n = n; + regopP->mode = 0; + regopP->special = 0; + return; + } else if (IS_FP_REG(n) && FP_OK(opdesc)){ + /* Floating point register, and it's allowed */ + regopP->n = n - FP0; + regopP->mode = 1; + regopP->special = 0; + return; + } else if (IS_SF_REG(n) && SFR_OK(opdesc)){ + /* Special-function register, and it's allowed */ + regopP->n = n - SF0; + regopP->mode = 0; + regopP->special = 1; + if (!targ_has_sfr(regopP->n)){ + as_bad("no such sfr in this architecture"); + } + return; + } + } else if (LIT_OK(opdesc)){ + /* + * How about a literal? + */ + regopP->mode = 1; + regopP->special = 0; + if (FP_OK(opdesc)){ /* floating point literal acceptable */ + /* Skip over 0f, 0d, or 0e prefix */ + if ( (optext[0] == '0') + && (optext[1] >= 'd') + && (optext[1] <= 'f') ){ + optext += 2; + } + + if (!strcmp(optext,"0.0") || !strcmp(optext,"0") ){ + regopP->n = 0x10; + return; + } + if (!strcmp(optext,"1.0") || !strcmp(optext,"1") ){ + regopP->n = 0x16; + return; + } + + } else { /* fixed point literal acceptable */ + if ((parse_expr(optext,&e) != SEG_ABSOLUTE) + || (offs(e) < 0) || (offs(e) > 31)){ + as_bad("illegal literal"); + offs(e) = 0; + } + regopP->n = offs(e); + return; + } + } + + /* Nothing worked */ + syntax(); + regopP->mode = 0; /* Register r0 is always a good one */ + regopP->n = 0; + regopP->special = 0; +} /* parse_regop() */ + +/***************************************************************************** + * reg_fmt: generate a REG-format instruction + * + **************************************************************************** */ +static void reg_fmt(args, oP) +char *args[]; /* args[0]->opcode mnemonic, args[1-3]->operands */ +struct i960_opcode *oP; /* Pointer to description of instruction */ +{ + long instr; /* Binary to be output */ + struct regop regop; /* Description of register operand */ + int n_ops; /* Number of operands */ + + + instr = oP->opcode; + n_ops = oP->num_ops; + + if (n_ops >= 1){ + parse_regop(®op, args[1], oP->operand[0]); + + if ((n_ops == 1) && !(instr & M3)){ + /* 1-operand instruction in which the dst field should + * be used (instead of src1). + */ + regop.n <<= 19; + if (regop.special){ + regop.mode = regop.special; + } + regop.mode <<= 13; + regop.special = 0; + } else { + /* regop.n goes in bit 0, needs no shifting */ + regop.mode <<= 11; + regop.special <<= 5; + } + instr |= regop.n | regop.mode | regop.special; + } + + if (n_ops >= 2) { + parse_regop(®op, args[2], oP->operand[1]); + + if ((n_ops == 2) && !(instr & M3)){ + /* 2-operand instruction in which the dst field should + * be used instead of src2). + */ + regop.n <<= 19; + if (regop.special){ + regop.mode = regop.special; + } + regop.mode <<= 13; + regop.special = 0; + } else { + regop.n <<= 14; + regop.mode <<= 12; + regop.special <<= 6; + } + instr |= regop.n | regop.mode | regop.special; + } + if (n_ops == 3){ + parse_regop(®op, args[3], oP->operand[2]); + if (regop.special){ + regop.mode = regop.special; + } + instr |= (regop.n <<= 19) | (regop.mode <<= 13); + } + emit(instr); +} + + +/***************************************************************************** + * relax_cobr: + * Replace cobr instruction in a code fragment with equivalent branch and + * compare instructions, so it can reach beyond a 13-bit displacement. + * Set up an address fix/relocation for the new branch instruction. + * + **************************************************************************** */ + +/* This "conditional jump" table maps cobr instructions into equivalent + * compare and branch opcodes. + */ +static + struct { + long compare; + long branch; + } coj[] = { /* COBR OPCODE: */ + CHKBIT, BNO, /* 0x30 - bbc */ + CMPO, BG, /* 0x31 - cmpobg */ + CMPO, BE, /* 0x32 - cmpobe */ + CMPO, BGE, /* 0x33 - cmpobge */ + CMPO, BL, /* 0x34 - cmpobl */ + CMPO, BNE, /* 0x35 - cmpobne */ + CMPO, BLE, /* 0x36 - cmpoble */ + CHKBIT, BO, /* 0x37 - bbs */ + CMPI, BNO, /* 0x38 - cmpibno */ + CMPI, BG, /* 0x39 - cmpibg */ + CMPI, BE, /* 0x3a - cmpibe */ + CMPI, BGE, /* 0x3b - cmpibge */ + CMPI, BL, /* 0x3c - cmpibl */ + CMPI, BNE, /* 0x3d - cmpibne */ + CMPI, BLE, /* 0x3e - cmpible */ + CMPI, BO, /* 0x3f - cmpibo */ + }; + +static + void + relax_cobr(fragP) +register fragS *fragP; /* fragP->fr_opcode is assumed to point to + * the cobr instruction, which comes at the + * end of the code fragment. + */ +{ + int opcode, src1, src2, m1, s2; + /* Bit fields from cobr instruction */ + long bp_bits; /* Branch prediction bits from cobr instruction */ + long instr; /* A single i960 instruction */ + char *iP; /*->instruction to be replaced */ + fixS *fixP; /* Relocation that can be done at assembly time */ + + /* PICK UP & PARSE COBR INSTRUCTION */ + iP = fragP->fr_opcode; + instr = md_chars_to_number(iP, 4); + opcode = ((instr >> 24) & 0xff) - 0x30; /* "-0x30" for table index */ + src1 = (instr >> 19) & 0x1f; + m1 = (instr >> 13) & 1; + s2 = instr & 1; + src2 = (instr >> 14) & 0x1f; + bp_bits= instr & BP_MASK; + + /* GENERATE AND OUTPUT COMPARE INSTRUCTION */ + instr = coj[opcode].compare + | src1 | (m1 << 11) | (s2 << 6) | (src2 << 14); + md_number_to_chars(iP, instr, 4); + + /* OUTPUT BRANCH INSTRUCTION */ + md_number_to_chars(iP+4, coj[opcode].branch | bp_bits, 4); + + /* SET UP ADDRESS FIXUP/RELOCATION */ + fixP = fix_new(fragP, + iP+4 - fragP->fr_literal, + 4, + fragP->fr_symbol, + 0, + fragP->fr_offset, + 1, + 0); + + fixP->fx_bit_fixP = (bit_fixS *) 24; /* Store size of bit field */ + + fragP->fr_fix += 4; + frag_wane(fragP); +} + + +/***************************************************************************** + * reloc_callj: Relocate a 'callj' instruction + * + * This is a "non-(GNU)-standard" machine-dependent hook. The base + * assembler calls it when it decides it can relocate an address at + * assembly time instead of emitting a relocation directive. + * + * Check to see if the relocation involves a 'callj' instruction to a: + * sysproc: Replace the default 'call' instruction with a 'calls' + * leafproc: Replace the default 'call' instruction with a 'bal'. + * other proc: Do nothing. + * + * See b.out.h for details on the 'n_other' field in a symbol structure. + * + * IMPORTANT!: + * Assumes the caller has already figured out, in the case of a leafproc, + * to use the 'bal' entry point, and has substituted that symbol into the + * passed fixup structure. + * + **************************************************************************** */ +void reloc_callj(fixP) +fixS *fixP; /* Relocation that can be done at assembly time */ +{ + char *where; /*->the binary for the instruction being relocated */ + + if (!fixP->fx_callj) { + return; + } /* This wasn't a callj instruction in the first place */ + + where = fixP->fx_frag->fr_literal + fixP->fx_where; + + if (TC_S_IS_SYSPROC(fixP->fx_addsy)) { + /* Symbol is a .sysproc: replace 'call' with 'calls'. + * System procedure number is (other-1). + */ + md_number_to_chars(where, CALLS|TC_S_GET_SYSPROC(fixP->fx_addsy), 4); + + /* Nothing else needs to be done for this instruction. + * Make sure 'md_number_to_field()' will perform a no-op. + */ + fixP->fx_bit_fixP = (bit_fixS *) 1; + + } else if (TC_S_IS_CALLNAME(fixP->fx_addsy)) { + /* Should not happen: see block comment above */ + as_fatal("Trying to 'bal' to %s", S_GET_NAME(fixP->fx_addsy)); + + } else if (TC_S_IS_BALNAME(fixP->fx_addsy)) { + /* Replace 'call' with 'bal'; both instructions have + * the same format, so calling code should complete + * relocation as if nothing happened here. + */ + md_number_to_chars(where, BAL, 4); + } else if (TC_S_IS_BADPROC(fixP->fx_addsy)) { + as_bad("Looks like a proc, but can't tell what kind.\n"); + } /* switch on proc type */ + + /* else Symbol is neither a sysproc nor a leafproc */ + + return; +} /* reloc_callj() */ + + +/***************************************************************************** + * s_leafproc: process .leafproc pseudo-op + * + * .leafproc takes two arguments, the second one is optional: + * arg[1]: name of 'call' entry point to leaf procedure + * arg[2]: name of 'bal' entry point to leaf procedure + * + * If the two arguments are identical, or if the second one is missing, + * the first argument is taken to be the 'bal' entry point. + * + * If there are 2 distinct arguments, we must make sure that the 'bal' + * entry point immediately follows the 'call' entry point in the linked + * list of symbols. + * + **************************************************************************** */ +static void s_leafproc(n_ops, args) +int n_ops; /* Number of operands */ +char *args[]; /* args[1]->1st operand, args[2]->2nd operand */ +{ + symbolS *callP; /* Pointer to leafproc 'call' entry point symbol */ + symbolS *balP; /* Pointer to leafproc 'bal' entry point symbol */ + + if ((n_ops != 1) && (n_ops != 2)) { + as_bad("should have 1 or 2 operands"); + return; + } /* Check number of arguments */ + + /* Find or create symbol for 'call' entry point. */ + callP = symbol_find_or_make(args[1]); + + if (TC_S_IS_CALLNAME(callP)) { + as_warn("Redefining leafproc %s", S_GET_NAME(callP)); + } /* is leafproc */ + + /* If that was the only argument, use it as the 'bal' entry point. + * Otherwise, mark it as the 'call' entry point and find or create + * another symbol for the 'bal' entry point. + */ + if ((n_ops == 1) || !strcmp(args[1],args[2])) { + TC_S_FORCE_TO_BALNAME(callP); + + } else { + TC_S_FORCE_TO_CALLNAME(callP); + + balP = symbol_find_or_make(args[2]); + if (TC_S_IS_CALLNAME(balP)) { + as_warn("Redefining leafproc %s", S_GET_NAME(balP)); + } + TC_S_FORCE_TO_BALNAME(balP); + + tc_set_bal_of_call(callP, balP); + } /* if only one arg, or the args are the same */ + + return; +} /* s_leafproc() */ + + +/* + * s_sysproc: process .sysproc pseudo-op + * + * .sysproc takes two arguments: + * arg[1]: name of entry point to system procedure + * arg[2]: 'entry_num' (index) of system procedure in the range + * [0,31] inclusive. + * + * For [ab].out, we store the 'entrynum' in the 'n_other' field of + * the symbol. Since that entry is normally 0, we bias 'entrynum' + * by adding 1 to it. It must be unbiased before it is used. + */ +static void s_sysproc(n_ops, args) +int n_ops; /* Number of operands */ +char *args[]; /* args[1]->1st operand, args[2]->2nd operand */ +{ + expressionS exp; + symbolS *symP; + + if (n_ops != 2) { + as_bad("should have two operands"); + return; + } /* bad arg count */ + + /* Parse "entry_num" argument and check it for validity. */ + if ((parse_expr(args[2],&exp) != SEG_ABSOLUTE) + || (offs(exp) < 0) + || (offs(exp) > 31)) { + as_bad("'entry_num' must be absolute number in [0,31]"); + return; + } + + /* Find/make symbol and stick entry number (biased by +1) into it */ + symP = symbol_find_or_make(args[1]); + + if (TC_S_IS_SYSPROC(symP)) { + as_warn("Redefining entrynum for sysproc %s", S_GET_NAME(symP)); + } /* redefining */ + + TC_S_SET_SYSPROC(symP, offs(exp)); /* encode entry number */ + TC_S_FORCE_TO_SYSPROC(symP); + + return; +} /* s_sysproc() */ + + +/***************************************************************************** + * shift_ok: + * Determine if a "shlo" instruction can be used to implement a "ldconst". + * This means that some number X < 32 can be shifted left to produce the + * constant of interest. + * + * Return the shift count, or 0 if we can't do it. + * Caller calculates X by shifting original constant right 'shift' places. + * + **************************************************************************** */ +static + int + shift_ok(n) +int n; /* The constant of interest */ +{ + int shift; /* The shift count */ + + if (n <= 0){ + /* Can't do it for negative numbers */ + return 0; + } + + /* Shift 'n' right until a 1 is about to be lost */ + for (shift = 0; (n & 1) == 0; shift++){ + n >>= 1; + } + + if (n >= 32){ + return 0; + } + return shift; +} + + +/***************************************************************************** + * syntax: issue syntax error + * + **************************************************************************** */ +static void syntax() { + as_bad("syntax error"); +} /* syntax() */ + + +/***************************************************************************** + * targ_has_sfr: + * Return TRUE iff the target architecture supports the specified + * special-function register (sfr). + * + **************************************************************************** */ +static + int + targ_has_sfr(n) +int n; /* Number (0-31) of sfr */ +{ + switch (architecture){ + case ARCH_KA: + case ARCH_KB: + case ARCH_MC: + return 0; + case ARCH_CA: + default: + return ((0 <= n) && (n <= 2)); + } +} + + +/***************************************************************************** + * targ_has_iclass: + * Return TRUE iff the target architecture supports the indicated + * class of instructions. + * + **************************************************************************** */ +static + int + targ_has_iclass(ic) +int ic; /* Instruction class; one of: + * I_BASE, I_CX, I_DEC, I_KX, I_FP, I_MIL, I_CASIM + */ +{ + iclasses_seen |= ic; + switch (architecture){ + case ARCH_KA: return ic & (I_BASE | I_KX); + case ARCH_KB: return ic & (I_BASE | I_KX | I_FP | I_DEC); + case ARCH_MC: return ic & (I_BASE | I_KX | I_FP | I_DEC | I_MIL); + case ARCH_CA: return ic & (I_BASE | I_CX | I_CASIM); + default: + if ((iclasses_seen & (I_KX|I_FP|I_DEC|I_MIL)) + && (iclasses_seen & I_CX)){ + as_warn("architecture of opcode conflicts with that of earlier instruction(s)"); + iclasses_seen &= ~ic; + } + return 1; + } +} + + +/* Parse an operand that is machine-specific. + We just return without modifying the expression if we have nothing + to do. */ + +/* ARGSUSED */ +void + md_operand (expressionP) +expressionS *expressionP; +{ +} + +/* We have no need to default values of symbols. */ + +/* ARGSUSED */ +symbolS *md_undefined_symbol(name) +char *name; +{ + return 0; +} /* md_undefined_symbol() */ + +/* Exactly what point is a PC-relative offset relative TO? + On the i960, they're relative to the address of the instruction, + which we have set up as the address of the fixup too. */ +long + md_pcrel_from (fixP) +fixS *fixP; +{ + return fixP->fx_where + fixP->fx_frag->fr_address; +} + +void + md_apply_fix(fixP, val) +fixS *fixP; +long val; +{ + char *place = fixP->fx_where + fixP->fx_frag->fr_literal; + + if (!fixP->fx_bit_fixP) { + + switch (fixP->fx_im_disp) { + case 0: + fixP->fx_addnumber = val; + md_number_to_imm(place, val, fixP->fx_size, fixP); + break; + case 1: + md_number_to_disp(place, + fixP->fx_pcrel ? val + fixP->fx_pcrel_adjust : val, + fixP->fx_size); + break; + case 2: /* fix requested for .long .word etc */ + md_number_to_chars(place, val, fixP->fx_size); + break; + default: + as_fatal("Internal error in md_apply_fix() in file \"%s\"", __FILE__); + } /* OVE: maybe one ought to put _imm _disp _chars in one md-func */ + } else { + md_number_to_field(place, val, fixP->fx_bit_fixP); + } + + return; +} /* md_apply_fix() */ + +#if defined(OBJ_AOUT) | defined(OBJ_BOUT) +void tc_bout_fix_to_chars(where, fixP, segment_address_in_file) +char *where; +fixS *fixP; +relax_addressT segment_address_in_file; +{ + static unsigned char nbytes_r_length[] = { 42, 0, 1, 42, 2 }; + struct relocation_info ri; + symbolS *symbolP; + + /* JF this is for paranoia */ + memset((char *)&ri, '\0', sizeof(ri)); + + know((symbolP = fixP->fx_addsy) != 0); + + /* These two 'cuz of NS32K */ + ri.r_callj = fixP->fx_callj; + + ri.r_length = nbytes_r_length[fixP->fx_size]; + ri.r_pcrel = fixP->fx_pcrel; + ri.r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file; + + if (!S_IS_DEFINED(symbolP)) { + ri.r_extern = 1; + ri.r_index = symbolP->sy_number; + } else { + ri.r_extern = 0; + ri.r_index = S_GET_TYPE(symbolP); + } + + /* Output the relocation information in machine-dependent form. */ + md_ri_to_chars(where, &ri); + + return; +} /* tc_bout_fix_to_chars() */ + +#endif /* OBJ_AOUT or OBJ_BOUT */ + +/* Align an address by rounding it up to the specified boundary. + */ +long md_section_align(seg, addr) +segT seg; +long addr; /* Address to be rounded up */ +{ + return((addr + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg])); +} /* md_section_align() */ + +#ifdef OBJ_COFF +void tc_headers_hook(headers) +object_headers *headers; +{ + /* FIXME: remove this line */ /* unsigned short arch_flag = 0; */ + + if ((iclasses_seen == I_BASE) || (iclasses_seen == 0)) { + headers->filehdr.f_flags |= F_I960CORE; + } else if (iclasses_seen & I_CX){ + headers->filehdr.f_flags |= F_I960CA; + } else if (iclasses_seen & I_MIL){ + headers->filehdr.f_flags |= F_I960MC; + } else if (iclasses_seen & (I_DEC|I_FP)){ + headers->filehdr.f_flags |= F_I960KB; + } else { + headers->filehdr.f_flags |= F_I960KA; + } /* set arch flag */ + + if (flagseen['R']) { + headers->filehdr.f_magic = I960RWMAGIC; + headers->aouthdr.magic = OMAGIC; + } else { + headers->filehdr.f_magic = I960ROMAGIC; + headers->aouthdr.magic = NMAGIC; + } /* set magic numbers */ + + return; +} /* tc_headers_hook() */ +#endif /* OBJ_COFF */ + +/* + * Things going on here: + * + * For bout, We need to assure a couple of simplifying + * assumptions about leafprocs for the linker: the leafproc + * entry symbols will be defined in the same assembly in + * which they're declared with the '.leafproc' directive; + * and if a leafproc has both 'call' and 'bal' entry points + * they are both global or both local. + * + * For coff, the call symbol has a second aux entry that + * contains the bal entry point. The bal symbol becomes a + * label. + * + * For coff representation, the call symbol has a second aux entry that + * contains the bal entry point. The bal symbol becomes a label. + * + */ + +void tc_crawl_symbol_chain(headers) +object_headers *headers; +{ + symbolS *symbolP; + + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { +#ifdef OBJ_COFF + if (TC_S_IS_SYSPROC(symbolP)) { + /* second aux entry already contains the sysproc number */ + S_SET_NUMBER_AUXILIARY(symbolP, 2); + S_SET_STORAGE_CLASS(symbolP, C_SCALL); + S_SET_DATA_TYPE(symbolP, S_GET_DATA_TYPE(symbolP) | (DT_FCN << N_BTSHFT)); + continue; + } /* rewrite sysproc */ +#endif /* OBJ_COFF */ + + if (!TC_S_IS_BALNAME(symbolP) && !TC_S_IS_CALLNAME(symbolP)) { + continue; + } /* Not a leafproc symbol */ + + if (!S_IS_DEFINED(symbolP)) { + as_bad("leafproc symbol '%s' undefined", S_GET_NAME(symbolP)); + } /* undefined leaf */ + + if (TC_S_IS_CALLNAME(symbolP)) { + symbolS *balP = tc_get_bal_of_call(symbolP); + if (S_IS_EXTERNAL(symbolP) != S_IS_EXTERNAL(balP)) { + S_SET_EXTERNAL(symbolP); + S_SET_EXTERNAL(balP); + as_warn("Warning: making leafproc entries %s and %s both global\n", + S_GET_NAME(symbolP), S_GET_NAME(balP)); + } /* externality mismatch */ + } /* if callname */ + } /* walk the symbol chain */ + + return; +} /* tc_crawl_symbol_chain() */ + +/* + * For aout or bout, the bal immediately follows the call. + * + * For coff, we cheat and store a pointer to the bal symbol + * in the second aux entry of the call. + */ + +void tc_set_bal_of_call(callP, balP) +symbolS *callP; +symbolS *balP; +{ + know(TC_S_IS_CALLNAME(callP)); + know(TC_S_IS_BALNAME(balP)); + +#ifdef OBJ_COFF + + callP->sy_symbol.ost_auxent[1].x_bal.x_balntry = (int) balP; + S_SET_NUMBER_AUXILIARY(callP,2); + +#elif defined(OBJ_AOUT) || defined(OBJ_BOUT) + + /* If the 'bal' entry doesn't immediately follow the 'call' + * symbol, unlink it from the symbol list and re-insert it. + */ + if (symbol_next(callP) != balP) { + symbol_remove(balP, &symbol_rootP, &symbol_lastP); + symbol_append(balP, callP, &symbol_rootP, &symbol_lastP); + } /* if not in order */ + +#else + (as yet unwritten.); +#endif /* switch on OBJ_FORMAT */ + + return; +} /* tc_set_bal_of_call() */ + +char *_tc_get_bal_of_call(callP) +symbolS *callP; +{ + symbolS *retval; + + know(TC_S_IS_CALLNAME(callP)); + +#ifdef OBJ_COFF + retval = (symbolS *) (callP->sy_symbol.ost_auxent[1].x_bal.x_balntry); +#elif defined(OBJ_AOUT) || defined(OBJ_BOUT) + retval = symbol_next(callP); +#else + (as yet unwritten.); +#endif /* switch on OBJ_FORMAT */ + + know(TC_S_IS_BALNAME(retval)); + return((char *) retval); +} /* _tc_get_bal_of_call() */ + +void tc_coff_symbol_emit_hook(symbolP) +symbolS *symbolP; +{ + if (TC_S_IS_CALLNAME(symbolP)) { +#ifdef OBJ_COFF + symbolS *balP = tc_get_bal_of_call(symbolP); + + /* second aux entry contains the bal entry point */ + /* S_SET_NUMBER_AUXILIARY(symbolP, 2); */ + symbolP->sy_symbol.ost_auxent[1].x_bal.x_balntry = S_GET_VALUE(balP); + S_SET_STORAGE_CLASS(symbolP, (!SF_GET_LOCAL(symbolP) ? C_LEAFEXT : C_LEAFSTAT)); + S_SET_DATA_TYPE(symbolP, S_GET_DATA_TYPE(symbolP) | (DT_FCN << N_BTSHFT)); + /* fix up the bal symbol */ + S_SET_STORAGE_CLASS(balP, C_LABEL); +#endif /* OBJ_COFF */ + } /* only on calls */ + + return; +} /* tc_coff_symbol_emit_hook() */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of tc-i960.c */ diff --git a/gnu/usr.bin/as/config/tc-i960.h b/gnu/usr.bin/as/config/tc-i960.h new file mode 100644 index 000000000000..caad4d622d37 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-i960.h @@ -0,0 +1,281 @@ +/* tc-i960.h - Basic 80960 instruction formats. + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, + or (at your option) any later version. + + GAS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with GAS; see the file COPYING. If not, write + to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef TC_I960 +#define TC_I960 1 + +#define NO_LISTING + +/* + * The 'COJ' instructions are actually COBR instructions with the 'b' in + * the mnemonic replaced by a 'j'; they are ALWAYS "de-optimized" if necessary: + * if the displacement will not fit in 13 bits, the assembler will replace them + * with the corresponding compare and branch instructions. + * + * All of the 'MEMn' instructions are the same format; the 'n' in the name + * indicates the default index scale factor (the size of the datum operated on). + * + * The FBRA formats are not actually an instruction format. They are the + * "convenience directives" for branching on floating-point comparisons, + * each of which generates 2 instructions (a 'bno' and one other branch). + * + * The CALLJ format is not actually an instruction format. It indicates that + * the instruction generated (a CTRL-format 'call') should have its relocation + * specially flagged for link-time replacement with a 'bal' or 'calls' if + * appropriate. + */ + +/* tailor gas */ +#define SYMBOLS_NEED_BACKPOINTERS +#define LOCAL_LABELS_FB +#define WANT_BITFIELDS + +/* tailor the coff format */ +#define OBJ_COFF_SECTION_HEADER_HAS_ALIGNMENT +#define OBJ_COFF_MAX_AUXENTRIES (2) + +/* other */ +#define CTRL 0 +#define COBR 1 +#define COJ 2 +#define REG 3 +#define MEM1 4 +#define MEM2 5 +#define MEM4 6 +#define MEM8 7 +#define MEM12 8 +#define MEM16 9 +#define FBRA 10 +#define CALLJ 11 + +/* Masks for the mode bits in REG format instructions */ +#define M1 0x0800 +#define M2 0x1000 +#define M3 0x2000 + +/* Generate the 12-bit opcode for a REG format instruction by placing the + * high 8 bits in instruction bits 24-31, the low 4 bits in instruction bits + * 7-10. + */ + +#define REG_OPC(opc) ((opc & 0xff0) << 20) | ((opc & 0xf) << 7) + +/* Generate a template for a REG format instruction: place the opcode bits + * in the appropriate fields and OR in mode bits for the operands that will not + * be used. I.e., + * set m1=1, if src1 will not be used + * set m2=1, if src2 will not be used + * set m3=1, if dst will not be used + * + * Setting the "unused" mode bits to 1 speeds up instruction execution(!). + * The information is also useful to us because some 1-operand REG instructions + * use the src1 field, others the dst field; and some 2-operand REG instructions + * use src1/src2, others src1/dst. The set mode bits enable us to distinguish. + */ +#define R_0(opc) ( REG_OPC(opc) | M1 | M2 | M3 ) /* No operands */ +#define R_1(opc) ( REG_OPC(opc) | M2 | M3 ) /* 1 operand: src1 */ +#define R_1D(opc) ( REG_OPC(opc) | M1 | M2 ) /* 1 operand: dst */ +#define R_2(opc) ( REG_OPC(opc) | M3 ) /* 2 ops: src1/src2 */ +#define R_2D(opc) ( REG_OPC(opc) | M2 ) /* 2 ops: src1/dst */ +#define R_3(opc) ( REG_OPC(opc) ) /* 3 operands */ + +/* DESCRIPTOR BYTES FOR REGISTER OPERANDS + * + * Interpret names as follows: + * R: global or local register only + * RS: global, local, or (if target allows) special-function register only + * RL: global or local register, or integer literal + * RSL: global, local, or (if target allows) special-function register; + * or integer literal + * F: global, local, or floating-point register + * FL: global, local, or floating-point register; or literal (including + * floating point) + * + * A number appended to a name indicates that registers must be aligned, + * as follows: + * 2: register number must be multiple of 2 + * 4: register number must be multiple of 4 + */ + +#define SFR 0x10 /* Mask for the "sfr-OK" bit */ +#define LIT 0x08 /* Mask for the "literal-OK" bit */ +#define FP 0x04 /* Mask for "floating-point-OK" bit */ + +/* This macro ors the bits together. Note that 'align' is a mask + * for the low 0, 1, or 2 bits of the register number, as appropriate. + */ +#define OP(align,lit,fp,sfr) ( align | lit | fp | sfr ) + +#define R OP( 0, 0, 0, 0 ) +#define RS OP( 0, 0, 0, SFR ) +#define RL OP( 0, LIT, 0, 0 ) +#define RSL OP( 0, LIT, 0, SFR ) +#define F OP( 0, 0, FP, 0 ) +#define FL OP( 0, LIT, FP, 0 ) +#define R2 OP( 1, 0, 0, 0 ) +#define RL2 OP( 1, LIT, 0, 0 ) +#define F2 OP( 1, 0, FP, 0 ) +#define FL2 OP( 1, LIT, FP, 0 ) +#define R4 OP( 3, 0, 0, 0 ) +#define RL4 OP( 3, LIT, 0, 0 ) +#define F4 OP( 3, 0, FP, 0 ) +#define FL4 OP( 3, LIT, FP, 0 ) + +#define M 0x7f /* Memory operand (MEMA & MEMB format instructions) */ + +/* Macros to extract info from the register operand descriptor byte 'od'. + */ +#define SFR_OK(od) (od & SFR) /* TRUE if sfr operand allowed */ +#define LIT_OK(od) (od & LIT) /* TRUE if literal operand allowed */ +#define FP_OK(od) (od & FP) /* TRUE if floating-point op allowed */ +#define REG_ALIGN(od,n) ((od & 0x3 & n) == 0) +/* TRUE if reg #n is properly aligned */ +#define MEMOP(od) (od == M) /* TRUE if operand is a memory operand*/ + +/* Classes of 960 intructions: + * - each instruction falls into one class. + * - each target architecture supports one or more classes. + * + * EACH CONSTANT MUST CONTAIN 1 AND ONLY 1 SET BIT!: see targ_has_iclass(). + */ +#define I_BASE 0x01 /* 80960 base instruction set */ +#define I_CX 0x02 /* 80960Cx instruction */ +#define I_DEC 0x04 /* Decimal instruction */ +#define I_FP 0x08 /* Floating point instruction */ +#define I_KX 0x10 /* 80960Kx instruction */ +#define I_MIL 0x20 /* Military instruction */ + +/* MEANING OF 'n_other' in the symbol record. + * + * If non-zero, the 'n_other' fields indicates either a leaf procedure or + * a system procedure, as follows: + * + * 1 <= n_other <= 32 : + * The symbol is the entry point to a system procedure. + * 'n_value' is the address of the entry, as for any other + * procedure. The system procedure number (which can be used in + * a 'calls' instruction) is (n_other-1). These entries come from + * '.sysproc' directives. + * + * n_other == N_CALLNAME + * the symbol is the 'call' entry point to a leaf procedure. + * The *next* symbol in the symbol table must be the corresponding + * 'bal' entry point to the procedure (see following). These + * entries come from '.leafproc' directives in which two different + * symbols are specified (the first one is represented here). + * + * + * n_other == N_BALNAME + * the symbol is the 'bal' entry point to a leaf procedure. + * These entries result from '.leafproc' directives in which only + * one symbol is specified, or in which the same symbol is + * specified twice. + * + * Note that an N_CALLNAME entry *must* have a corresponding N_BALNAME entry, + * but not every N_BALNAME entry must have an N_CALLNAME entry. + */ +#define N_CALLNAME (-1) +#define N_BALNAME (-2) + + +/* i960 uses a custom relocation record. */ + +/* let obj-aout.h know */ +#define CUSTOM_RELOC_FORMAT 1 +/* let a.out.gnu.h know */ +#define N_RELOCATION_INFO_DECLARED 1 +struct relocation_info { + int r_address; /* File address of item to be relocated */ + unsigned + r_index:24,/* Index of symbol on which relocation is based*/ + r_pcrel:1, /* 1 => relocate PC-relative; else absolute + * On i960, pc-relative implies 24-bit + * address, absolute implies 32-bit. + */ + r_length:2, /* Number of bytes to relocate: + * 0 => 1 byte + * 1 => 2 bytes + * 2 => 4 bytes -- only value used for i960 + */ + r_extern:1, + r_bsr:1, /* Something for the GNU NS32K assembler */ + r_disp:1, /* Something for the GNU NS32K assembler */ + r_callj:1, /* 1 if relocation target is an i960 'callj' */ + nuthin:1; /* Unused */ +}; + +/* hacks for tracking callj's */ +#if defined(OBJ_AOUT) | defined(OBJ_BOUT) + +#define TC_S_IS_SYSPROC(s) ((1 <= S_GET_OTHER(s)) && (S_GET_OTHER(s) <= 32)) +#define TC_S_IS_BALNAME(s) (S_GET_OTHER(s) == N_BALNAME) +#define TC_S_IS_CALLNAME(s) (S_GET_OTHER(s) == N_CALLNAME) +#define TC_S_IS_BADPROC(s) ((S_GET_OTHER(s) != 0) && !TC_S_IS_CALLNAME(s) && !TC_S_IS_BALNAME(s) && !TC_S_IS_SYSPROC(s)) + +#define TC_S_SET_SYSPROC(s, p) (S_SET_OTHER((s), (p)+1)) +#define TC_S_GET_SYSPROC(s) (S_GET_OTHER(s)-1) + +#define TC_S_FORCE_TO_BALNAME(s) (S_SET_OTHER((s), N_BALNAME)) +#define TC_S_FORCE_TO_CALLNAME(s) (S_SET_OTHER((s), N_CALLNAME)) +#define TC_S_FORCE_TO_SYSPROC(s) {;} + +#elif defined(OBJ_COFF) + +#define TC_S_IS_SYSPROC(s) (S_GET_STORAGE_CLASS(s) == C_SCALL) +#define TC_S_IS_BALNAME(s) (SF_GET_BALNAME(s)) +#define TC_S_IS_CALLNAME(s) (SF_GET_CALLNAME(s)) +#define TC_S_IS_BADPROC(s) (TC_S_IS_SYSPROC(s) && TC_S_GET_SYSPROC(s) < 0 && 31 < TC_S_GET_SYSPROC(s)) + +#define TC_S_SET_SYSPROC(s, p) ((s)->sy_symbol.ost_auxent[1].x_sc.x_stindx = (p)) +#define TC_S_GET_SYSPROC(s) ((s)->sy_symbol.ost_auxent[1].x_sc.x_stindx) + +#define TC_S_FORCE_TO_BALNAME(s) (SF_SET_BALNAME(s)) +#define TC_S_FORCE_TO_CALLNAME(s) (SF_SET_CALLNAME(s)) +#define TC_S_FORCE_TO_SYSPROC(s) (S_SET_STORAGE_CLASS((s), C_SCALL)) + +#else /* switch on OBJ */ +you lose +#endif /* witch on OBJ */ + +#if __STDC__ == 1 + + void brtab_emit(void); +void reloc_callj(); /* this is really reloc_callj(fixS *fixP) but I don't want to change header inclusion order. */ +void tc_set_bal_of_call(); /* this is really tc_set_bal_of_call(symbolS *callP, symbolS *balP) */ + +#else /* not __STDC__ */ + +void brtab_emit(); +void reloc_callj(); +void tc_set_bal_of_call(); + +#endif /* not __STDC__ */ + +char *_tc_get_bal_of_call(); /* this is really symbolS *tc_get_bal_of_call(symbolS *callP). */ +#define tc_get_bal_of_call(c) ((symbolS *) _tc_get_bal_of_call(c)) +#endif + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of tc-i960.h */ diff --git a/gnu/usr.bin/as/config/tc-m68851.h b/gnu/usr.bin/as/config/tc-m68851.h new file mode 100644 index 000000000000..5f70e42be10f --- /dev/null +++ b/gnu/usr.bin/as/config/tc-m68851.h @@ -0,0 +1,304 @@ +/* This file is tc-m68851.h + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * pmmu.h + */ + +/* I suppose we have to copyright this file. Someone on the net sent it + to us as part of the changes for the m68851 Memory Management Unit */ + +/* Copyright (C) 1987 Free Software Foundation, Inc. + + This file is part of Gas, the GNU Assembler. + + The GNU assembler is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY. No author or distributor + accepts responsibility to anyone for the consequences of using it + or for whether it serves any particular purpose or works at all, + unless he says so in writing. Refer to the GNU Assembler General + Public License for full details. + + Everyone is granted permission to copy, modify and redistribute + the GNU Assembler, but only under the conditions described in the + GNU Assembler General Public License. A copy of this license is + supposed to have been given to you along with the GNU Assembler + so you can know your rights and responsibilities. It should be + in a file named COPYING. Among other things, the copyright + notice and this notice must be preserved on all copies. */ + +#ifdef m68851 + +/* + I didn't use much imagination in choosing the + following codes, so many of them aren't very + mnemonic. -rab + + P pmmu register + Possible values: + 000 TC Translation Control reg + 100 CAL Current Access Level + 101 VAL Validate Access Level + 110 SCC Stack Change Control + 111 AC Access Control + + W wide pmmu registers + Possible values: + 001 DRP Dma Root Pointer + 010 SRP Supervisor Root Pointer + 011 CRP Cpu Root Pointer + + f function code register + 0 SFC + 1 DFC + + V VAL register only + + X BADx, BACx + 100 BAD Breakpoint Acknowledge Data + 101 BAC Breakpoint Acknowledge Control + + Y PSR + Z PCSR + + | memory (modes 2-6, 7.*) + + */ + +/* + * these defines should be in m68k.c but + * i put them here to keep all the m68851 stuff + * together -rab + * JF--Make sure these #s don't clash with the ones in m68k.c + * That would be BAD. + */ +#define TC (FPS+1) /* 48 */ +#define DRP (TC+1) /* 49 */ +#define SRP (DRP+1) /* 50 */ +#define CRP (SRP+1) /* 51 */ +#define CAL (CRP+1) /* 52 */ +#define VAL (CAL+1) /* 53 */ +#define SCC (VAL+1) /* 54 */ +#define AC (SCC+1) /* 55 */ +#define BAD (AC+1) /* 56,57,58,59, 60,61,62,63 */ +#define BAC (BAD+8) /* 64,65,66,67, 68,69,70,71 */ +#define PSR (BAC+8) /* 72 */ +#define PCSR (PSR+1) /* 73 */ + +/* name */ /* opcode */ /* match */ /* args */ + +{"pbac", one(0xf0c7), one(0xffbf), "Bc"}, +{"pbacw", one(0xf087), one(0xffbf), "Bc"}, +{"pbas", one(0xf0c6), one(0xffbf), "Bc"}, +{"pbasw", one(0xf086), one(0xffbf), "Bc"}, +{"pbbc", one(0xf0c1), one(0xffbf), "Bc"}, +{"pbbcw", one(0xf081), one(0xffbf), "Bc"}, +{"pbbs", one(0xf0c0), one(0xffbf), "Bc"}, +{"pbbsw", one(0xf080), one(0xffbf), "Bc"}, +{"pbcc", one(0xf0cf), one(0xffbf), "Bc"}, +{"pbccw", one(0xf08f), one(0xffbf), "Bc"}, +{"pbcs", one(0xf0ce), one(0xffbf), "Bc"}, +{"pbcsw", one(0xf08e), one(0xffbf), "Bc"}, +{"pbgc", one(0xf0cd), one(0xffbf), "Bc"}, +{"pbgcw", one(0xf08d), one(0xffbf), "Bc"}, +{"pbgs", one(0xf0cc), one(0xffbf), "Bc"}, +{"pbgsw", one(0xf08c), one(0xffbf), "Bc"}, +{"pbic", one(0xf0cb), one(0xffbf), "Bc"}, +{"pbicw", one(0xf08b), one(0xffbf), "Bc"}, +{"pbis", one(0xf0ca), one(0xffbf), "Bc"}, +{"pbisw", one(0xf08a), one(0xffbf), "Bc"}, +{"pblc", one(0xf0c3), one(0xffbf), "Bc"}, +{"pblcw", one(0xf083), one(0xffbf), "Bc"}, +{"pbls", one(0xf0c2), one(0xffbf), "Bc"}, +{"pblsw", one(0xf082), one(0xffbf), "Bc"}, +{"pbsc", one(0xf0c5), one(0xffbf), "Bc"}, +{"pbscw", one(0xf085), one(0xffbf), "Bc"}, +{"pbss", one(0xf0c4), one(0xffbf), "Bc"}, +{"pbssw", one(0xf084), one(0xffbf), "Bc"}, +{"pbwc", one(0xf0c9), one(0xffbf), "Bc"}, +{"pbwcw", one(0xf089), one(0xffbf), "Bc"}, +{"pbws", one(0xf0c8), one(0xffbf), "Bc"}, +{"pbwsw", one(0xf088), one(0xffbf), "Bc"}, + + +{"pdbac", two(0xf048, 0x0007), two(0xfff8, 0xffff), "DsBw"}, +{"pdbas", two(0xf048, 0x0006), two(0xfff8, 0xffff), "DsBw"}, +{"pdbbc", two(0xf048, 0x0001), two(0xfff8, 0xffff), "DsBw"}, +{"pdbbs", two(0xf048, 0x0000), two(0xfff8, 0xffff), "DsBw"}, +{"pdbcc", two(0xf048, 0x000f), two(0xfff8, 0xffff), "DsBw"}, +{"pdbcs", two(0xf048, 0x000e), two(0xfff8, 0xffff), "DsBw"}, +{"pdbgc", two(0xf048, 0x000d), two(0xfff8, 0xffff), "DsBw"}, +{"pdbgs", two(0xf048, 0x000c), two(0xfff8, 0xffff), "DsBw"}, +{"pdbic", two(0xf048, 0x000b), two(0xfff8, 0xffff), "DsBw"}, +{"pdbis", two(0xf048, 0x000a), two(0xfff8, 0xffff), "DsBw"}, +{"pdblc", two(0xf048, 0x0003), two(0xfff8, 0xffff), "DsBw"}, +{"pdbls", two(0xf048, 0x0002), two(0xfff8, 0xffff), "DsBw"}, +{"pdbsc", two(0xf048, 0x0005), two(0xfff8, 0xffff), "DsBw"}, +{"pdbss", two(0xf048, 0x0004), two(0xfff8, 0xffff), "DsBw"}, +{"pdbwc", two(0xf048, 0x0009), two(0xfff8, 0xffff), "DsBw"}, +{"pdbws", two(0xf048, 0x0008), two(0xfff8, 0xffff), "DsBw"}, + +{"pflusha", two(0xf000, 0x2400), two(0xffff, 0xffff), "" }, + +{"pflush", two(0xf000, 0x3010), two(0xffc0, 0xfe10), "T3T9" }, +{"pflush", two(0xf000, 0x3810), two(0xffc0, 0xfe10), "T3T9&s" }, +{"pflush", two(0xf000, 0x3008), two(0xffc0, 0xfe18), "D3T9" }, +{"pflush", two(0xf000, 0x3808), two(0xffc0, 0xfe18), "D3T9&s" }, +{"pflush", two(0xf000, 0x3000), two(0xffc0, 0xfe1e), "f3T9" }, +{"pflush", two(0xf000, 0x3800), two(0xffc0, 0xfe1e), "f3T9&s" }, + +{"pflushs", two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9" }, +{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe00), "T3T9&s" }, +{"pflushs", two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9" }, +{"pflushs", two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s" }, +{"pflushs", two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9" }, +{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s"}, + +{"pflushr", two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s" }, + +{"ploadr", two(0xf000, 0x2210), two(0xffc0, 0xfff0), "T3&s" }, +{"ploadr", two(0xf000, 0x2208), two(0xffc0, 0xfff8), "D3&s" }, +{"ploadr", two(0xf000, 0x2200), two(0xffc0, 0xfffe), "f3&s" }, +{"ploadw", two(0xf000, 0x2010), two(0xffc0, 0xfff0), "T3&s" }, +{"ploadw", two(0xf000, 0x2008), two(0xffc0, 0xfff8), "D3&s" }, +{"ploadw", two(0xf000, 0x2000), two(0xffc0, 0xfffe), "f3&s" }, + + /* TC, CRP, DRP, SRP, CAL, VAL, SCC, AC */ +{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "*sP8" }, +{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "P8%s" }, +{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "|sW8" }, +{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "W8~s" }, + + /* BADx, BACx */ +{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xe3e3), "*sX3" }, +{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xe3e3), "X3%s" }, + + /* PSR, PCSR */ + /* {"pmove", two(0xf000, 0x6100), two(oxffc0, oxffff), "*sZ8" }, */ +{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xffff), "*sY8" }, +{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xffff), "Y8%s" }, +{"pmove", two(0xf000, 0x6600), two(0xffc0, 0xffff), "Z8%s" }, + +{"prestore", one(0xf140), one(0xffc0), "&s"}, +{"prestore", one(0xf158), one(0xfff8), "+s"}, +{"psave", one(0xf100), one(0xffc0), "&s"}, +{"psave", one(0xf100), one(0xffc0), "+s"}, + +{"psac", two(0xf040, 0x0007), two(0xffc0, 0xffff), "@s"}, +{"psas", two(0xf040, 0x0006), two(0xffc0, 0xffff), "@s"}, +{"psbc", two(0xf040, 0x0001), two(0xffc0, 0xffff), "@s"}, +{"psbs", two(0xf040, 0x0000), two(0xffc0, 0xffff), "@s"}, +{"pscc", two(0xf040, 0x000f), two(0xffc0, 0xffff), "@s"}, +{"pscs", two(0xf040, 0x000e), two(0xffc0, 0xffff), "@s"}, +{"psgc", two(0xf040, 0x000d), two(0xffc0, 0xffff), "@s"}, +{"psgs", two(0xf040, 0x000c), two(0xffc0, 0xffff), "@s"}, +{"psic", two(0xf040, 0x000b), two(0xffc0, 0xffff), "@s"}, +{"psis", two(0xf040, 0x000a), two(0xffc0, 0xffff), "@s"}, +{"pslc", two(0xf040, 0x0003), two(0xffc0, 0xffff), "@s"}, +{"psls", two(0xf040, 0x0002), two(0xffc0, 0xffff), "@s"}, +{"pssc", two(0xf040, 0x0005), two(0xffc0, 0xffff), "@s"}, +{"psss", two(0xf040, 0x0004), two(0xffc0, 0xffff), "@s"}, +{"pswc", two(0xf040, 0x0009), two(0xffc0, 0xffff), "@s"}, +{"psws", two(0xf040, 0x0008), two(0xffc0, 0xffff), "@s"}, + +{"ptestr", two(0xf000, 0x8210), two(0xffc0, 0xe3f0), "T3&sQ8" }, +{"ptestr", two(0xf000, 0x8310), two(0xffc0, 0xe310), "T3&sQ8A9" }, +{"ptestr", two(0xf000, 0x8208), two(0xffc0, 0xe3f8), "D3&sQ8" }, +{"ptestr", two(0xf000, 0x8308), two(0xffc0, 0xe318), "D3&sQ8A9" }, +{"ptestr", two(0xf000, 0x8200), two(0xffc0, 0xe3fe), "f3&sQ8" }, +{"ptestr", two(0xf000, 0x8300), two(0xffc0, 0xe31e), "f3&sQ8A9" }, + +{"ptestw", two(0xf000, 0x8010), two(0xffc0, 0xe3f0), "T3&sQ8" }, +{"ptestw", two(0xf000, 0x8110), two(0xffc0, 0xe310), "T3&sQ8A9" }, +{"ptestw", two(0xf000, 0x8008), two(0xffc0, 0xe3f8), "D3&sQ8" }, +{"ptestw", two(0xf000, 0x8108), two(0xffc0, 0xe318), "D3&sQ8A9" }, +{"ptestw", two(0xf000, 0x8000), two(0xffc0, 0xe3fe), "f3&sQ8" }, +{"ptestw", two(0xf000, 0x8100), two(0xffc0, 0xe31e), "f3&sQ8A9" }, + +{"ptrapacw", two(0xf07a, 0x0007), two(0xffff, 0xffff), "#w"}, +{"ptrapacl", two(0xf07b, 0x0007), two(0xffff, 0xffff), "#l"}, +{"ptrapac", two(0xf07c, 0x0007), two(0xffff, 0xffff), ""}, + +{"ptrapasw", two(0xf07a, 0x0006), two(0xffff, 0xffff), "#w"}, +{"ptrapasl", two(0xf07b, 0x0006), two(0xffff, 0xffff), "#l"}, +{"ptrapas", two(0xf07c, 0x0006), two(0xffff, 0xffff), ""}, + +{"ptrapbcw", two(0xf07a, 0x0001), two(0xffff, 0xffff), "#w"}, +{"ptrapbcl", two(0xf07b, 0x0001), two(0xffff, 0xffff), "#l"}, +{"ptrapbc", two(0xf07c, 0x0001), two(0xffff, 0xffff), ""}, + +{"ptrapbsw", two(0xf07a, 0x0000), two(0xffff, 0xffff), "#w"}, +{"ptrapbsl", two(0xf07b, 0x0000), two(0xffff, 0xffff), "#l"}, +{"ptrapbs", two(0xf07c, 0x0000), two(0xffff, 0xffff), ""}, + +{"ptrapccw", two(0xf07a, 0x000f), two(0xffff, 0xffff), "#w"}, +{"ptrapccl", two(0xf07b, 0x000f), two(0xffff, 0xffff), "#l"}, +{"ptrapcc", two(0xf07c, 0x000f), two(0xffff, 0xffff), ""}, + +{"ptrapcsw", two(0xf07a, 0x000e), two(0xffff, 0xffff), "#w"}, +{"ptrapcsl", two(0xf07b, 0x000e), two(0xffff, 0xffff), "#l"}, +{"ptrapcs", two(0xf07c, 0x000e), two(0xffff, 0xffff), ""}, + +{"ptrapgcw", two(0xf07a, 0x000d), two(0xffff, 0xffff), "#w"}, +{"ptrapgcl", two(0xf07b, 0x000d), two(0xffff, 0xffff), "#l"}, +{"ptrapgc", two(0xf07c, 0x000d), two(0xffff, 0xffff), ""}, + +{"ptrapgsw", two(0xf07a, 0x000c), two(0xffff, 0xffff), "#w"}, +{"ptrapgsl", two(0xf07b, 0x000c), two(0xffff, 0xffff), "#l"}, +{"ptrapgs", two(0xf07c, 0x000c), two(0xffff, 0xffff), ""}, + +{"ptrapicw", two(0xf07a, 0x000b), two(0xffff, 0xffff), "#w"}, +{"ptrapicl", two(0xf07b, 0x000b), two(0xffff, 0xffff), "#l"}, +{"ptrapic", two(0xf07c, 0x000b), two(0xffff, 0xffff), ""}, + +{"ptrapisw", two(0xf07a, 0x000a), two(0xffff, 0xffff), "#w"}, +{"ptrapisl", two(0xf07b, 0x000a), two(0xffff, 0xffff), "#l"}, +{"ptrapis", two(0xf07c, 0x000a), two(0xffff, 0xffff), ""}, + +{"ptraplcw", two(0xf07a, 0x0003), two(0xffff, 0xffff), "#w"}, +{"ptraplcl", two(0xf07b, 0x0003), two(0xffff, 0xffff), "#l"}, +{"ptraplc", two(0xf07c, 0x0003), two(0xffff, 0xffff), ""}, + +{"ptraplsw", two(0xf07a, 0x0002), two(0xffff, 0xffff), "#w"}, +{"ptraplsl", two(0xf07b, 0x0002), two(0xffff, 0xffff), "#l"}, +{"ptrapls", two(0xf07c, 0x0002), two(0xffff, 0xffff), ""}, + +{"ptrapscw", two(0xf07a, 0x0005), two(0xffff, 0xffff), "#w"}, +{"ptrapscl", two(0xf07b, 0x0005), two(0xffff, 0xffff), "#l"}, +{"ptrapsc", two(0xf07c, 0x0005), two(0xffff, 0xffff), ""}, + +{"ptrapssw", two(0xf07a, 0x0004), two(0xffff, 0xffff), "#w"}, +{"ptrapssl", two(0xf07b, 0x0004), two(0xffff, 0xffff), "#l"}, +{"ptrapss", two(0xf07c, 0x0004), two(0xffff, 0xffff), ""}, + +{"ptrapwcw", two(0xf07a, 0x0009), two(0xffff, 0xffff), "#w"}, +{"ptrapwcl", two(0xf07b, 0x0009), two(0xffff, 0xffff), "#l"}, +{"ptrapwc", two(0xf07c, 0x0009), two(0xffff, 0xffff), ""}, + +{"ptrapwsw", two(0xf07a, 0x0008), two(0xffff, 0xffff), "#w"}, +{"ptrapwsl", two(0xf07b, 0x0008), two(0xffff, 0xffff), "#l"}, +{"ptrapws", two(0xf07c, 0x0008), two(0xffff, 0xffff), ""}, + +{"pvalid", two(0xf000, 0x2800), two(0xffc0, 0xffff), "Vs&s"}, +{"pvalid", two(0xf000, 0x2c00), two(0xffc0, 0xfff8), "A3&s" }, + +#endif /* m68851 */ + +/* end of tc-m68851.h */ diff --git a/gnu/usr.bin/as/config/tc-m68k.c b/gnu/usr.bin/as/config/tc-m68k.c new file mode 100644 index 000000000000..2dac35b3bcbe --- /dev/null +++ b/gnu/usr.bin/as/config/tc-m68k.c @@ -0,0 +1,4076 @@ +/* tc-m68k.c All the m68020 specific stuff in one convenient, huge, + slow to compile, easy to find file. + + Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <ctype.h> + +#include "as.h" + +#include "obstack.h" + +/* note that this file includes real declarations and thus can only be included by one source file per executable. */ +#include "opcode/m68k.h" +#ifdef TE_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 comments like this one will always work. */ +const char line_comment_chars[] = "#"; + +/* Chars that can be used to separate mant from exp in floating point nums */ +const char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant */ +/* As in 0f12.456 */ +/* or 0d1.2345e12 */ + +const char FLT_CHARS[] = "rRsSfFdDxXeEpP"; + +/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be + changed in read.c. Ideally it shouldn't have to know about it at all, + but nothing is ideal around here. + */ + +int md_reloc_size = 8; /* Size of relocation record */ + +/* Its an arbitrary name: This means I don't approve of it */ +/* See flames below */ +static struct obstack robyn; + +#define TAB(x,y) (((x)<<2)+(y)) +#define TABTYPE(xy) ((xy) >> 2) +#define BYTE 0 +#define SHORT 1 +#define LONG 2 +#define SZ_UNDEF 3 + +#define BRANCH 1 +#define FBRANCH 2 +#define PCREL 3 +#define BCC68000 4 +#define DBCC 5 +#define PCLEA 6 + +/* 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) + + */ + +enum operand_type { + IMMED = 1, + DREG, + AREG, + AINDR, + ADEC, + AINC, + AOFF, + AINDX, + APODX, + AMIND, + APRDX, + ABSL, + MSCR, + REGLST, +}; + + +struct m68k_exp { + char *e_beg; + char *e_end; + expressionS e_exp; + short e_siz; /* 0 == default 1 == short/byte 2 == word 3 == long */ +}; + +/* 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 */ + +enum _register { + DATA = 1, /* 1- 8 == data registers 0-7 */ + DATA0 = DATA, + DATA1, + DATA2, + DATA3, + DATA4, + DATA5, + DATA6, + DATA7, + + ADDR, + ADDR0 = ADDR, + ADDR1, + ADDR2, + ADDR3, + ADDR4, + ADDR5, + ADDR6, + ADDR7, + + /* Note that COPNUM == processor #1 -- COPNUM+7 == #8, which stores as 000 */ + /* I think... */ + + SP = ADDR7, + + FPREG, /* Eight FP registers */ + FP0 = FPREG, + FP1, + FP2, + FP3, + FP4, + FP5, + FP6, + FP7, + COPNUM = (FPREG+8), /* Co-processor #1-#8 */ + COP0 = COPNUM, + COP1, + COP2, + COP3, + COP4, + COP5, + COP6, + COP7, + PC, /* Program counter */ + ZPC, /* Hack for Program space, but 0 addressing */ + SR, /* Status Reg */ + CCR, /* Condition code Reg */ + + /* These have to be in order for the movec instruction to work. */ + USP, /* User Stack Pointer */ + ISP, /* Interrupt stack pointer */ + SFC, + DFC, + CACR, + VBR, + CAAR, + MSP, + ITT0, + ITT1, + DTT0, + DTT1, + MMUSR, + TC, + SRP, + URP, + /* end of movec ordering constraints */ + + FPI, + FPS, + FPC, + + DRP, + CRP, + CAL, + VAL, + SCC, + AC, + BAD, + BAD0 = BAD, + BAD1, + BAD2, + BAD3, + BAD4, + BAD5, + BAD6, + BAD7, + BAC, + BAC0 = BAC, + BAC1, + BAC2, + BAC3, + BAC4, + BAC5, + BAC6, + BAC7, + PSR, + PCSR, + + IC, /* instruction cache token */ + DC, /* data cache token */ + NC, /* no cache token */ + BC, /* both caches token */ + +}; + +/* Internal form of an operand. */ +struct m68k_op { + char *error; /* Couldn't parse it */ + enum operand_type mode; /* What mode this instruction is in. */ + enum _register 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 m68k_it { + char *error; + char *args; /* list of opcode info */ + int numargs; + + int numo; /* Number of shorts in opcode */ + short opcode[11]; + + struct m68k_op operands[6]; + + int nexp; /* number of exprs in use */ + struct m68k_exp exprs[4]; + + int nfrag; /* Number of frags we have to produce */ + struct { + int fragoff; /* Where in the current opcode[] the frag ends */ + symbolS *fadd; + long foff; + int fragty; + } fragb[4]; + + int nrel; /* Num of reloc strucs in use */ + struct { + int n; + symbolS *add, + *sub, + *got; + long off; + char wid; + char pcrel; + enum reloc_type rtype; + } reloc[5]; /* Five is enough??? */ +}; + +#define cpu_of_arch(x) ((x) & m68000up) +#define float_of_arch(x) ((x) & mfloat) +#define mmu_of_arch(x) ((x) & mmmu) + +static struct m68k_it the_ins; /* the instruction being assembled */ + +/* Macros for adding things to the m68k_it struct */ + +#define addword(w) the_ins.opcode[the_ins.numo++]=(w) + +/* Like addword, but goes BEFORE general operands */ +#define insop(w) { \ + int z; \ + for (z=the_ins.numo;z>opcode->m_codenum;--z) \ + the_ins.opcode[z]=the_ins.opcode[z-1]; \ + for (z=0;z<the_ins.nrel;z++) \ + the_ins.reloc[z].n+=2; \ + the_ins.opcode[opcode->m_codenum]=w; \ + the_ins.numo++; \ + } + + +#define add_exp(beg,end) (the_ins.exprs[the_ins.nexp].e_beg=beg, \ + the_ins.exprs[the_ins.nexp].e_end=end, \ + &the_ins.exprs[the_ins.nexp++] \ + ) + + +/* The numo+1 kludge is so we can hit the low order byte of the prev word. Blecch*/ +#define add_fix(width, exp, pc_rel, r_type) { \ + 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].got=gots((exp)); \ + the_ins.reloc[the_ins.nrel].wid=width; \ + the_ins.reloc[the_ins.nrel].pcrel=pc_rel; \ + the_ins.reloc[the_ins.nrel++].rtype=r_type; \ + } + +#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) || gots(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) +#define gots(exp) ((exp)->e_exp.X_got_symbol) + + +struct m68k_incant { + char *m_operands; + unsigned long m_opcode; + short m_opnum; + short m_codenum; + enum m68k_architecture m_arch; + struct m68k_incant *m_next; +}; + +#define getone(x) ((((x)->m_opcode)>>16)&0xffff) +#define gettwo(x) (((x)->m_opcode)&0xffff) + + +#if __STDC__ == 1 + +static char *crack_operand(char *str, struct m68k_op *opP); +static int get_num(struct m68k_exp *exp, int ok); +static int get_regs(int i, char *str, struct m68k_op *opP); +static int reverse_16_bits(int in); +static int reverse_8_bits(int in); +static int try_index(char **s, struct m68k_op *opP); +static void install_gen_operand(int mode, int val); +static void install_operand(int mode, int val); +static void s_bss(void); +static void s_data1(void); +static void s_data2(void); +static void s_even(void); +static void s_proc(void); + +#else /* not __STDC__ */ + +static char *crack_operand(); +static int get_num(); +static int get_regs(); +static int reverse_16_bits(); +static int reverse_8_bits(); +static int try_index(); +static void install_gen_operand(); +static void install_operand(); +static void s_bss(); +static void s_data1(); +static void s_data2(); +static void s_even(); +static void s_proc(); + +#endif /* not __STDC__ */ + +static enum m68k_architecture current_architecture = 0; + +/* BCC68000 is for patching in an extra jmp instruction for long offsets + on the 68000. The 68000 doesn't support long branches with branchs */ + +/* This table desribes how you change sizes for the various types of variable + size expressions. This version only supports two kinds. */ + +/* Note that calls to frag_var need to specify the maximum expansion needed */ +/* This is currently 10 bytes for DBCC */ + +/* The fields are: + How far Forward this mode will reach: + How far Backward this mode will reach: + How many bytes this mode will add to the size of the frag + Which mode to go to if the offset won't fit in this one + */ +const relax_typeS + md_relax_table[] = { + { 1, 1, 0, 0 }, /* First entries aren't used */ + { 1, 1, 0, 0 }, /* For no good reason except */ + { 1, 1, 0, 0 }, /* that the VAX doesn't either */ + { 1, 1, 0, 0 }, + + { (127), (-128), 0, TAB(BRANCH,SHORT)}, + { (32767), (-32768), 2, TAB(BRANCH,LONG) }, + { 0, 0, 4, 0 }, + { 1, 1, 0, 0 }, + + { 1, 1, 0, 0 }, /* FBRANCH doesn't come BYTE */ + { (32767), (-32768), 2, TAB(FBRANCH,LONG)}, + { 0, 0, 4, 0 }, + { 1, 1, 0, 0 }, + + { 1, 1, 0, 0 }, /* PCREL doesn't come BYTE */ + { (32767), (-32768), 2, TAB(PCREL,LONG)}, + { 0, 0, 4, 0 }, + { 1, 1, 0, 0 }, + + { (127), (-128), 0, TAB(BCC68000,SHORT)}, + { (32767), (-32768), 2, TAB(BCC68000,LONG) }, + { 0, 0, 6, 0 }, /* jmp long space */ + { 1, 1, 0, 0 }, + + { 1, 1, 0, 0 }, /* DBCC doesn't come BYTE */ + { (32767), (-32768), 2, TAB(DBCC,LONG) }, + { 0, 0, 10, 0 }, /* bra/jmp long space */ + { 1, 1, 0, 0 }, + + { 1, 1, 0, 0 }, /* PCLEA doesn't come BYTE */ + { 32767, -32768, 2, TAB(PCLEA,LONG) }, + { 0, 0, 6, 0 }, + { 1, 1, 0, 0 }, + + }; + +/* These are the machine dependent pseudo-ops. These are included so + the assembler can work on the output from the SUN C compiler, which + generates these. + */ + +/* This table describes all the machine specific pseudo-ops the assembler + has to support. The fields are: + pseudo-op name without dot + function to call to execute this pseudo-op + Integer arg to pass to the function + */ +const pseudo_typeS md_pseudo_table[] = { + { "data1", s_data1, 0 }, + { "data2", s_data2, 0 }, + { "bss", s_bss, 0 }, + { "even", s_even, 0 }, + { "skip", s_space, 0 }, + { "proc", s_proc, 0 }, + { 0, 0, 0 } +}; + + +/* #define isbyte(x) ((x) >= -128 && (x) <= 127) */ +/* #define isword(x) ((x) >= -32768 && (x) <= 32767) */ + +#define issbyte(x) ((x) >= -128 && (x) <= 127) +#define isubyte(x) ((x) >= 0 && (x) <= 255) +#define issword(x) ((x) >= -32768 && (x) <= 32767) +#define isuword(x) ((x) >= 0 && (x) <= 65535) + +#define isbyte(x) ((x) >= -128 && (x) <= 255) +#define isword(x) ((x) >= -32768 && (x) <= 65535) +#define islong(x) (1) + +extern char *input_line_pointer; + +enum { + FAIL = 0, + OK = 1, +}; + +/* 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 + +/* Handle the extra arg for fix_new when doing PIC */ +#ifdef PIC +#define FIX_NO_RELOC NO_RELOC, NULL +#else +#define FIX_NO_RELOC NO_RELOC +#endif /* PIC */ + + +/* JF modified this to handle cases where the first part of a symbol name + looks like a register */ + +/* + * m68k_reg_parse() := if it looks like a register, return it's token & + * advance the pointer. + */ + +enum _register m68k_reg_parse(ccp) +register char **ccp; +{ +#ifndef MAX_REG_NAME_LEN +#define MAX_REG_NAME_LEN (6) +#endif /* MAX_REG_NAME_LEN */ + register char c[MAX_REG_NAME_LEN]; + char *p, *q; + register int n = 0, + ret = FAIL; + + c[0] = mklower(ccp[0][0]); +#ifdef REGISTER_PREFIX + if (c[0] != REGISTER_PREFIX) { + return(FAIL); + } /* need prefix */ +#endif + + for (p = c, q = ccp[0]; p < c + MAX_REG_NAME_LEN; ++p, ++q) + { + if (*q == 0) + { + *p = 0; + break; + } + else + *p = mklower(*q); + } /* downcase */ + + switch (c[0]) { + case 'a': + if (c[1] >= '0' && c[1] <= '7') { + n=2; + ret=ADDR+c[1]-'0'; + } +#ifndef NO_68851 + else if (c[1] == 'c') { + n = 2; + ret = AC; + } +#endif + break; +#ifndef NO_68851 + case 'b': + if (c[1] == 'a') { + if (c[2] == 'd') { + if (c[3] >= '0' && c[3] <= '7') { + n = 4; + ret = BAD + c[3] - '0'; + } + } /* BAD */ + if (c[2] == 'c') { + if (c[3] >= '0' && c[3] <= '7') { + n = 4; + ret = BAC + c[3] - '0'; + } + } /* BAC */ + } else if (c[1] == 'c') { + n = 2; + ret = BC; + } /* BC */ + break; +#endif + case 'c': +#ifndef NO_68851 + if (c[1] == 'a' && c[2] == 'l') { + n = 3; + ret = CAL; + } else +#endif + /* This supports both CCR and CC as the ccr reg. */ + if (c[1] == 'c' && c[2] == 'r') { + n=3; + ret = CCR; + } else if (c[1] == 'c') { + n=2; + ret = CCR; + } else if (c[1] == 'a' && (c[2] == 'a' || c[2] == 'c') && c[3] == 'r') { + n=4; + ret = c[2] == 'a' ? CAAR : CACR; + } +#ifndef NO_68851 + else if (c[1] == 'r' && c[2] == 'p') { + n = 3; + ret = (CRP); + } +#endif + break; + case 'd': + if (c[1] >= '0' && c[1] <= '7') { + n = 2; + ret = DATA + c[1] - '0'; + } else if (c[1] == 'f' && c[2] == 'c') { + n = 3; + ret = DFC; + } else if (c[1] == 'c') { + n = 2; + ret = DC; + } else if (c[1] == 't' && c[2] == 't') { + if ('0' <= c[3] && c[3] <= '1') { + n = 4; + ret = DTT0 + (c[3] - '0'); + } /* DTT[01] */ + } +#ifndef NO_68851 + else if (c[1] == 'r' && c[2] == 'p') { + n = 3; + ret = (DRP); + } +#endif + break; + case 'f': + if (c[1] == 'p') { + if (c[2] >= '0' && c[2] <= '7') { + n=3; + ret = FPREG+c[2]-'0'; + if (c[3] == ':') + ccp[0][3]=','; + } else if (c[2] == 'i') { + n=3; + ret = FPI; + } else if (c[2] == 's') { + n= (c[3] == 'r' ? 4 : 3); + ret = FPS; + } else if (c[2] == 'c') { + n= (c[3] == 'r' ? 4 : 3); + ret = FPC; + } + } + break; + case 'i': + if (c[1] == 's' && c[2] == 'p') { + n = 3; + ret = ISP; + } else if (c[1] == 'c') { + n = 2; + ret = IC; + } else if (c[1] == 't' && c[2] == 't') { + if ('0' <= c[3] && c[3] <= '1') { + n = 4; + ret = ITT0 + (c[3] - '0'); + } /* ITT[01] */ + } + break; + case 'm': + if (c[1] == 's' && c[2] == 'p') { + n = 3; + ret = MSP; + } else if (c[1] == 'm' && c[2] == 'u' && c[3] == 's' && c[4] == 'r') { + n = 5; + ret = MMUSR; + } + break; + case 'n': + if (c[1] == 'c') { + n = 2; + ret = NC; + } + break; + case 'p': + if (c[1] == 'c') { +#ifndef NO_68851 + if (c[2] == 's' && c[3] == 'r') { + n=4; + ret = (PCSR); + } else +#endif + { + n=2; + ret = PC; + } + } +#ifndef NO_68851 + else if (c[1] == 's' && c[2] == 'r') { + n = 3; + ret = (PSR); + } +#endif + break; + case 's': +#ifndef NO_68851 + if (c[1] == 'c' && c[2] == 'c') { + n = 3; + ret = (SCC); + } else +#endif + if (c[1] == 'r') { + if (c[2] == 'p') { + n = 3; + ret = SRP; + } else { + n = 2; + ret = SR; + } /* srp else sr */ + } else if (c[1] == 'p') { + n = 2; + ret = SP; + } else if (c[1] == 'f' && c[2] == 'c') { + n = 3; + ret = SFC; + } + break; + case 't': + if (c[1] == 'c') { + n = 2; + ret = TC; + } + break; + case 'u': + if (c[1] == 's' && c[2] == 'p') { + n=3; + ret = USP; + } else if (c[1] == 'r' && c[2] == 'p') { + n = 3; + ret = URP; + } + break; + case 'v': +#ifndef NO_68851 + if (c[1] == 'a' && c[2] == 'l') { + n = 3; + ret = (VAL); + } else +#endif + if (c[1] == 'b' && c[2] == 'r') { + n=3; + ret = VBR; + } + break; + case 'z': + if (c[1] == 'p' && c[2] == '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++;} + +/* + * m68k_ip_op := '#' + <anything> + * | <register> + range_sep + get_regs + * ; + * + * range_sep := '/' | '-' ; + * + * SKIP_WHITE := <empty> | ' ' ; + * + */ + +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 beginning of the string */ + + if (!*str) { + opP->error="Missing operand"; + return FAIL; + } /* Out of gas */ + + for (strend = str; *strend; strend++) ;; + + --strend; + + if (*str == '#') { + str++; + opP->con1=add_exp(str,strend); + opP->mode=IMMED; + return OK; + } /* Guess what: A constant. Shar and enjoy */ + + i = m68k_reg_parse(&str); + + /* is a register, is exactly a register, and is followed by '@' */ + + if ((i == FAIL || *str != '\0') && *str != '@') { + char *stmp; + + if (i != FAIL && (*str == '/' || *str == '-')) { + opP->mode=REGLST; + return(get_regs(i,str,opP)); + } + if ((stmp=strchr(str,'@')) != '\0') { + opP->con1=add_exp(str,stmp-1); + if (stmp == strend) { + opP->mode=AINDX; + return(OK); + } + + if ((current_architecture & m68020up) == 0) { + return(FAIL); + } /* if target is not a '20 or better */ + + 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); + } /* if there's an '@' */ + opP->mode = ABSL; + opP->con1 = add_exp(str,strend); + return(OK); + } /* not a register, not exactly a register, or no '@' */ + + opP->reg=i; + + if (*str == '\0') { + if (i >= DATA+0 && i <= DATA+7) + opP->mode=DREG; + else if (i >= ADDR+0 && i <= ADDR+7) + opP->mode=AREG; + else + opP->mode=MSCR; + return OK; + } + + if ((i<ADDR+0 || i>ADDR+7) && i != PC && i != ZPC && i != FAIL) { /* Can't indirect off non address regs */ + opP->error="Invalid indirect register"; + return FAIL; + } + know(*str == '@'); + + 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); + } + + if ((current_architecture & m68020up) == 0) { + return(FAIL); + } /* if target is not a '20 or better */ + + 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); +} /* m68k_ip_op() */ + +/* + * + * try_index := data_or_address_register + ')' + SKIP_W + * | data_or_address_register + ':' + SKIP_W + size_spec + SKIP_W + multiplier + ')' + SKIP_W + * + * multiplier := <empty> + * | ':' + multiplier_number + * ; + * + * multiplier_number := '1' | '2' | '4' | '8' ; + * + * size_spec := 'l' | 'L' | 'w' | 'W' ; + * + * SKIP_W := <empty> | ' ' ; + * + */ + +static int try_index(s,opP) +char **s; +struct m68k_op *opP; +{ + register int i; + char *ss; +#define SKIP_W() { ss++; if (*ss == ' ') ss++;} + + ss= *s; + /* SKIP_W(); */ + i=m68k_reg_parse(&ss); + if (!(i >= DATA+0 && i <= ADDR+7)) { /* if i is not DATA or ADDR reg */ + *s=ss; + return FAIL; + } + opP->ireg=i; + /* SKIP_W(); */ + if (*ss == ')') { + opP->isiz=0; + opP->imul=1; + SKIP_W(); + *s=ss; + return OK; + } + if (*ss != ':') { + opP->error="Missing : in index register"; + *s=ss; + return FAIL; + } + SKIP_W(); + switch (*ss) { + case 'w': + case 'W': + opP->isiz=2; + break; + case 'l': + case 'L': + opP->isiz=3; + break; + default: + opP->error="Index register size spec not :w or :l"; + *s=ss; + return FAIL; + } + SKIP_W(); + if (*ss == ':') { + SKIP_W(); + switch (*ss) { + case '1': + case '2': + case '4': + case '8': + opP->imul= *ss-'0'; + break; + default: + opP->error="index multiplier not 1, 2, 4 or 8"; + *s=ss; + return FAIL; + } + SKIP_W(); + } else opP->imul=1; + if (*ss != ')') { + opP->error="Missing )"; + *s=ss; + return FAIL; + } + SKIP_W(); + *s=ss; + return OK; +} /* try_index() */ + +#ifdef TEST1 /* TEST1 tests m68k_ip_op(), which parses operands */ +main() +{ + char buf[128]; + struct m68k_op thark; + + for (;;) { + if (!gets(buf)) + break; + memset(&thark, '\0', 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 m68k_ip_begin() + will crash */ + + +/* + * m 6 8 k _ 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 m68k_ip_begin() once and m86_ip_end() never before using + * this function. + */ + +/* JF this function no longer returns a useful value. Sorry */ +void m68k_ip (instring) +char *instring; +{ + register char *p; + register struct m68k_op *opP; + register struct m68k_incant *opcode; + register char *s; + register int tmpreg = 0, + baseo = 0, + outro = 0, + nextword; + int siz1, + siz2; + char c; + int losing; + int opsfound; + int reloc_type; + 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 m68k_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 */ + while (*p == ' ') ++p; + + 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]; + + /* memcpy((char *)(&the_ins.operands[1]), (char *)(&the_ins.operands[0]), opsfound*sizeof(the_ins.operands[0])); */ + memset((char *)(&the_ins.operands[0]), '\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 we didn't get the right number of ops, + or we have no common model with this pattern + then reject this pattern. */ + + if (opsfound != opcode->m_opnum + || ((opcode->m_arch & current_architecture) == 0)) { + + ++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) { +#ifdef PIC + case ' ': + /* this operand is just here to indicate a jump-table branch */ + if (!flagseen['k']) + losing++; + break; +#endif /* PIC */ + + 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 'a': + if (opP->mode != AINDR) { + ++losing; + } /* if not address register indirect */ + break; + case 'B': /* FOO */ + if (opP->mode != ABSL || (flagseen['S'] && instring[0] == 'j' + && instring[1] == 'b' + && instring[2] == 's' + && instring[3] == 'r')) + losing++; + break; + + case 'C': + if (opP->mode != MSCR || opP->reg != CCR) + losing++; + break; + + case 'd': /* FOO This mode is a KLUDGE!! */ + if (opP->mode != AOFF && (opP->mode != ABSL || + opP->con1->e_beg[0] != '(' || opP->con1->e_end[0] != ')')) + losing++; + break; + + case 'D': + if (opP->mode != DREG) + losing++; + break; + + case 'F': + if (opP->mode != MSCR || opP->reg<(FPREG+0) || opP->reg>(FPREG+7)) + losing++; + break; + + case 'I': + if (opP->mode != MSCR || opP->reg<COPNUM || + opP->reg >= COPNUM+7) + losing++; + break; + + case 'J': + if (opP->mode != MSCR + || opP->reg < USP + || opP->reg > URP + || cpu_of_arch(current_architecture) < m68010 /* before 68010 had none */ + || (cpu_of_arch(current_architecture) < m68020 + && opP->reg != SFC + && opP->reg != DFC + && opP->reg != USP + && opP->reg != VBR) /* 68010's had only these */ + || (cpu_of_arch(current_architecture) < m68040 + && opP->reg != SFC + && opP->reg != DFC + && opP->reg != USP + && opP->reg != VBR + && opP->reg != CACR + && opP->reg != CAAR + && opP->reg != MSP + && opP->reg != ISP) /* 680[23]0's have only these */ + || (cpu_of_arch(current_architecture) == m68040 /* 68040 has all but this */ + && opP->reg == CAAR)) { + losing++; + } /* doesn't cut it */ + 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 */ +#ifndef NO_68851 + /* 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 + case 'c': + if (opP->reg != NC + && opP->reg != IC + && opP->reg != DC + && opP->reg != BC) { + losing++; + } /* not a cache specifier. */ + break; + + case '_': + if (opP->mode != ABSL) { + ++losing; + } /* not absolute */ + break; + + default: + as_fatal("Internal error: Operand mode %c unknown in line %s of file \"%s\"", + *s, __LINE__, __FILE__); + } /* switch on type of operand */ + + if (losing) break; + } /* for each operand */ + } /* if immediately wrong */ + + if (!losing) { + break; + } /* got it. */ + + opcode = opcode->m_next; + + if (!opcode) { + the_ins.error = "instruction/operands mismatch"; + return; + } /* Fell off the end */ + + losing = 0; + } + + /* now assemble it */ + + 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. + Watch the first step; its a big one! */ + switch (s[0]) { + +#ifdef PIC + case ' ': + /* this operand is just here to indicate a jump-table branch */ + break; +#endif /* PIC */ + + case '*': + case '~': + case '%': + case ';': + case '@': + case '!': + case '&': + case '$': + case '?': + case '/': +#ifndef NO_68851 + case '|': +#endif + +#ifdef PIC + /* Use GLOB_DAT for operand references in PIC mode */ + if (flagseen['k']) + reloc_type = RELOC_GLOB_DAT; + else +#endif /* PIC */ + reloc_type = NO_RELOC; + + switch (opP->mode) { + case IMMED: + tmpreg=0x3c; /* 7.4 */ + if (strchr("bwl",s[1])) nextword=get_num(opP->con1,80); + else nextword=nextword=get_num(opP->con1,0); + if (isvar(opP->con1)) { +#ifdef PIC + /* KLUDGE!!! In PIC assembly, an immediate reference to + __GLOBAL_OFFSET_TABLE_ is turned into a pc-relative + reference to __GLOBAL_OFFSET_TABLE_ - 6, + for the sake of Sun compatibility. */ + if (s[1] == 'l' && flagseen['k'] && gots(opP->con1)) { + offs(opP->con1) -= 6; + add_fix(s[1], opP->con1, 1, NO_RELOC); + } else +#endif /* PIC */ + add_fix(s[1],opP->con1,0,reloc_type); + } + switch (s[1]) { + case 'b': + if (!isbyte(nextword)) + opP->error="operand out of range"; + addword(nextword); + baseo=0; + break; + case 'w': + if (!isword(nextword)) + opP->error="operand out of range"; + addword(nextword); + baseo=0; + break; + case 'l': + addword(nextword>>16); + addword(nextword); + baseo=0; + break; + + case 'f': + baseo=2; + outro=8; + break; + case 'F': + baseo=4; + outro=11; + break; + case 'x': + baseo=6; + outro=15; + break; + case 'p': + baseo=6; + outro= -1; + break; + default: + as_fatal("Internal error: Can't decode %c%c in line %s of file \"%s\"", + *s, s[1], __LINE__, __FILE__); + } + if (!baseo) + break; + + /* We gotta put out some float */ + if (seg(opP->con1) != SEG_BIG) { + int_to_gen(nextword); + gen_to_words(words,baseo,(long 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)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 && !subs(opP->con1)) { + add_frag(adds(opP->con1), + offs(opP->con1), + TAB(PCLEA,SZ_UNDEF)); + break; + } else { + addword(0x0170); + add_fix('l',opP->con1,0,reloc_type); + } + } 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,NO_RELOC); + } else + add_fix('w',opP->con1,0,reloc_type); + } + } + addword(nextword); + break; + + case APODX: + case AMIND: + case APRDX: + know(current_architecture & m68020up); + /* intentional fall-through */ + case AINDX: + 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: as_fatal("failed sanity check."); + } + /* 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,reloc_type); + 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. If so, 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,NO_RELOC); + opP->con1->e_exp.X_add_number+=6; + } else + add_fix(siz1 == 3 ? 'l' : 'w',opP->con1,0,reloc_type); + } + 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,NO_RELOC); + opP->con1->e_exp.X_add_number+=6; + } else + add_fix(siz2 == 3 ? 'l' : 'w',opP->con2,0,reloc_type); + } + 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 + && cpu_of_arch(current_architecture) >= m68020 + && !flagseen['S'] + && !strchr("~%&$?", s[0])) { + tmpreg=0x3A; /* 7.2 */ + add_frag(adds(opP->con1), + offs(opP->con1), + TAB(PCREL,SZ_UNDEF)); + break; + } + case 3: /* Fall through into long */ + if (isvar(opP->con1)) + add_fix('l',opP->con1,0,NO_RELOC); + + tmpreg=0x39; /* 7.1 mode */ + addword(nextword>>16); + addword(nextword); + break; + + case 2: /* Word */ + if (isvar(opP->con1)) + add_fix('w',opP->con1,0,NO_RELOC); + + 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,NO_RELOC); + switch (s[1]) { + case 'b': /* Danger: These do no check for + certain types of overflow. + user beware! */ + if (!isbyte(tmpreg)) + opP->error="out of range"; + insop(tmpreg); + if (isvar(opP->con1)) + the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2; + break; + case 'w': + if (!isword(tmpreg)) + opP->error="out of range"; + insop(tmpreg); + if (isvar(opP->con1)) + the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2; + break; + case 'l': + insop(tmpreg); /* Because of the way insop works, we put these two out backwards */ + insop(tmpreg>>16); + if (isvar(opP->con1)) + the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2; + break; + case '3': + tmpreg&=0xFF; + case '8': + case 'C': + install_operand(s[1],tmpreg); + break; + default: + as_fatal("Internal error: Unknown mode #%c in line %s of file \"%s\"", s[1], __LINE__, __FILE__); + } + break; + + case '+': + case '-': + case 'A': + case 'a': + install_operand(s[1], opP->reg - ADDR); + break; + + case 'B': + tmpreg = get_num(opP->con1, 80); + switch (s[1]) { + case 'B': + /* Offset is relative to next word */ + opP->con1->e_exp.X_add_number -= 1; + add_fix('B', opP->con1, 1,NO_RELOC); + break; + case 'W': + add_fix('w', opP->con1, 1,NO_RELOC); + addword(0); + break; + case 'L': + long_branch: + if (cpu_of_arch(current_architecture) < m68020) /* 68000 or 010 */ + as_warn("Can't use long branches on 68000/68010"); + the_ins.opcode[the_ins.numo-1]|=0xff; + add_fix('l',opP->con1,1,NO_RELOC); + addword(0); + addword(0); + break; + case 'g': +#ifdef PIC + /* If we have the optional kludgey 2nd operand, + make this go via the jump table. */ + if (flagseen['k'] && s[2] == ' ') { + the_ins.opcode[the_ins.numo-1] |= 0xFF; + add_fix('l', opP->con1, 1, RELOC_JMP_TBL); + addword(0); + addword(0); + break; + } +#endif /* PIC */ + if (subs(opP->con1)) /* We can't relax it */ + goto long_branch; + + /* This could either be a symbol, or an + absolute address. No matter, the + frag hacking will finger it out. + Not quite: it can't switch from + BRANCH to BCC68000 for the case + where opnd is absolute (it needs + to use the 68000 hack since no + conditional abs jumps). */ + if (((cpu_of_arch(current_architecture) < m68020) || (0 == adds(opP->con1))) + && (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)); + } + 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,NO_RELOC); + } + addword(0); + break; + case 'C': /* Fixed size LONG coproc branches */ + the_ins.opcode[the_ins.numo-1]|=0x40; + /* Offset the displacement to be relative to byte disp location */ + /* Coproc branches don't have a byte disp option, but they are + compatible with the ordinary branches, which do... */ + opP->con1->e_exp.X_add_number+=4; + add_fix('l',opP->con1,1,NO_RELOC); + addword(0); + addword(0); + break; + case 'c': /* Var size Coprocesssor branches */ + if (subs(opP->con1)) { + add_fix('l',opP->con1,1,NO_RELOC); + 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,NO_RELOC); + addword(0); + addword(4); + } + break; + default: + as_fatal("Internal error: operand type B%c unknown in line %s of file \"%s\"", + s[1], __LINE__, __FILE__); + } + break; + + case 'C': /* Ignore it */ + break; + + case 'd': /* JF this is a kludge */ + if (opP->mode == AOFF) { + install_operand('s',opP->reg-ADDR); + } else { + char *tmpP; + + tmpP=opP->con1->e_end-2; + opP->con1->e_beg++; + opP->con1->e_end-=4; /* point to the , */ + baseo=m68k_reg_parse(&tmpP); + if (baseo<ADDR+0 || baseo>ADDR+7) { + as_bad("Unknown address reg, using A0"); + baseo=0; + } else baseo-=ADDR; + install_operand('s',baseo); + } + tmpreg=get_num(opP->con1,80); + if (!issword(tmpreg)) { + as_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=0x000; break; + case DFC: tmpreg=0x001; break; + case CACR: tmpreg=0x002; break; + case TC: tmpreg=0x003; break; + case ITT0: tmpreg=0x004; break; + case ITT1: tmpreg=0x005; break; + case DTT0: tmpreg=0x006; break; + case DTT1: tmpreg=0x007; 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; + case MMUSR: tmpreg=0x805; break; + case URP: tmpreg=0x806; break; + case SRP: tmpreg=0x807; break; + default: + as_fatal("failed sanity check."); + } + 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 as_fatal("failed sanity check."); + 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; + + case 'c': + switch (opP->reg) { + case NC: tmpreg = 0; break; + case DC: tmpreg = 1; break; + case IC: tmpreg = 2; break; + case BC: tmpreg = 3; break; + default: + as_fatal("failed sanity check"); + } /* switch on cache token */ + install_operand(s[1], tmpreg); + break; +#ifndef NO_68851 + /* JF: These are out of order, I fear. */ + case 'f': + switch (opP->reg) { + case SFC: + tmpreg=0; + break; + case DFC: + tmpreg=1; + break; + default: + as_fatal("failed sanity check."); + } + 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: + as_fatal("failed sanity check."); + } + install_operand(s[1],tmpreg); + break; + + case 'V': + if (opP->reg == VAL) + break; + as_fatal("failed sanity check."); + + case 'W': + switch (opP->reg) { + + case DRP: + tmpreg=1; + break; + case SRP: + tmpreg=2; + break; + case CRP: + tmpreg=3; + break; + default: + as_fatal("failed sanity check."); + } + 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: + as_fatal("failed sanity check."); + } + install_operand(s[1], tmpreg); + break; + case 'Y': + know(opP->reg == PSR); + break; + case 'Z': + know(opP->reg == PCSR); + break; +#endif /* m68851 */ + case '_': + tmpreg=get_num(opP->con1,80); + install_operand(s[1], tmpreg); + break; + default: + as_fatal("Internal error: Operand type %c unknown in line %s of file \"%s\"", s[0], __LINE__, __FILE__); + } + } + /* By the time whe get here (FINALLY) the_ins contains the complete + instruction, ready to be emitted... */ +} /* m68k_ip() */ + +/* + * get_regs := '/' + ? + * | '-' + <register> + * | '-' + <register> + ? + * | <empty> + * ; + * + + * The idea here must be to scan in a set of registers but I don't + * understand it. Looks awfully sloppy to me but I don't have any doc on + * this format so... + + * + * + */ + +static int get_regs(i,str,opP) +int i; +struct m68k_op *opP; +char *str; +{ + /* 26, 25, 24, 23-16, 15-8, 0-7 */ + /* Low order 24 bits encoded fpc,fps,fpi,fp7-fp0,a7-a0,d7-d0 */ + unsigned long cur_regs = 0; + int reg1, + reg2; + +#define ADD_REG(x) { if (x == FPI) cur_regs|=(1<<24);\ +else if (x == FPS) cur_regs|=(1<<25);\ +else if (x == FPC) cur_regs|=(1<<26);\ +else cur_regs|=(1<<(x-1)); } + + reg1=i; + for (;;) { + if (*str == '/') { + ADD_REG(reg1); + str++; + } else if (*str == '-') { + str++; + reg2=m68k_reg_parse(&str); + if (reg2<DATA || reg2 >= FPREG+8 || reg1 == FPI || reg1 == FPS || reg1 == FPC) { + opP->error="unknown register in register list"; + return FAIL; + } + while (reg1 <= reg2) { + ADD_REG(reg1); + reg1++; + } + if (*str == '\0') + break; + } else if (*str == '\0') { + ADD_REG(reg1); + break; + } else { + opP->error="unknow character in register list"; + return FAIL; + } + /* DJA -- Bug Fix. Did't handle d1-d2/a1 until the following instruction was added */ + if (*str == '/') + str ++; + reg1=m68k_reg_parse(&str); + if ((reg1<DATA || reg1 >= FPREG+8) && !(reg1 == FPI || reg1 == FPS || reg1 == FPC)) { + opP->error="unknown register in register list"; + return FAIL; + } + } + opP->reg=cur_regs; + return OK; +} /* get_regs() */ + +static int reverse_16_bits(in) +int in; +{ + int out=0; + int n; + + static int mask[16] = { + 0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080, + 0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000 + }; + for (n=0;n<16;n++) { + if (in&mask[n]) + out|=mask[15-n]; + } + return out; +} /* reverse_16_bits() */ + +static int reverse_8_bits(in) +int in; +{ + int out=0; + int n; + + static int mask[8] = { + 0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080, + }; + + for (n=0;n<8;n++) { + if (in&mask[n]) + out|=mask[7-n]; + } + return out; +} /* reverse_8_bits() */ + +static void install_operand(mode,val) +int mode; +int val; +{ + switch (mode) { + case 's': + the_ins.opcode[0]|=val & 0xFF; /* JF FF is for M kludge */ + break; + case 'd': + the_ins.opcode[0]|=val<<9; + break; + case '1': + the_ins.opcode[1]|=val<<12; + break; + case '2': + the_ins.opcode[1]|=val<<6; + break; + case '3': + the_ins.opcode[1]|=val; + break; + case '4': + the_ins.opcode[2]|=val<<12; + break; + case '5': + the_ins.opcode[2]|=val<<6; + break; + case '6': + /* DANGER! This is a hack to force cas2l and cas2w cmds + to be three words long! */ + the_ins.numo++; + the_ins.opcode[2]|=val; + break; + case '7': + the_ins.opcode[1]|=val<<7; + break; + case '8': + the_ins.opcode[1]|=val<<10; + break; +#ifndef NO_68851 + 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 'e': + the_ins.opcode[0] |= (val << 6); + break; + case 'L': + the_ins.opcode[1] = (val >> 16); + the_ins.opcode[2] = val & 0xffff; + break; + case 'c': + default: + as_fatal("failed sanity check."); + } +} /* install_operand() */ + +static void install_gen_operand(mode,val) +int mode; +int val; +{ + switch (mode) { + case 's': + the_ins.opcode[0]|=val; + break; + case 'd': + /* This is a kludge!!! */ + the_ins.opcode[0]|=(val&0x07)<<9|(val&0x38)<<3; + break; + case 'b': + case 'w': + case 'l': + case 'f': + case 'F': + case 'x': + case 'p': + the_ins.opcode[0]|=val; + break; + /* more stuff goes here */ + default: + as_fatal("failed sanity check."); + } +} /* install_gen_operand() */ + +/* + * verify that we have some number of paren pairs, do m68k_ip_op(), and + * then deal with the bitfield hack. + */ + +static char *crack_operand(str,opP) +register char *str; +register struct m68k_op *opP; +{ + register int parens; + register int c; + register char *beg_str; + + if (!str) { + return str; + } + beg_str=str; + for (parens=0;*str && (parens>0 || notend(str));str++) { + if (*str == '(') parens++; + else if (*str == ')') { + if (!parens) { /* ERROR */ + opP->error="Extra )"; + return str; + } + --parens; + } + } + if (!*str && parens) { /* ERROR */ + opP->error="Missing )"; + return str; + } + c= *str; + *str='\0'; + if (m68k_ip_op(beg_str,opP) == FAIL) { + *str=c; + return str; + } + *str=c; + if (c == '}') + c= *++str; /* JF bitfield hack */ + if (c) { + c= *++str; + if (!c) + as_bad("Missing operand"); + } + return str; +} + +/* See the comment up above where the #define notend(... is */ +#if 0 +notend(s) +char *s; +{ + if (*s == ',') return 0; + if (*s == '{' || *s == '}') + return 0; + if (*s != ':') return 1; + /* This kludge here is for the division cmd, which is a kludge */ + if (index("aAdD#",s[1])) return 0; + return 1; +} +#endif + +/* + * Generate a new fixup for one of the relocs in the_ins. + */ +static void + make_fix(m, where) +int m; +char *where; +{ + int n; + + switch (the_ins.reloc[m].wid) { + case 'B': + case 'b': + n=1; + break; + case '3': + 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, + where - frag_now->fr_literal + 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, + the_ins.reloc[m].rtype +#ifdef PIC + , the_ins.reloc[m].got +#endif /* PIC */ + ); +#ifdef PIC + if (the_ins.reloc[m].rtype == RELOC_GLOB_DAT + && the_ins.reloc[m].add != NULL) + the_ins.reloc[m].add->sy_forceout = 1; +#endif /* PIC */ +} + +/* This is the guts of the machine-dependent assembler. STR points to a + machine dependent instruction. This function is supposed to emit + the frags/bytes it assembles to. + */ +void + md_assemble(str) +char *str; +{ + char *er; + short *fromP; + char *toP = NULL; + int m,n = 0; + char *to_beg_P; + int shorts_this_frag; + + + if (current_architecture == 0) { + current_architecture = (m68020 +#ifndef NO_68881 + | m68881 +#endif +#ifndef NO_68851 + | m68851 +#endif + ); + } /* default current_architecture */ + + memset((char *)(&the_ins), '\0', sizeof(the_ins)); /* JF for paranoia sake */ + m68k_ip(str); + er=the_ins.error; + if (!er) { + for (n=the_ins.numargs;n;--n) + if (the_ins.operands[n].error) { + er=the_ins.operands[n].error; + break; + } + } + if (er) { + as_bad("\"%s\" -- Statement '%s' ignored",er,str); + return; + } + + if (the_ins.nfrag == 0) { /* No frag hacking involved; just put it out */ + toP=frag_more(2*the_ins.numo); + fromP= &the_ins.opcode[0]; + for (m=the_ins.numo;m;--m) { + md_number_to_chars(toP,(long)(*fromP),2); + toP+=2; + fromP++; + } + /* put out symbol-dependent info */ + for (m = 0; m < the_ins.nrel; m++) { + make_fix(m, toP-the_ins.numo*2); + } + return; + } + + /* There's some frag hacking */ + for (n=0,fromP= &the_ins.opcode[0];n<the_ins.nfrag;n++) { + int wid; + + if (n == 0) wid=2*the_ins.fragb[n].fragoff; + else wid=2*(the_ins.numo-the_ins.fragb[n-1].fragoff); + toP=frag_more(wid); + to_beg_P=toP; + shorts_this_frag=0; + for (m=wid/2;m;--m) { + md_number_to_chars(toP,(long)(*fromP),2); + toP+=2; + fromP++; + shorts_this_frag++; + } + for (m=0;m<the_ins.nrel;m++) { + if ((the_ins.reloc[m].n) >= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */) { + the_ins.reloc[m].n-= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */; + break; + } + if (the_ins.reloc[m].wid == 0) + continue; + make_fix(m, toP-the_ins.numo*2); + the_ins.reloc[m].wid=0; + } + /* know(the_ins.fragb[n].fadd); */ + (void)frag_var(rs_machine_dependent,10,0,(relax_substateT)(the_ins.fragb[n].fragty), + the_ins.fragb[n].fadd,the_ins.fragb[n].foff,to_beg_P); + } + n=(the_ins.numo-the_ins.fragb[n-1].fragoff); + shorts_this_frag=0; + if (n) { + toP=frag_more(n*sizeof(short)); + while (n--) { + md_number_to_chars(toP,(long)(*fromP),2); + toP+=2; + fromP++; + shorts_this_frag++; + } + } + for (m=0;m<the_ins.nrel;m++) { + if (the_ins.reloc[m].wid == 0) + continue; + make_fix(m, toP - /* the_ins.numo */ shorts_this_frag*2); + } +} + +/* This function is called once, at assembler startup time. This should + set up all the tables, etc that the MD part of the assembler needs + */ +void + md_begin() +{ + /* + * md_begin -- set up hash tables with 68000 instructions. + * similar to what the vax assembler does. ---phr + */ + /* RMS claims the thing to do is take the m68k-opcode.h table, and make + a copy of it at runtime, adding in the information we want but isn't + there. I think it'd be better to have an awk script hack the table + at compile time. Or even just xstr the table and use it as-is. But + my lord ghod hath spoken, so we do it this way. Excuse the ugly var + names. */ + + register const struct m68k_opcode *ins; + register struct m68k_incant *hack, + *slak; + register char *retval = 0; /* empty string, or error msg text */ + register unsigned int i; + register char c; + + if ((op_hash = hash_new()) == NULL) + as_fatal("Virtual memory exhausted"); + + obstack_begin(&robyn,4000); + for (ins = m68k_opcodes; ins < endop; ins++) { + hack=slak=(struct m68k_incant *)obstack_alloc(&robyn,sizeof(struct m68k_incant)); + do { + /* we *could* ignore insns that don't match our + arch here but just leaving them out of the + hash. */ + slak->m_operands=ins->args; + slak->m_opnum=strlen(slak->m_operands)/2; + slak->m_arch = ins->arch; + 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 m68k_incant *) obstack_alloc(&robyn,sizeof(struct m68k_incant)); + ins++; + } else + slak->m_next=0; + slak=slak->m_next; + } while (slak); + + retval = hash_insert (op_hash, ins->name,(char *)hack); + /* Didn't his mommy tell him about null pointers? */ + if (retval && *retval) + as_fatal("Internal Error: Can't hash %s: %s",ins->name,retval); + } + + for (i = 0; i < sizeof(mklower_table) ; i++) + mklower_table[i] = (isupper(c = (char) i)) ? tolower(c) : c; + + for (i = 0 ; i < sizeof(notend_table) ; i++) { + notend_table[i] = 0; + alt_notend_table[i] = 0; + } + notend_table[','] = 1; + notend_table['{'] = 1; + notend_table['}'] = 1; + alt_notend_table['a'] = 1; + alt_notend_table['A'] = 1; + alt_notend_table['d'] = 1; + alt_notend_table['D'] = 1; + alt_notend_table['#'] = 1; + alt_notend_table['f'] = 1; + alt_notend_table['F'] = 1; +#ifdef REGISTER_PREFIX + alt_notend_table[REGISTER_PREFIX] = 1; +#endif +} + +#if 0 +#define notend(s) ((*s == ',' || *s == '}' || *s == '{' \ + || (*s == ':' && strchr("aAdD#", s[1]))) \ + ? 0 : 1) +#endif + +/* This funciton is called once, before the assembler exits. It is + supposed to do any final cleanup for this part of the assembler. + */ +void + md_end() +{ +} + +/* Equal to MAX_PRECISION in atof-ieee.c */ +#define MAX_LITTLENUMS 6 + +/* Turn a string in input_line_pointer into a floating point constant of type + type, and store the appropriate bytes in *litP. The number of LITTLENUMS + emitted is stored in *sizeP. An error message is returned, or NULL on OK. + */ +char * + md_atof(type,litP,sizeP) +char type; +char *litP; +int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + 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: + as_fatal("failed sanity check."); + } +} + +void + md_apply_fix(fixP, val) +fixS *fixP; +long val; +{ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + + switch (fixP->fx_size) { + case 1: + *buf++ = val; + break; + case 2: + *buf++ = (val >> 8); + *buf++ = val; + break; + case 4: + *buf++ = (val >> 24); + *buf++ = (val >> 16); + *buf++ = (val >> 8); + *buf++ = val; + break; + default: + BAD_CASE (fixP->fx_size); + } +} + + +/* *fragP has been relaxed to its final size, and now needs to have + the bytes inside it modified to conform to the new size There is UGLY + MAGIC here. .. + */ +void + md_convert_frag(headers, fragP) +object_headers *headers; +register fragS *fragP; +{ + long disp; + long ext = 0; + + /* Address in object code of the displacement. */ + register int object_address = fragP->fr_fix + fragP->fr_address; + +#ifdef IBM_COMPILER_SUX + /* This is wrong but it convinces the native rs6000 compiler to + generate the code we want. */ + register char *buffer_address = fragP->fr_literal; + buffer_address += fragP->fr_fix; +#else /* IBM_COMPILER_SUX */ + /* Address in gas core of the place to store the displacement. */ + register char *buffer_address = fragP->fr_fix + fragP->fr_literal; +#endif /* IBM_COMPILER_SUX */ + + /* No longer true: know(fragP->fr_symbol); */ + + /* The displacement of the address, from current location. */ + disp = fragP->fr_symbol ? S_GET_VALUE(fragP->fr_symbol) : 0; + disp = (disp + 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 (cpu_of_arch(current_architecture) < m68020) { + 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, + FIX_NO_RELOC); + + fragP->fr_fix+=4; + ext=0; + } else if (fragP->fr_opcode[0] == 0x60) { + fragP->fr_opcode[0]= 0x4E; + fragP->fr_opcode[1]= 0xF9; /* JMP with ABSL LONG offset */ + subseg_change(SEG_TEXT, 0); + fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset,0, + FIX_NO_RELOC); + fragP->fr_fix+=4; + ext=0; + } else { + as_bad("Long branch offset not supported."); + } + } else { + fragP->fr_opcode[1]=0xff; + ext=4; + } + break; + case TAB(BCC68000,LONG): + /* only Bcc 68000 instructions can come here */ + /* change bcc into b!cc/jmp absl long */ + fragP->fr_opcode[0] ^= 0x01; /* invert bcc */ + fragP->fr_opcode[1] = 0x6; /* branch offset = 6 */ + + /* JF: these used to be fr_opcode[2,3], but they may be in a + different frag, in which case refering to them is a no-no. + Only fr_opcode[0,1] are guaranteed to work. */ + *buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */ + *buffer_address++ = 0xf9; + fragP->fr_fix += 2; /* account for jmp instruction */ + subseg_change(SEG_TEXT,0); + fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, + fragP->fr_offset,0, + FIX_NO_RELOC); + fragP->fr_fix += 4; + ext=0; + break; + case TAB(DBCC,LONG): + /* only DBcc 68000 instructions can come here */ + /* change dbcc into dbcc/jmp absl long */ + /* JF: these used to be fr_opcode[2-7], but that's wrong */ + *buffer_address++ = 0x00; /* branch offset = 4 */ + *buffer_address++ = 0x04; + *buffer_address++ = 0x60; /* put in bra pc+6 */ + *buffer_address++ = 0x06; + *buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */ + *buffer_address++ = 0xf9; + + fragP->fr_fix += 6; /* account for bra/jmp instructions */ + subseg_change(SEG_TEXT,0); + fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, + fragP->fr_offset,0, + FIX_NO_RELOC); + fragP->fr_fix += 4; + ext=0; + break; + case TAB(FBRANCH,SHORT): + know((fragP->fr_opcode[1]&0x40) == 0); + ext=2; + break; + case TAB(FBRANCH,LONG): + fragP->fr_opcode[1]|=0x40; /* Turn on LONG bit */ + ext=4; + break; + case TAB(PCREL,SHORT): + ext=2; + break; + case TAB(PCREL,LONG): + /* 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, FIX_NO_RELOC); + if ((fragP->fr_opcode[1] & 0x3F) != 0x3A) + as_bad("Internal error (long PC-relative operand) for insn 0x%04lx at 0x%lx", + fragP->fr_opcode[0],fragP->fr_address); + fragP->fr_opcode[1]&= ~0x3F; + fragP->fr_opcode[1]|=0x39; /* Mode 7.1 */ + fragP->fr_fix+=4; + /* 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, FIX_NO_RELOC); + fragP->fr_opcode[1] &= ~0x3F; + fragP->fr_opcode[1] |= 0x3A; + ext=2; + break; + case TAB(PCLEA,LONG): + subseg_change(SEG_TEXT,0); + fix_new(fragP, (int) (fragP->fr_fix) + 2, 4, fragP->fr_symbol, (symbolS *) 0, fragP->fr_offset + 2, 1, FIX_NO_RELOC); + *buffer_address++ = 0x01; + *buffer_address++ = 0x70; + fragP->fr_fix+=2; + /* buffer_address+=2; */ + ext=4; + break; + +} /* switch on subtype */ + + if (ext) { + md_number_to_chars(buffer_address, (long) disp, (int) ext); + fragP->fr_fix += ext; + /* H_SET_TEXT_SIZE(headers, H_GET_TEXT_SIZE(headers) + ext); */ + } /* if extending */ + + return; +} /* md_convert_frag() */ + +/* Force truly undefined symbols to their maximum size, and generally set up + the frag list to be relaxed + */ +int md_estimate_size_before_relax(fragP, segment) +register fragS *fragP; +segT segment; +{ + int old_fix; + register char *buffer_address = fragP->fr_fix + fragP->fr_literal; + + old_fix = fragP->fr_fix; + + /* handle SZ_UNDEF first, it can be changed to BYTE or SHORT */ + switch (fragP->fr_subtype) { + + case TAB(BRANCH,SZ_UNDEF): { + if ((fragP->fr_symbol != NULL) /* Not absolute */ + && S_GET_SEGMENT(fragP->fr_symbol) == segment) { + fragP->fr_subtype = TAB(TABTYPE(fragP->fr_subtype), BYTE); + break; + } else if ((fragP->fr_symbol == 0) || (cpu_of_arch(current_architecture) < m68020)) { + /* On 68000, or for absolute value, switch to abs long */ + /* FIXME, we should check abs val, pick short or long */ + if (fragP->fr_opcode[0] == 0x61) { + fragP->fr_opcode[0]= 0x4E; + fragP->fr_opcode[1]= 0xB9; /* JSR with ABSL LONG offset */ + subseg_change(SEG_TEXT, 0); + fix_new(fragP, fragP->fr_fix, 4, + fragP->fr_symbol, 0, fragP->fr_offset, 0, FIX_NO_RELOC); + fragP->fr_fix+=4; + frag_wane(fragP); + } 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, FIX_NO_RELOC); + 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, 1, FIX_NO_RELOC); + 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, 1, +#ifdef PIC + /* With -k, make all external branches go via the jump table. */ + (flagseen['k']? RELOC_JMP_TBL: NO_RELOC), NULL +#else + NO_RELOC +#endif + ); + fragP->fr_fix += 4; + fragP->fr_opcode[1] = 0xff; + frag_wane(fragP); + break; + } + + break; + } /* case TAB(BRANCH,SZ_UNDEF) */ + + case TAB(FBRANCH,SZ_UNDEF): { + if (S_GET_SEGMENT(fragP->fr_symbol) == segment || flagseen['l']) { + fragP->fr_subtype = TAB(FBRANCH,SHORT); + fragP->fr_var += 2; + } else { + fragP->fr_subtype = TAB(FBRANCH,LONG); + fragP->fr_var += 4; + } + break; + } /* TAB(FBRANCH,SZ_UNDEF) */ + + case TAB(PCREL,SZ_UNDEF): { + if (S_GET_SEGMENT(fragP->fr_symbol) == segment || flagseen['l']) { + fragP->fr_subtype = TAB(PCREL,SHORT); + fragP->fr_var += 2; + } else { + fragP->fr_subtype = TAB(PCREL,LONG); + fragP->fr_var += 4; + } + break; + } /* TAB(PCREL,SZ_UNDEF) */ + + case TAB(BCC68000,SZ_UNDEF): { + if ((fragP->fr_symbol != NULL) + && S_GET_SEGMENT(fragP->fr_symbol) == segment) { + fragP->fr_subtype=TAB(BCC68000,BYTE); + break; + } + /* only Bcc 68000 instructions can come here */ + /* change bcc into b!cc/jmp absl long */ + fragP->fr_opcode[0] ^= 0x01; /* invert bcc */ + if (flagseen['l']) { + fragP->fr_opcode[1] = 0x04; /* branch offset = 6 */ + /* JF: these were fr_opcode[2,3] */ + buffer_address[0] = 0x4e; /* put in jmp long (0x4ef9) */ + buffer_address[1] = 0xf8; + fragP->fr_fix += 2; /* account for jmp instruction */ + subseg_change(SEG_TEXT,0); + fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0, + fragP->fr_offset, 0, FIX_NO_RELOC); + fragP->fr_fix += 2; + } else { + fragP->fr_opcode[1] = 0x06; /* branch offset = 6 */ + /* JF: these were fr_opcode[2,3] */ + buffer_address[2] = 0x4e; /* put in jmp long (0x4ef9) */ + buffer_address[3] = 0xf9; + fragP->fr_fix += 2; /* account for jmp instruction */ + subseg_change(SEG_TEXT,0); + fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, + fragP->fr_offset, 0, FIX_NO_RELOC); + fragP->fr_fix += 4; + } + frag_wane(fragP); + break; + } /* case TAB(BCC68000,SZ_UNDEF) */ + + case TAB(DBCC,SZ_UNDEF): { + if (fragP->fr_symbol != NULL && S_GET_SEGMENT(fragP->fr_symbol) == segment) { + fragP->fr_subtype=TAB(DBCC,SHORT); + fragP->fr_var+=2; + break; + } + /* only DBcc 68000 instructions can come here */ + /* change dbcc into dbcc/jmp absl long */ + /* JF: these used to be fr_opcode[2-4], which is wrong. */ + buffer_address[0] = 0x00; /* branch offset = 4 */ + buffer_address[1] = 0x04; + buffer_address[2] = 0x60; /* put in bra pc + ... */ + + if (flagseen['l']) { + /* JF: these were fr_opcode[5-7] */ + buffer_address[3] = 0x04; /* plus 4 */ + buffer_address[4] = 0x4e;/* Put in Jump Word */ + buffer_address[5] = 0xf8; + fragP->fr_fix += 6; /* account for bra/jmp instruction */ + subseg_change(SEG_TEXT,0); + fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0, + fragP->fr_offset, 0, FIX_NO_RELOC); + fragP->fr_fix += 2; + } else { + /* JF: these were fr_opcode[5-7] */ + buffer_address[3] = 0x06; /* Plus 6 */ + buffer_address[4] = 0x4e; /* put in jmp long (0x4ef9) */ + buffer_address[5] = 0xf9; + fragP->fr_fix += 6; /* account for bra/jmp instruction */ + subseg_change(SEG_TEXT,0); + fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, + fragP->fr_offset, 0, FIX_NO_RELOC); + fragP->fr_fix += 4; + } + + frag_wane(fragP); + break; + } /* case TAB(DBCC,SZ_UNDEF) */ + + case TAB(PCLEA,SZ_UNDEF): { + if ((S_GET_SEGMENT(fragP->fr_symbol)) == segment || flagseen['l']) { + fragP->fr_subtype=TAB(PCLEA,SHORT); + fragP->fr_var+=2; + } else { + fragP->fr_subtype=TAB(PCLEA,LONG); + fragP->fr_var+=6; + } + break; + } /* TAB(PCLEA,SZ_UNDEF) */ + + default: + break; + + } /* switch on subtype looking for SZ_UNDEF's. */ + + /* now that SZ_UNDEF are taken care of, check others */ + switch (fragP->fr_subtype) { + case TAB(BCC68000,BYTE): + case TAB(BRANCH,BYTE): + /* We can't do a short jump to the next instruction, + so we force word mode. */ + if (fragP->fr_symbol && S_GET_VALUE(fragP->fr_symbol) == 0 && + fragP->fr_symbol->sy_frag == fragP->fr_next) { + fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),SHORT); + fragP->fr_var+=2; + } + break; + default: + break; +} + return fragP->fr_var + fragP->fr_fix - old_fix; +} + +#if defined(OBJ_AOUT) | defined(OBJ_BOUT) +/* the bit-field entries in the relocation_info struct plays hell + with the byte-order problems of cross-assembly. So as a hack, + I added this mach. dependent ri twiddler. Ugly, but it gets + you there. -KWK */ +/* on m68k: first 4 bytes are normal unsigned long, next three bytes + are symbolnum, most sig. byte first. Last byte is broken up with + bit 7 as pcrel, bits 6 & 5 as length, bit 4 as pcrel, and the lower + nibble as nuthin. (on Sun 3 at least) */ +/* Translate the internal relocation information into target-specific + format. */ +#ifdef comment +void + md_ri_to_chars(the_bytes, ri) +char *the_bytes; +struct reloc_info_generic *ri; +{ + /* this is easy */ + md_number_to_chars(the_bytes, ri->r_address, 4); + /* now the fun stuff */ + the_bytes[4] = (ri->r_symbolnum >> 16) & 0x0ff; + the_bytes[5] = (ri->r_symbolnum >> 8) & 0x0ff; + the_bytes[6] = ri->r_symbolnum & 0x0ff; + the_bytes[7] = (((ri->r_pcrel << 7) & 0x80) | ((ri->r_length << 5) & 0x60) | + ((ri->r_extern << 4) & 0x10)); +} +#endif /* comment */ + +void tc_aout_fix_to_chars(where, fixP, segment_address_in_file) +char *where; +fixS *fixP; +relax_addressT segment_address_in_file; +{ + /* + * In: length of relocation (or of address) in chars: 1, 2 or 4. + * Out: GNU LD relocation length code: 0, 1, or 2. + */ + + static unsigned char nbytes_r_length[] = { 42, 0, 1, 42, 2 }; + long r_symbolnum; + int r_flags; + + know(fixP->fx_addsy != NULL); + + md_number_to_chars(where, + fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, + 4); + + r_symbolnum = (S_IS_DEFINED(fixP->fx_addsy) + ? S_GET_TYPE(fixP->fx_addsy) + : fixP->fx_addsy->sy_number); + r_flags = (fixP->fx_pcrel? 0x80: 0) + | ((nbytes_r_length[fixP->fx_size] & 3) << 5) + | (!S_IS_DEFINED(fixP->fx_addsy)? 0x10: 0); + +#ifdef PIC + switch (fixP->fx_r_type) { + case NO_RELOC: + break; + case RELOC_32: + if (flagseen['k'] && S_IS_EXTERNAL(fixP->fx_addsy)) { + r_symbolnum = fixP->fx_addsy->sy_number; + r_flags |= 0x10; /* set extern bit */ + } + break; + case RELOC_GLOB_DAT: + r_flags |= 8; /* set baserel bit */ + r_symbolnum = fixP->fx_addsy->sy_number; + if (S_IS_EXTERNAL(fixP->fx_addsy)) + r_flags |= 0x10; + break; + case RELOC_JMP_TBL: + r_flags |= 4; /* set jmptable bit */ + break; + case RELOC_RELATIVE: + /* should never happen */ + r_flags |= 2; /* set relative bit */ + break; + } +#endif /* PIC */ + + where[4] = (r_symbolnum >> 16) & 0x0ff; + where[5] = (r_symbolnum >> 8) & 0x0ff; + where[6] = r_symbolnum & 0x0ff; + where[7] = r_flags; + + return; +} /* tc_aout_fix_to_chars() */ + +#endif /* OBJ_AOUT or OBJ_BOUT */ + +#ifndef WORKING_DOT_WORD +const int md_short_jump_size = 4; +const int md_long_jump_size = 6; + +void + md_create_short_jump(ptr,from_addr,to_addr,frag,to_symbol) +char *ptr; +long from_addr, + to_addr; +fragS *frag; +symbolS *to_symbol; +{ + long offset; + + offset = to_addr - (from_addr+2); + + md_number_to_chars(ptr ,(long)0x6000,2); + md_number_to_chars(ptr+2,(long)offset,2); +} + +void + md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol) +char *ptr; +long from_addr, + to_addr; +fragS *frag; +symbolS *to_symbol; +{ + long offset; + + if (cpu_of_arch(current_architecture) < m68020) { + offset=to_addr-S_GET_VALUE(to_symbol); + md_number_to_chars(ptr ,(long)0x4EF9,2); + md_number_to_chars(ptr+2,(long)offset,4); + fix_new(frag,(ptr+2)-frag->fr_literal,4,to_symbol,(symbolS *)0,(long)0,0, + FIX_NO_RELOC); + } else { + offset=to_addr - (from_addr+2); + md_number_to_chars(ptr ,(long)0x60ff,2); + md_number_to_chars(ptr+2,(long)offset,4); + } +} + +#endif +/* Different values of OK tell what its OK to return. Things that aren't OK are an error (what a shock, no?) + + 0: Everything is OK + 10: Absolute 1:8 only + 20: Absolute 0:7 only + 30: absolute 0:15 only + 40: Absolute 0:31 only + 50: absolute 0:127 only + 55: absolute -64:63 only + 60: absolute -128:127 only + 70: absolute 0:4095 only + 80: No bignums + + */ + +static int get_num(exp,ok) +struct m68k_exp *exp; +int ok; +{ +#ifdef TEST2 + long l = 0; + + if (!exp->e_beg) + return 0; + if (*exp->e_beg == '0') { + if (exp->e_beg[1] == 'x') + sscanf(exp->e_beg+2,"%x",&l); + else + sscanf(exp->e_beg+1,"%O",&l); + return l; + } + return atol(exp->e_beg); +#else + char *save_in; + char c_save; + + if (!exp) { + /* Can't do anything */ + return 0; + } + if (!exp->e_beg || !exp->e_end) { + seg(exp)=SEG_ABSOLUTE; + adds(exp)=0; + subs(exp)=0; + offs(exp)= (ok == 10) ? 1 : 0; + as_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_ABSENT: + /* Do the same thing the VAX asm does */ + seg(exp)=SEG_ABSOLUTE; + adds(exp)=0; + subs(exp)=0; + offs(exp)=0; + if (ok == 10) { + as_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: + as_fatal("failed sanity check."); + } + 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 +} /* get_num() */ + +/* These are the back-ends for the various machine dependent pseudo-ops. */ +void demand_empty_rest_of_line(); /* Hate those extra verbose names */ + +static void s_data1() { + subseg_new(SEG_DATA,1); + demand_empty_rest_of_line(); +} /* s_data1() */ + +static void s_data2() { + subseg_new(SEG_DATA,2); + demand_empty_rest_of_line(); +} /* s_data2() */ + +static void s_bss() { + /* We don't support putting frags in the BSS segment, but we + can put them into initialized data for now... */ + subseg_new(SEG_DATA,255); /* FIXME-SOON */ + demand_empty_rest_of_line(); +} /* s_bss() */ + +static void s_even() { + register int temp; + register long temp_fill; + + temp = 1; /* JF should be 2? */ + temp_fill = get_absolute_expression (); + if ( ! need_pass_2 ) /* Never make frag if expect extra pass. */ + frag_align (temp, (int)temp_fill); + demand_empty_rest_of_line(); +} /* s_even() */ + +static void s_proc() { + demand_empty_rest_of_line(); +} /* s_proc() */ + +/* s_space is defined in read.c .skip is simply an alias to it. */ + +/* + * md_parse_option + * Invocation line includes a switch not recognized by the base assembler. + * See if it's a processor-specific option. These are: + * + * -[A]m[c]68000, -[A]m[c]68008, -[A]m[c]68010, -[A]m[c]68020, -[A]m[c]68030, -[A]m[c]68040 + * -[A]m[c]68881, -[A]m[c]68882, -[A]m[c]68851 + * Select the architecture. Instructions or features not + * supported by the selected architecture cause fatal + * errors. More than one may be specified. The default is + * -m68020 -m68851 -m68881. Note that -m68008 is a synonym + * for -m68000, and -m68882 is a synonym for -m68881. + * + * MAYBE_FLOAT_TOO is defined below so that specifying a processor type + * (e.g. m68020) also requests that float instructions be included. This + * is the default setup, mostly to avoid hassling users. A better + * rearrangement of this structure would be to add an option to DENY + * floating point opcodes, for people who want to really know there's none + * of that funny floaty stuff going on. FIXME-later. + */ +#ifndef MAYBE_FLOAT_TOO +#define MAYBE_FLOAT_TOO m68881 +#endif + +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 'S': /* -S means that jbsr's always turn into jsr's. */ + break; + + case 'A': + (*argP)++; + /* intentional fall-through */ + case 'm': + (*argP)++; + + if (**argP == 'c') { + (*argP)++; + } /* allow an optional "c" */ + + if (!strcmp(*argP, "68000") + || !strcmp(*argP, "68008")) { + current_architecture |= m68000; + } else if (!strcmp(*argP, "68010")) { +#ifdef TE_SUN + omagic= 1<<16|OMAGIC; +#endif + current_architecture |= m68010; + + } else if (!strcmp(*argP, "68020")) { + current_architecture |= m68020 | MAYBE_FLOAT_TOO; + + } else if (!strcmp(*argP, "68030")) { + current_architecture |= m68030 | MAYBE_FLOAT_TOO; + + } else if (!strcmp(*argP, "68040")) { + current_architecture |= m68040 | MAYBE_FLOAT_TOO; + +#ifndef NO_68881 + } else if (!strcmp(*argP, "68881")) { + current_architecture |= m68881; + + } else if (!strcmp(*argP, "68882")) { + current_architecture |= m68882; + +#endif /* NO_68881 */ +#ifndef NO_68851 + } else if (!strcmp(*argP,"68851")) { + current_architecture |= m68851; + +#endif /* NO_68851 */ + } else { + as_warn("Unknown architecture, \"%s\". option ignored", *argP); + } /* switch on architecture */ + + while (**argP) (*argP)++; + + break; + + case 'p': + if (!strcmp(*argP,"pic")) { + (*argP) += 3; + break; /* -pic, Position Independent Code */ + } else { + return(0); + } /* pic or not */ + +#ifdef PIC + case 'k': + /* Predefine GOT symbol */ + GOT_symbol = symbol_find_or_make("__GLOBAL_OFFSET_TABLE_"); + break; +#endif /* PIC */ + + default: + return 0; + } + return 1; +} + + +#ifdef TEST2 + +/* TEST2: Test md_assemble() */ +/* Warning, this routine probably doesn't work anymore */ + +main() +{ + struct m68k_it the_ins; + char buf[120]; + char *cp; + int n; + + m68k_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; + memset(&the_ins, '\0', sizeof(the_ins)); + m68k_ip(&the_ins,buf); + if (the_ins.error) { + printf("Error %s in %s\n",the_ins.error,buf); + } else { + printf("Opcode(%d.%s): ",the_ins.numo,the_ins.args); + for (n=0;n<the_ins.numo;n++) + printf(" 0x%x",the_ins.opcode[n]&0xffff); + printf(" "); + print_the_insn(&the_ins.opcode[0],stdout); + (void)putchar('\n'); + } + for (n=0;n<strlen(the_ins.args)/2;n++) { + if (the_ins.operands[n].error) { + printf("op%d Error %s in %s\n",n,the_ins.operands[n].error,buf); + continue; + } + printf("mode %d, reg %d, ",the_ins.operands[n].mode,the_ins.operands[n].reg); + if (the_ins.operands[n].b_const) + printf("Constant: '%.*s', ",1+the_ins.operands[n].e_const-the_ins.operands[n].b_const,the_ins.operands[n].b_const); + printf("ireg %d, isiz %d, imul %d, ",the_ins.operands[n].ireg,the_ins.operands[n].isiz,the_ins.operands[n].imul); + if (the_ins.operands[n].b_iadd) + printf("Iadd: '%.*s',",1+the_ins.operands[n].e_iadd-the_ins.operands[n].b_iadd,the_ins.operands[n].b_iadd); + (void)putchar('\n'); + } + } + m68k_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); +} + +print_frags() +{ + fragS *fragP; + extern fragS *text_frag_root; + + for (fragP=text_frag_root;fragP;fragP=fragP->fr_next) { + printf("addr %lu next 0x%x fix %ld var %ld symbol 0x%x offset %ld\n", + fragP->fr_address,fragP->fr_next,fragP->fr_fix,fragP->fr_var,fragP->fr_symbol,fragP->fr_offset); + printf("opcode 0x%x type %d subtype %d\n\n",fragP->fr_opcode,fragP->fr_type,fragP->fr_subtype); + } + fflush(stdout); + return 0; +} +#endif + +#ifdef DONTDEF +/*VARARGS1*/ +panic(format,args) +char *format; +{ + fputs("Internal error:",stderr); + _doprnt(format,&args,stderr); + (void)putc('\n',stderr); + as_where(); + abort(); +} +#endif + +/* We have no need to default values of symbols. */ + +/* ARGSUSED */ +symbolS * + md_undefined_symbol (name) +char *name; +{ + return 0; +} + +/* Parse an operand that is machine-specific. + We just return without modifying the expression if we have nothing + to do. */ + +/* ARGSUSED */ +void + md_operand (expressionP) +expressionS *expressionP; +{ +} + +/* Round up a section size to the appropriate boundary. */ +long + md_section_align (segment, size) +segT segment; +long size; +{ + return size; /* Byte alignment is fine */ +} + +/* Exactly what point is a PC-relative offset relative TO? + On the 68k, they're relative to the address of the offset. */ +long + md_pcrel_from (fixP) +fixS *fixP; +{ + return(fixP->fx_where + fixP->fx_frag->fr_address); +} + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of tc-m68k.c */ diff --git a/gnu/usr.bin/as/config/tc-m68k.h b/gnu/usr.bin/as/config/tc-m68k.h new file mode 100644 index 000000000000..ce69252b963a --- /dev/null +++ b/gnu/usr.bin/as/config/tc-m68k.h @@ -0,0 +1,60 @@ +/* This file is tc-m68k.h + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * This file is tp-generic.h and is intended to be a template for + * target processor specific header files. + */ + +#define TC_M68K 1 + +#define NO_LISTING + +#ifdef OLD_GAS +#define REVERSE_SORT_RELOCS +#endif /* OLD_GAS */ + +#define AOUT_MACHTYPE 0x2 +#define LOCAL_LABELS_FB + +#define tc_crawl_symbol_chain(a) {;} /* not used */ +#define tc_headers_hook(a) {;} /* not used */ +#define tc_aout_pre_write_hook(x) {;} /* not used */ + +#define LISTING_WORD_SIZE 2 /* A word is 2 bytes */ +#define LISTING_LHS_WIDTH 2 /* One word on the first line */ +#define LISTING_LHS_WIDTH_SECOND 2 /* One word on the second line */ +#define LISTING_LHS_CONT_LINES 4 /* And 4 lines max */ +#define LISTING_HEADER "68K GAS " + +/* Copied from write.c */ +#define M68K_AIM_KLUDGE(aim, this_state,this_type) \ + if (aim == 0 && this_state == 4) { /* hard encoded from tc-m68k.c */ \ + aim=this_type->rlx_forward+1; /* Force relaxation into word mode */ \ + } + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of tc-m68k.h */ diff --git a/gnu/usr.bin/as/config/tc-m68kmote.h b/gnu/usr.bin/as/config/tc-m68kmote.h new file mode 100644 index 000000000000..8d98bafd17aa --- /dev/null +++ b/gnu/usr.bin/as/config/tc-m68kmote.h @@ -0,0 +1,64 @@ +/* This file is tc-m68kmote.h + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * This file is tp-generic.h and is intended to be a template for + * target processor specific header files. + */ + +#define TC_M68K 1 + +#ifdef TE_SUN3 +/* This variable contains the value to write out at the beginning of + the a.out file. The 2<<16 means that this is a 68020 file instead + of an old-style 68000 file */ + +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (2<<16|OMAGIC); /* Magic byte for file header */ +#endif /* TE_SUN3 */ + +#define AOUT_MACHTYPE 0x2 +#define REVERSE_SORT_RELOCS /* FIXME-NOW: this line can be removed. */ +#define LOCAL_LABELS_FB + +#define tc_crawl_symbol_chain(a) {;} /* not used */ +#define tc_headers_hook(a) {;} /* not used */ +#define tc_aout_pre_write_hook(x) {;} /* not used */ + +#define LISTING_WORD_SIZE 2 /* A word is 2 bytes */ +#define LISTING_LHS_WIDTH 3 /* 3 word on the first line */ +#define LISTING_LHS_WIDTH_SECOND 3 /* One word on the second line */ +#define LISTING_LHS_CONT_LINES 4 /* And 4 lines max */ +#define LISTING_HEADER "68K GAS " + +/* Copied from write.c */ +#define M68K_AIM_KLUDGE(aim, this_state,this_type) \ + if (aim == 0 && this_state == 4) { /* hard encoded from tc-m68k.c */ \ + aim=this_type->rlx_forward+1; /* Force relaxation into word mode */ \ + } +#define MRI + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of tc-m68kmote.h */ diff --git a/gnu/usr.bin/as/config/tc-m88k.c b/gnu/usr.bin/as/config/tc-m88k.c new file mode 100644 index 000000000000..fd7dd863ac40 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-m88k.c @@ -0,0 +1,1435 @@ +/* m88k.c -- Assembler for the Motorola 88000 + Contributed by Devon Bowen of Buffalo University + and Torbjorn Granlund of the Swedish Institute of Computer Science. + Copyright (C) 1989-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "as.h" +#include "opcode/m88k.h" + +struct m88k_insn +{ + unsigned long opcode; + expressionS exp; + enum reloc_type reloc; +}; + +#if __STDC__ == 1 + +static int calcop(struct m88k_opcode *format, char *param, struct m88k_insn *insn); + +#else /* not __STDC__ */ + +static int calcop(); + +#endif /* not __STDC__ */ + +char *getval (); +char *get_reg (); +char *get_imm16 (); +char *get_bf (); +char *get_pcr (); +char *get_cmp (); +char *get_cnd (); +char *get_cr (); +char *get_fcr (); +char *get_vec9 (); + +struct field_val_assoc +{ + char *name; + unsigned val; +}; + +struct field_val_assoc cr_regs[] = +{ + {"PID", 0}, + {"PSR", 1}, + {"EPSR", 2}, + {"SSBR", 3}, + {"SXIP", 4}, + {"SNIP", 5}, + {"SFIP", 6}, + {"VBR", 7}, + {"DMT0", 8}, + {"DMD0", 9}, + {"DMA0", 10}, + {"DMT1", 11}, + {"DMD1", 12}, + {"DMA1", 13}, + {"DMT2", 14}, + {"DMD2", 15}, + {"DMA2", 16}, + {"SR0", 17}, + {"SR1", 18}, + {"SR2", 19}, + {"SR3", 20}, + + {NULL, 0}, +}; + +struct field_val_assoc fcr_regs[] = +{ + {"FPECR", 0}, + {"FPHS1", 1}, + {"FPLS1", 2}, + {"FPHS2", 3}, + {"FPLS2", 4}, + {"FPPT", 5}, + {"FPRH", 6}, + {"FPRL", 7}, + {"FPIT", 8}, + + {"FPSR", 62}, + {"FPCR", 63}, + + {NULL, 0}, +}; + +struct field_val_assoc cmpslot[] = +{ +/* Integer Floating point */ + {"nc", 0}, + {"cp", 1}, + {"eq", 2}, + {"ne", 3}, + {"gt", 4}, + {"le", 5}, + {"lt", 6}, + {"ge", 7}, + {"hi", 8}, {"ou", 8}, + {"ls", 9}, {"ib", 9}, + {"lo", 10}, {"in", 10}, + {"hs", 11}, {"ob", 11}, + + {NULL, 0}, +}; + +struct field_val_assoc cndmsk[] = +{ + {"gt0", 1}, + {"eq0", 2}, + {"ge0", 3}, + {"lt0", 12}, + {"ne0", 13}, + {"le0", 14}, + + {NULL, 0}, +}; + +extern char *myname; +static struct hash_control *op_hash = NULL; + +/* These bits should be turned off in the first address of every segment */ +int md_seg_align = 7; + +/* 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 */ +char comment_chars[] = ";"; + +/* These chars only start a comment at the beginning of a line. */ +char line_comment_chars[] = "#"; + +/* Chars that can be used to separate mant from exp in floating point nums */ +char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant */ +/* as in 0f123.456 */ +/* or 0H1.234E-12 (see exp chars above) */ +char FLT_CHARS[] = "dDfF"; + +extern void float_cons (), cons (), s_globl (), s_line (), + s_space (), s_set (), stringer (), s_lcomm (); +static void s_bss (); + +const pseudo_typeS md_pseudo_table[] = { + {"align", s_align_bytes, 0 }, + {"def", s_set, 0}, + {"dfloat", float_cons, 'd'}, + {"ffloat", float_cons, 'f'}, + {"global", s_globl, 0}, + {"half", cons, 2 }, + {"bss", s_bss, 0}, + {"string", stringer, 0}, + {"word", cons, 4 }, + {"zero", s_space, 0}, + {0} +}; + +const int md_reloc_size = 12; /* Size of relocation record */ + +void +md_begin () +{ + char *retval = NULL; + unsigned int i = 0; + + /* initialize hash table */ + + op_hash = hash_new (); + if (op_hash == NULL) + as_fatal ("Could not initialize hash table"); + + /* loop until you see the end of the list */ + + while (*m88k_opcodes[i].name) + { + char *name = m88k_opcodes[i].name; + + /* hash each mnemonic and record its position */ + + retval = hash_insert (op_hash, name, &m88k_opcodes[i]); + + if (retval != NULL && *retval != '\0') + as_fatal ("Can't hash instruction '%s':%s", + m88k_opcodes[i].name, retval); + + /* skip to next unique mnemonic or end of list */ + + for (i++; !strcmp (m88k_opcodes[i].name, name); i++) + ; + } +} + +int +md_parse_option (argP, cntP, vecP) + char **argP; + int *cntP; + char ***vecP; +{ + as_warn ("unknown option: -%s", *argP); + return(0); +} + +void +md_assemble (op) + char *op; +{ + char *param, *thisfrag; + struct m88k_opcode *format; + struct m88k_insn insn; + + assert (op); + + /* skip over instruction to find parameters */ + + for (param = op; *param != 0 && !isspace (*param); param++) + ; + if (*param != 0) + *param++ = 0; + + /* try to find the instruction in the hash table */ + + if ((format = (struct m88k_opcode *) hash_find (op_hash, op)) == NULL) + { + as_fatal ("Invalid mnemonic '%s'", op); + return; + } + + /* try parsing this instruction into insn */ + + insn.exp.X_add_symbol = 0; + insn.exp.X_subtract_symbol = 0; + insn.exp.X_add_number = 0; + insn.exp.X_seg = 0; + insn.reloc = NO_RELOC; + + while (!calcop(format, param, &insn)) + { + /* if it doesn't parse try the next instruction */ + + if (!strcmp (format[0].name, format[1].name)) + format++; + else + { + as_fatal ("Parameter syntax error"); + return; + } + } + + /* grow the current frag and plop in the opcode */ + + thisfrag = frag_more (4); + md_number_to_chars (thisfrag, insn.opcode, 4); + + /* if this instruction requires labels mark it for later */ + + switch (insn.reloc) + { + case NO_RELOC: + break; + + case RELOC_LO16: + case RELOC_HI16: + fix_new (frag_now, + thisfrag - frag_now->fr_literal + 2, + 2, + insn.exp.X_add_symbol, + insn.exp.X_subtract_symbol, + insn.exp.X_add_number, + 0, + insn.reloc); + break; + + case RELOC_IW16: + fix_new (frag_now, + thisfrag - frag_now->fr_literal, + 4, + insn.exp.X_add_symbol, + insn.exp.X_subtract_symbol, + insn.exp.X_add_number, + 0, + insn.reloc); + break; + + case RELOC_PC16: + fix_new (frag_now, + thisfrag - frag_now->fr_literal + 2, + 2, + insn.exp.X_add_symbol, + insn.exp.X_subtract_symbol, + insn.exp.X_add_number, + 1, + insn.reloc); + break; + + case RELOC_PC26: + fix_new (frag_now, + thisfrag - frag_now->fr_literal, + 4, + insn.exp.X_add_symbol, + insn.exp.X_subtract_symbol, + insn.exp.X_add_number, + 1, + insn.reloc); + break; + + default: + as_fatal ("Unknown relocation type"); + break; + } +} + +int +calcop (format, param, insn) + struct m88k_opcode *format; + char *param; + struct m88k_insn *insn; +{ + char *fmt = format->op_spec; + int f; + unsigned val; + unsigned opcode; + + insn->opcode = format->opcode; + opcode = 0; + + for (;;) + { + if (param == 0) + return 0; + f = *fmt++; + switch (f) + { + case 0: + insn->opcode |= opcode; + return *param == 0; + + default: + if (f != *param++) + return 0; + break; + + case 'd': + param = get_reg (param, &val); + opcode |= val << 21; + break; + + case '1': + param = get_reg (param, &val); + opcode |= val << 16; + break; + + case '2': + param = get_reg (param, &val); + opcode |= val; + break; + + case '3': + param = get_reg (param, &val); + opcode |= (val << 16) | val; + break; + + case 'I': + param = get_imm16 (param, insn); + break; + + case 'b': + param = get_bf (param, &val); + opcode |= val; + break; + + case 'p': + param = get_pcr (param, insn, RELOC_PC16); + break; + + case 'P': + param = get_pcr (param, insn, RELOC_PC26); + break; + + case 'B': + param = get_cmp (param, &val); + opcode |= val; + break; + + case 'M': + param = get_cnd (param, &val); + opcode |= val; + break; + + case 'c': + param = get_cr (param, &val); + opcode |= val << 5; + break; + + case 'f': + param = get_fcr (param, &val); + opcode |= val << 5; + break; + + case 'V': + param = get_vec9 (param, &val); + opcode |= val; + break; + + case '?': + /* Having this here repeats the warning somtimes. + But can't we stand that? */ + as_warn ("Use of obsolete instruction"); + break; + } + } +} + +char * +match_name (param, assoc_tab, valp) + char *param; + struct field_val_assoc *assoc_tab; + unsigned *valp; +{ + int i; + char *name; + int name_len; + + for (i = 0;; i++) + { + name = assoc_tab[i].name; + if (name == NULL) + return NULL; + name_len = strlen (name); + if (!strncmp (param, name, name_len)) + { + *valp = assoc_tab[i].val; + return param + name_len; + } + } +} + +char * +get_reg (param, regnop) + char *param; + unsigned *regnop; +{ + unsigned c; + unsigned regno; + + c = *param++; + if (c == 'r') + { + regno = *param++ - '0'; + if (regno < 10) + { + if (regno == 0) + { + *regnop = 0; + return param; + } + c = *param - '0'; + if (c < 10) + { + regno = regno * 10 + c; + if (c < 32) + { + *regnop = regno; + return param + 1; + } + } + else + { + *regnop = regno; + return param; + } + } + return NULL; + } + else if (c == 's' && param[0] == 'p') + { + *regnop = 31; + return param + 1; + } + + return 0; +} + +char * +get_imm16 (param, insn) + char *param; + struct m88k_insn *insn; +{ + enum reloc_type reloc = NO_RELOC; + unsigned int val; + segT seg; + char *save_ptr; + + if (!strncmp (param, "hi16", 4) && !isalnum (param[4])) + { + reloc = RELOC_HI16; + param += 4; + } + else if (!strncmp (param, "lo16", 4) && !isalnum (param[4])) + { + reloc = RELOC_LO16; + param += 4; + } + else if (!strncmp (param, "iw16", 4) && !isalnum (param[4])) + { + reloc = RELOC_IW16; + param += 4; + } + + save_ptr = input_line_pointer; + input_line_pointer = param; + seg = expression (&insn->exp); + param = input_line_pointer; + input_line_pointer = save_ptr; + + val = insn->exp.X_add_number; + + if (seg == SEG_ABSOLUTE) + { + /* Insert the value now, and reset reloc to NO_RELOC. */ + if (reloc == NO_RELOC) + { + /* Warn about too big expressions if not surrounded by xx16. */ + if (val > 0xffff) + as_warn ("Expression truncated to 16 bits"); + } + + if (reloc == RELOC_HI16) + val >>= 16; + + insn->opcode |= val & 0xffff; + reloc = NO_RELOC; + } + else if (reloc == NO_RELOC) + /* We accept a symbol even without lo16, hi16, etc, and assume + lo16 was intended. */ + reloc = RELOC_LO16; + + insn->reloc = reloc; + + return param; +} + +char * +get_pcr (param, insn, reloc) + char *param; + struct m88k_insn *insn; + enum reloc_type reloc; +{ + char *saveptr, *saveparam; + segT seg; + + saveptr = input_line_pointer; + input_line_pointer = param; + + seg = expression (&insn->exp); + + saveparam = input_line_pointer; + input_line_pointer = saveptr; + + /* Botch: We should relocate now if SEG_ABSOLUTE. */ + insn->reloc = reloc; + + return saveparam; +} + +char * +get_cmp (param, valp) + char *param; + unsigned *valp; +{ + unsigned int val; + char *save_ptr; + + save_ptr = param; + + param = match_name (param, cmpslot, valp); + val = *valp; + + if (param == NULL) + { + param = save_ptr; + + save_ptr = input_line_pointer; + input_line_pointer = param; + val = get_absolute_expression (); + param = input_line_pointer; + input_line_pointer = save_ptr; + + if (val >= 32) + { + as_warn ("Expression truncated to 5 bits"); + val %= 32; + } + } + + *valp = val << 21; + return param; +} + +char * +get_cnd (param, valp) + char *param; + unsigned *valp; +{ + unsigned int val; + + if (isdigit (*param)) + { + param = getval (param, &val); + + if (val >= 32) + { + as_warn ("Expression truncated to 5 bits"); + val %= 32; + } + } + else + { + if (isupper (*param)) + *param = tolower (*param); + + if (isupper (param[1])) + param[1] = tolower (param[1]); + + param = match_name (param, cndmsk, valp); + + if (param == NULL) + return NULL; + + val = *valp; + } + + *valp = val << 21; + return param; +} + +char * +get_bf2 (param, bc) + char *param; + int bc; +{ + int depth = 0; + int c; + + for (;;) + { + c = *param; + if (c == 0) + return param; + else if (c == '(') + depth++; + else if (c == ')') + depth--; + else if (c == bc && depth <= 0) + return param; + param++; + } +} + +char * +get_bf_offset_expression (param, offsetp) + char *param; + unsigned *offsetp; +{ + unsigned offset; + + if (isalpha (param[0])) + { + if (isupper (param[0])) + param[0] = tolower (param[0]); + if (isupper (param[1])) + param[1] = tolower (param[1]); + + param = match_name (param, cmpslot, offsetp); + + return param; + } + else + { + input_line_pointer = param; + offset = get_absolute_expression (); + param = input_line_pointer; + } + + *offsetp = offset; + return param; +} + +char * +get_bf (param, valp) + char *param; + unsigned *valp; +{ + unsigned offset = 0; + unsigned width = 0; + char *xp; + char *save_ptr; + + xp = get_bf2 (param, '<'); + + save_ptr = input_line_pointer; + input_line_pointer = param; + if (*xp == 0) + { + /* We did not find '<'. We have an offset (width implicitly 32). */ + param = get_bf_offset_expression (param, &offset); + if (param == NULL) + return NULL; + input_line_pointer = save_ptr; + } + else + { + *xp++ = 0; /* Overwrite the '<' */ + param = get_bf2 (xp, '>'); + if (*param == 0) + return NULL; + *param++ = 0; /* Overwrite the '>' */ + + width = get_absolute_expression (); + xp = get_bf_offset_expression (xp, &offset); + input_line_pointer = save_ptr; + + if (xp + 1 != param) + return NULL; + } + + *valp = ((width % 32) << 5) | (offset % 32); + + return param; +} + +char * +get_cr (param, regnop) + char *param; + unsigned *regnop; +{ + unsigned regno; + unsigned c; +/* int i; FIXME remove this */ +/* int name_len; FIXME remove this */ + + if (!strncmp (param, "cr", 2)) + { + param += 2; + + regno = *param++ - '0'; + if (regno < 10) + { + if (regno == 0) + { + *regnop = 0; + return param; + } + c = *param - '0'; + if (c < 10) + { + regno = regno * 10 + c; + if (c < 64) + { + *regnop = regno; + return param + 1; + } + } + else + { + *regnop = regno; + return param; + } + } + return NULL; + } + + param = match_name (param, cr_regs, regnop); + + return param; +} + +char * +get_fcr (param, regnop) + char *param; + unsigned *regnop; +{ + unsigned regno; + unsigned c; +/* int i; FIXME remove this */ +/* int name_len; FIXME: remove this */ + + if (!strncmp (param, "fcr", 3)) + { + param += 3; + + regno = *param++ - '0'; + if (regno < 10) + { + if (regno == 0) + { + *regnop = 0; + return param; + } + c = *param - '0'; + if (c < 10) + { + regno = regno * 10 + c; + if (c < 64) + { + *regnop = regno; + return param + 1; + } + } + else + { + *regnop = regno; + return param; + } + } + return NULL; + } + + param = match_name (param, fcr_regs, regnop); + + return param; +} + +char * +get_vec9 (param, valp) + char *param; + unsigned *valp; +{ + unsigned val; + char *save_ptr; + + save_ptr = input_line_pointer; + input_line_pointer = param; + val = get_absolute_expression (); + param = input_line_pointer; + input_line_pointer = save_ptr; + + if (val >= 1 << 9) + as_warn ("Expression truncated to 9 bits"); + + *valp = val % (1 << 9); + + return param; +} + +#define hexval(z) \ + (isdigit (z) ? (z) - '0' : \ + islower (z) ? (z) - 'a' + 10 : \ + isupper (z) ? (z) - 'A' + 10 : -1) + +char * +getval (param, valp) + char *param; + unsigned int *valp; +{ + unsigned int val = 0; + unsigned int c; + + c = *param++; + if (c == '0') + { + c = *param++; + if (c == 'x' || c == 'X') + { + c = *param++; + c = hexval (c); + while (c < 16) + { + val = val * 16 + c; + c = *param++; + c = hexval (c); + } + } + else + { + c -= '0'; + while (c < 8) + { + val = val * 8 + c; + c = *param++ - '0'; + } + } + } + else + { + c -= '0'; + while (c < 10) + { + val = val * 10 + c; + c = *param++ - '0'; + } + } + + *valp = val; + return param - 1; +} + +void +md_number_to_chars (buf, val, nbytes) +char *buf; +long val; +int nbytes; +{ + switch (nbytes) + { + case 4: + *buf++ = val >> 24; + *buf++ = val >> 16; + case 2: + *buf++ = val >> 8; + case 1: + *buf = val; + break; + + default: + abort (); + } +} + +#ifdef comment + +void +md_number_to_imm (buf, val, nbytes, fixP, seg_type) +unsigned char *buf; +unsigned int val; +int nbytes; +fixS *fixP; +int seg_type; +{ + if (seg_type != N_TEXT || fixP->fx_r_type == NO_RELOC) + { + switch (nbytes) + { + case 4: + *buf++ = val >> 24; + *buf++ = val >> 16; + case 2: + *buf++ = val >> 8; + case 1: + *buf = val; + break; + + default: + abort (); + } + return; + } + + switch (fixP->fx_r_type) + { + case RELOC_IW16: + buf[2] = val >> 8; + buf[3] = val; + break; + + case RELOC_LO16: + buf[0] = val >> 8; + buf[1] = val; + break; + + case RELOC_HI16: + buf[0] = val >> 24; + buf[1] = val >> 16; + break; + + case RELOC_PC16: + val += 4; + buf[0] = val >> 10; + buf[1] = val >> 2; + break; + + case RELOC_PC26: + val += 4; + buf[0] |= (val >> 26) & 0x03; + buf[1] = val >> 18; + buf[2] = val >> 10; + buf[3] = val >> 2; + break; + + case RELOC_32: + buf[0] = val >> 24; + buf[1] = val >> 16; + buf[2] = val >> 8; + buf[3] = val; + break; + + default: + as_fatal ("Bad relocation type"); + break; + } +} +#endif /* comment */ + +/* Apply a fixS to the frags, now that we know the value it ought to + hold. */ + +void md_apply_fix(fixP, val) +fixS *fixP; +long val; +{ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + + fixP->fx_addnumber = val; + + + switch (fixP->fx_r_type) { + + case RELOC_IW16: + buf[2] = val >> 8; + buf[3] = val; + break; + + case RELOC_LO16: + buf[0] = val >> 8; + buf[1] = val; + break; + + case RELOC_HI16: + buf[0] = val >> 24; + buf[1] = val >> 16; + break; + + case RELOC_PC16: + val += 4; + buf[0] = val >> 10; + buf[1] = val >> 2; + break; + + case RELOC_PC26: + val += 4; + buf[0] |= (val >> 26) & 0x03; + buf[1] = val >> 18; + buf[2] = val >> 10; + buf[3] = val >> 2; + break; + + case RELOC_32: + buf[0] = val >> 24; + buf[1] = val >> 16; + buf[2] = val >> 8; + buf[3] = val; + break; + + case NO_RELOC: + switch (fixP->fx_size) { + case 4: + *buf++ = val >> 24; + *buf++ = val >> 16; + case 2: + *buf++ = val >> 8; + case 1: + *buf = val; + break; + + default: + abort (); + } + + default: + as_bad("bad relocation type: 0x%02x", fixP->fx_r_type); + break; + } + + return; +} /* md_apply_fix() */ + +void +md_number_to_disp (buf, val, nbytes) +char *buf; +int val; +int nbytes; +{ + as_fatal ("md_number_to_disp not defined"); + md_number_to_chars (buf, val, nbytes); +} + +void +md_number_to_field (buf, val, nbytes) +char *buf; +int val; +int nbytes; +{ + as_fatal ("md_number_to_field not defined"); + md_number_to_chars (buf, val, nbytes); +} + +#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 */ +} + +int md_short_jump_size = 4; + +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; +{ + ptr[0] = 0xc0; ptr[1] = 0x00; ptr[2] = 0x00; ptr[3] = 0x00; + fix_new (frag, + ptr - frag->fr_literal, + 4, + to_symbol, + (symbolS *) 0, + (long int) 0, + 0, + RELOC_PC26); /* Botch: Shouldn't this be RELOC_PC16? */ +} + +int md_long_jump_size = 4; + +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; +{ + ptr[0] = 0xc0; ptr[1] = 0x00; ptr[2] = 0x00; ptr[3] = 0x00; + fix_new (frag, + ptr - frag->fr_literal, + 4, + to_symbol, + (symbolS *) 0, + (long int) 0, + 0, + RELOC_PC26); +} + +int +md_estimate_size_before_relax (fragP, segment_type) + fragS *fragP; + segT segment_type; +{ + as_fatal("Relaxation should never occur"); + return(0); +} + +const relax_typeS md_relax_table[] = {0}; + +void +md_convert_frag (headers, fragP) +object_headers *headers; + fragS *fragP; +{ + as_fatal ("Relaxation should never occur"); +} + +void +md_end () +{ +} + +#ifdef comment + +/* + * Risc relocations are completely different, so it needs + * this machine dependent routine to emit them. + */ +void +emit_relocations (fixP, segment_address_in_file) + fixS *fixP; + relax_addressT segment_address_in_file; +{ + struct reloc_info_m88k ri; + symbolS *symbolP; + extern char *next_object_file_charP; + + bzero ((char *) &ri, sizeof (ri)); + for (; fixP; fixP = fixP->fx_next) { + + if (fixP->fx_r_type >= NO_RELOC) { + fprintf (stderr, "fixP->fx_r_type = %d\n", fixP->fx_r_type); + abort (); + } + + if ((symbolP = fixP->fx_addsy) != NULL) { + ri.r_address = fixP->fx_frag->fr_address + + fixP->fx_where - segment_address_in_file; + if ((symbolP->sy_type & N_TYPE) == N_UNDF) { + ri.r_extern = 1; + ri.r_symbolnum = symbolP->sy_number; + } else { + ri.r_extern = 0; + ri.r_symbolnum = symbolP->sy_type & N_TYPE; + } + if (symbolP && symbolP->sy_frag) { + ri.r_addend = symbolP->sy_frag->fr_address; + } + ri.r_type = fixP->fx_r_type; + if (fixP->fx_pcrel) { +/* ri.r_addend -= fixP->fx_where; */ + ri.r_addend -= ri.r_address; + } else { + ri.r_addend = fixP->fx_addnumber; + } + +/* md_ri_to_chars ((char *) &ri, ri); */ + append (&next_object_file_charP, (char *)& ri, sizeof (ri)); + } + } + return; +} +#endif /* comment */ + +/* Translate internal representation of relocation info to target format. + + On m88k: first 4 bytes are normal unsigned long address, + next three bytes are index, most sig. byte first. + Byte 7 is broken up with bit 7 as external, + bits 6, 5, & 4 unused, and the lower four bits as relocation + type. + Next 4 bytes are long addend. */ + +void tc_aout_fix_to_chars(where, fixP, segment_address_in_file) +char *where; +fixS *fixP; +relax_addressT segment_address_in_file; +{ + long r_index; + long r_extern; + long r_addend = 0; + long r_address; + + know(fixP->fx_addsy); + + if (!S_IS_DEFINED(fixP->fx_addsy)) { + r_extern = 1; + r_index = fixP->fx_addsy->sy_number; + } else { + r_extern = 0; + r_index = S_GET_TYPE(fixP->fx_addsy); + } + + /* this is easy */ + md_number_to_chars(where, + r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, + 4); + + /* now the fun stuff */ + where[4] = (r_index >> 16) & 0x0ff; + where[5] = (r_index >> 8) & 0x0ff; + where[6] = r_index & 0x0ff; + where[7] = ((r_extern << 7) & 0x80) | (0 & 0x70) | (fixP->fx_r_type & 0xf); + + /* Also easy */ + if (fixP->fx_addsy->sy_frag) { + r_addend = fixP->fx_addsy->sy_frag->fr_address; + } + + if (fixP->fx_pcrel) { + r_addend -= r_address; + } else { + r_addend = fixP->fx_addnumber; + } + + md_number_to_chars(&where[8], r_addend, 4); + + return; +} /* tc_aout_fix_to_chars() */ + + +static void +s_bss() +{ + char *name; + char c; + char *p; + int temp, bss_align = 1; + symbolS *symbolP; + extern char is_end_of_line[256]; + + 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 (*input_line_pointer == ',') + { + input_line_pointer++; + bss_align = get_absolute_expression(); + while (local_bss_counter % bss_align != 0) + local_bss_counter++; + } + + if (!S_IS_DEFINED(symbolP) + || (S_GET_SEGMENT(symbolP) == SEG_BSS + && S_GET_VALUE(symbolP) == local_bss_counter)) { + S_SET_VALUE(symbolP, local_bss_counter); + S_SET_SEGMENT(symbolP, SEG_BSS); + symbolP->sy_frag = &bss_address_frag; + local_bss_counter += temp; + } else { + as_warn( "Ignoring attempt to re-define symbol from %d. to %d.", + S_GET_VALUE(symbolP), local_bss_counter ); + } + while (!is_end_of_line[*input_line_pointer]) + { + input_line_pointer++; + } + + return; +} + +/* We have no need to default values of symbols. */ + +/* ARGSUSED */ +symbolS *md_undefined_symbol(name) +char *name; +{ + return 0; +} /* md_undefined_symbol() */ + +/* Parse an operand that is machine-specific. + We just return without modifying the expression if we have nothing + to do. */ + +/* ARGSUSED */ +void md_operand(expressionP) +expressionS *expressionP; +{ +} /* md_operand() */ + +/* Round up a section size to the appropriate boundary. */ +long md_section_align(segment, size) +segT segment; +long size; +{ + return((size + 7) & ~7); /* Round all sects to multiple of 8 */ +} /* md_section_align() */ + +/* Exactly what point is a PC-relative offset relative TO? + On the sparc, they're relative to the address of the offset, plus + its size. This gets us to the following instruction. + (??? Is this right? FIXME-SOON) */ +long md_pcrel_from(fixP) +fixS *fixP; +{ + return(fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address); +} /* md_pcrel_from() */ + + /* end of tc-m88k.c */ diff --git a/gnu/usr.bin/as/config/tc-m88k.h b/gnu/usr.bin/as/config/tc-m88k.h new file mode 100644 index 000000000000..d5960d15e194 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-m88k.h @@ -0,0 +1,35 @@ +/* m88k.h -- Assembler for the Motorola 88000 + Contributed by Devon Bowen of Buffalo University + and Torbjorn Granlund of the Swedish Institute of Computer Science. + Copyright (C) 1989-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define TC_M88K 1 + +#define NO_LISTING +#define NO_DOT_PSEUDOS +#define ALLOW_ATSIGN + +#define LOCAL_LABEL(name) (name[0] == '@' \ + && ( name[1] == 'L' || name[1] == '.' )) + +#define tc_crawl_symbol_chain(a) {;} /* not used */ +#define tc_headers_hook(a) {;} /* not used */ +#define tc_aout_pre_write_hook(x) {;} /* not used */ + + /* end of tc-m88k.h */ diff --git a/gnu/usr.bin/as/config/tc-mips.c b/gnu/usr.bin/as/config/tc-mips.c new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-mips.c diff --git a/gnu/usr.bin/as/config/tc-mips.h b/gnu/usr.bin/as/config/tc-mips.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-mips.h diff --git a/gnu/usr.bin/as/config/tc-ns32k.c b/gnu/usr.bin/as/config/tc-ns32k.c new file mode 100644 index 000000000000..02d86c442806 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-ns32k.c @@ -0,0 +1,1923 @@ +/* ns32k.c -- Assemble on the National Semiconductor 32k series + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/*#define SHOW_NUM 1*/ /* uncomment for debugging */ + +#include <stdio.h> +#include <ctype.h> +#ifdef USG +#include <string.h> +#else +#include <strings.h> +#endif +#include "opcode/ns32k.h" + +#include "as.h" + +#include "obstack.h" + +/* Macros */ +#define IIF_ENTRIES 13 /* number of entries in iif */ +#define PRIVATE_SIZE 256 /* size of my garbage memory */ +#define MAX_ARGS 4 +#define DEFAULT -1 /* addr_mode returns this value when plain constant or label is encountered */ + +#define IIF(ptr,a1,c1,e1,g1,i1,k1,m1,o1,q1,s1,u1) \ + iif.iifP[ptr].type= a1; \ + iif.iifP[ptr].size= c1; \ + iif.iifP[ptr].object= e1; \ + iif.iifP[ptr].object_adjust= g1; \ + iif.iifP[ptr].pcrel= i1; \ + iif.iifP[ptr].pcrel_adjust= k1; \ + iif.iifP[ptr].im_disp= m1; \ + iif.iifP[ptr].relax_substate= o1; \ + iif.iifP[ptr].bit_fixP= q1; \ + iif.iifP[ptr].addr_mode= s1; \ + iif.iifP[ptr].bsr= u1; + +#ifdef TE_SEQUENT +#define LINE_COMMENT_CHARS "|" +#define ABSOLUTE_PREFIX '@' +#define IMMEDIATE_PREFIX '#' +#endif + +#ifndef LINE_COMMENT_CHARS +#define LINE_COMMENT_CHARS "#" +#endif + +char comment_chars[] = "#"; +char line_comment_chars[] = LINE_COMMENT_CHARS; +#if !defined(ABSOLUTE_PREFIX) && !defined(IMMEDIATE_PREFIX) +#define ABSOLUTE_PREFIX '@' /* One or the other MUST be defined */ +#endif + +struct addr_mode { + char mode; /* addressing mode of operand (0-31) */ + char scaled_mode; /* mode combined with scaled mode */ + char scaled_reg; /* register used in scaled+1 (1-8) */ + char float_flag; /* set if R0..R7 was F0..F7 ie a floating-point-register */ + char am_size; /* estimated max size of general addr-mode parts*/ + char im_disp; /* if im_disp == 1 we have a displacement */ + char pcrel; /* 1 if pcrel, this is really redundant info */ + char disp_suffix[2]; /* length of displacement(s), 0=undefined */ + char *disp[2]; /* pointer(s) at displacement(s) + or immediates(s) (ascii) */ + char index_byte; /* index byte */ +}; +typedef struct addr_mode addr_modeS; + + +char *freeptr,*freeptr_static; /* points at some number of free bytes */ +struct hash_control *inst_hash_handle; + +struct ns32k_opcode *desc; /* pointer at description of instruction */ +addr_modeS addr_modeP; +char EXP_CHARS[] = "eE"; +char FLT_CHARS[] = "fd"; /* we don't want to support lowercase, do we */ + +/* UPPERCASE denotes live names + * when an instruction is built, IIF is used as an intermidiate form to store + * the actual parts of the instruction. A ns32k machine instruction can + * be divided into a couple of sub PARTs. When an instruction is assembled + * the appropriate PART get an assignment. When an IIF has been completed it's + * converted to a FRAGment as specified in AS.H */ + +/* internal structs */ +struct option { + char *pattern; + unsigned long or; + unsigned long and; +}; + +typedef struct { + int type; /* how to interpret object */ + int size; /* Estimated max size of object */ + unsigned long object; /* binary data */ + int object_adjust; /* number added to object */ + int pcrel; /* True if object is pcrel */ + int pcrel_adjust; /* length in bytes from the + instruction start to the + displacement */ + int im_disp; /* True if the object is a displacement */ + relax_substateT relax_substate; /* Initial relaxsubstate */ + bit_fixS *bit_fixP; /* Pointer at bit_fix struct */ + int addr_mode; /* What addrmode do we associate with this iif-entry */ + char bsr; /* Sequent hack */ +}iif_entryT; /* Internal Instruction Format */ + +struct int_ins_form { + int instr_size; /* Max size of instruction in bytes. */ + iif_entryT iifP[IIF_ENTRIES + 1]; +}; +struct int_ins_form iif; +expressionS exprP; +char *input_line_pointer; +/* description of the PARTs in IIF + *object[n]: + * 0 total length in bytes of entries in iif + * 1 opcode + * 2 index_byte_a + * 3 index_byte_b + * 4 disp_a_1 + * 5 disp_a_2 + * 6 disp_b_1 + * 7 disp_b_2 + * 8 imm_a + * 9 imm_b + * 10 implied1 + * 11 implied2 + * + * For every entry there is a datalength in bytes. This is stored in size[n]. + * 0, the objectlength is not explicitly given by the instruction + * and the operand is undefined. This is a case for relaxation. + * Reserve 4 bytes for the final object. + * + * 1, the entry contains one byte + * 2, the entry contains two bytes + * 3, the entry contains three bytes + * 4, the entry contains four bytes + * etc + * + * Furthermore, every entry has a data type identifier in type[n]. + * + * 0, the entry is void, ignore it. + * 1, the entry is a binary number. + * 2, the entry is a pointer at an expression. + * Where expression may be as simple as a single '1', + * and as complicated as foo-bar+12, + * foo and bar may be undefined but suffixed by :{b|w|d} to + * control the length of the object. + * + * 3, the entry is a pointer at a bignum struct + * + * + * The low-order-byte coresponds to low physical memory. + * Obviously a FRAGment must be created for each valid disp in PART whose + * datalength is undefined (to bad) . + * The case where just the expression is undefined is less severe and is + * handled by fix. Here the number of bytes in the objectfile is known. + * With this representation we simplify the assembly and separates the + * machine dependent/independent parts in a more clean way (said OE) + */ + +struct option opt1[]= /* restore, exit */ +{ + { "r0", 0x80, 0xff }, + { "r1", 0x40, 0xff }, + { "r2", 0x20, 0xff }, + { "r3", 0x10, 0xff }, + { "r4", 0x08, 0xff }, + { "r5", 0x04, 0xff }, + { "r6", 0x02, 0xff }, + { "r7", 0x01, 0xff }, + { 0 , 0x00, 0xff } +}; +struct option opt2[]= /* save, enter */ +{ + { "r0", 0x01, 0xff }, + { "r1", 0x02, 0xff }, + { "r2", 0x04, 0xff }, + { "r3", 0x08, 0xff }, + { "r4", 0x10, 0xff }, + { "r5", 0x20, 0xff }, + { "r6", 0x40, 0xff }, + { "r7", 0x80, 0xff }, + { 0 , 0x00, 0xff } +}; +struct option opt3[]= /* setcfg */ +{ + { "c", 0x8, 0xff }, + { "m", 0x4, 0xff }, + { "f", 0x2, 0xff }, + { "i", 0x1, 0xff }, + { 0 , 0x0, 0xff } +}; +struct option opt4[]= /* cinv */ +{ + { "a", 0x4, 0xff }, + { "i", 0x2, 0xff }, + { "d", 0x1, 0xff }, + { 0 , 0x0, 0xff } +}; +struct option opt5[]= /* string inst */ +{ + { "b", 0x2, 0xff }, + { "u", 0xc, 0xff }, + { "w", 0x4, 0xff }, + { 0 , 0x0, 0xff } +}; +struct option opt6[]= /* plain reg ext,cvtp etc */ +{ + { "r0", 0x00, 0xff }, + { "r1", 0x01, 0xff }, + { "r2", 0x02, 0xff }, + { "r3", 0x03, 0xff }, + { "r4", 0x04, 0xff }, + { "r5", 0x05, 0xff }, + { "r6", 0x06, 0xff }, + { "r7", 0x07, 0xff }, + { 0 , 0x00, 0xff } +}; + +#if !defined(NS32032) && !defined(NS32532) +#define NS32032 +#endif + +struct option cpureg_532[]= /* lpr spr */ +{ + { "us", 0x0, 0xff }, + { "dcr", 0x1, 0xff }, + { "bpc", 0x2, 0xff }, + { "dsr", 0x3, 0xff }, + { "car", 0x4, 0xff }, + { "fp", 0x8, 0xff }, + { "sp", 0x9, 0xff }, + { "sb", 0xa, 0xff }, + { "usp", 0xb, 0xff }, + { "cfg", 0xc, 0xff }, + { "psr", 0xd, 0xff }, + { "intbase", 0xe, 0xff }, + { "mod", 0xf, 0xff }, + { 0 , 0x00, 0xff } +}; +struct option mmureg_532[]= /* lmr smr */ +{ + { "mcr", 0x9, 0xff }, + { "msr", 0xa, 0xff }, + { "tear", 0xb, 0xff }, + { "ptb0", 0xc, 0xff }, + { "ptb1", 0xd, 0xff }, + { "ivar0", 0xe, 0xff }, + { "ivar1", 0xf, 0xff }, + { 0 , 0x0, 0xff } +}; + +struct option cpureg_032[]= /* lpr spr */ +{ + { "upsr", 0x0, 0xff }, + { "fp", 0x8, 0xff }, + { "sp", 0x9, 0xff }, + { "sb", 0xa, 0xff }, + { "psr", 0xd, 0xff }, + { "intbase", 0xe, 0xff }, + { "mod", 0xf, 0xff }, + { 0 , 0x0, 0xff } +}; +struct option mmureg_032[]= /* lmr smr */ +{ + { "bpr0", 0x0, 0xff }, + { "bpr1", 0x1, 0xff }, + { "pf0", 0x4, 0xff }, + { "pf1", 0x5, 0xff }, + { "sc", 0x8, 0xff }, + { "msr", 0xa, 0xff }, + { "bcnt", 0xb, 0xff }, + { "ptb0", 0xc, 0xff }, + { "ptb1", 0xd, 0xff }, + { "eia", 0xf, 0xff }, + { 0 , 0x0, 0xff } +}; + +#if defined(NS32532) +struct option *cpureg = cpureg_532; +struct option *mmureg = mmureg_532; +#else +struct option *cpureg = cpureg_032; +struct option *mmureg = mmureg_032; +#endif + + +const pseudo_typeS md_pseudo_table[]={ /* so far empty */ + { 0, 0, 0 } +}; + +#define IND(x,y) (((x)<<2)+(y)) + +/* those are index's to relax groups in md_relax_table + ie it must be multiplied by 4 to point at a group start. Viz IND(x,y) + Se function relax_segment in write.c for more info */ + +#define BRANCH 1 +#define PCREL 2 + +/* those are index's to entries in a relax group */ + +#define BYTE 0 +#define WORD 1 +#define DOUBLE 2 +#define UNDEF 3 +/* Those limits are calculated from the displacement start in memory. + The ns32k uses the begining of the instruction as displacement base. + This type of displacements could be handled here by moving the limit window + up or down. I choose to use an internal displacement base-adjust as there + are other routines that must consider this. Also, as we have two various + offset-adjusts in the ns32k (acb versus br/brs/jsr/bcond), two set of limits + would have had to be used. + Now we dont have to think about that. */ + + +const relax_typeS md_relax_table[] = { + { 1, 1, 0, 0 }, + { 1, 1, 0, 0 }, + { 1, 1, 0, 0 }, + { 1, 1, 0, 0 }, + + { (63), (-64), 1, IND(BRANCH,WORD) }, + { (8192), (-8192), 2, IND(BRANCH,DOUBLE) }, + { 0, 0, 4, 0 }, + { 1, 1, 0, 0 } +}; + +/* Array used to test if mode contains displacements. + Value is true if mode contains displacement. */ + +char disp_test[] = { 0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1, + 1,1,1,0,0,1,1,0, + 1,1,1,1,1,1,1,1 }; + +/* Array used to calculate max size of displacements */ + +char disp_size[] = { 4,1,2,0,4 }; + + +#if __STDC__ == 1 + +static segT evaluate_expr(expressionS *resultP, char *ptr); +static void md_number_to_disp(char *buf, long val, int n); +static void md_number_to_imm(char *buf, long val, int n); + +#else /* not __STDC__ */ + +static segT evaluate_expr(); +static void md_number_to_disp(); +static void md_number_to_imm(); + +#endif /* not __STDC__ */ + +/* Parses a general operand into an addressingmode struct + + in: pointer at operand in ascii form + pointer at addr_mode struct for result + the level of recursion. (always 0 or 1) + + out: data in addr_mode struct + */ +int addr_mode(operand,addr_modeP,recursive_level) +char *operand; +register addr_modeS *addr_modeP; +int recursive_level; +{ + register char *str; + register int i; + register int strl; + register int mode; + int j; + mode = DEFAULT; /* default */ + addr_modeP->scaled_mode=0; /* why not */ + addr_modeP->scaled_reg=0; /* if 0, not scaled index */ + addr_modeP->float_flag=0; + addr_modeP->am_size=0; + addr_modeP->im_disp=0; + addr_modeP->pcrel=0; /* not set in this function */ + addr_modeP->disp_suffix[0]=0; + addr_modeP->disp_suffix[1]=0; + addr_modeP->disp[0]=NULL; + addr_modeP->disp[1]=NULL; + str=operand; + if (str[0] == 0) {return (0);} /* we don't want this */ + strl=strlen(str); + switch (str[0]) { + /* the following three case statements controls the mode-chars + this is the place to ed if you want to change them */ +#ifdef ABSOLUTE_PREFIX + case ABSOLUTE_PREFIX: + if (str[strl-1] == ']') break; + addr_modeP->mode=21; /* absolute */ + addr_modeP->disp[0]=str+1; + return (-1); +#endif +#ifdef IMMEDIATE_PREFIX + case IMMEDIATE_PREFIX: + if (str[strl-1] == ']') break; + addr_modeP->mode=20; /* immediate */ + addr_modeP->disp[0]=str+1; + return (-1); +#endif + case '.': + if (str[strl-1] != ']') { + switch (str[1]) { + case'-':case'+': + if (str[2] != '\000') { + addr_modeP->mode=27; /* pc-relativ */ + addr_modeP->disp[0]=str+2; + return (-1); + } + default: + as_warn("Invalid syntax in PC-relative addressing mode"); + return(0); + } + } + break; + case'e': + if (str[strl-1] != ']') { + if ((!strncmp(str,"ext(",4)) && strl>7) { /* external */ + addr_modeP->disp[0]=str+4; + i=0; + j=2; + do { /* disp[0]'s termination point */ + j+=1; + if (str[j] == '(') i++; + if (str[j] == ')') i--; + } while (j < strl && i != 0); + if (i != 0 || !(str[j+1] == '-' || str[j+1] == '+') ) { + as_warn("Invalid syntax in External addressing mode"); + return(0); + } + str[j]='\000'; /* null terminate disp[0] */ + addr_modeP->disp[1]=str+j+2; + addr_modeP->mode=22; + return (-1); + } + } + break; + default:; + } + strl=strlen(str); + switch (strl) { + case 2: + switch (str[0]) { + case'f':addr_modeP->float_flag=1; + case'r': + if (str[1] >= '0' && str[1] < '8') { + addr_modeP->mode=str[1]-'0'; + return (-1); + } + } + case 3: + if (!strncmp(str,"tos",3)) { + addr_modeP->mode=23; /* TopOfStack */ + return (-1); + } + default:; + } + if (strl>4) { + if (str[strl - 1] == ')') { + if (str[strl - 2] == ')') { + if (!strncmp(&str[strl-5],"(fp",3)) { + mode=16; /* Memory Relative */ + } + if (!strncmp(&str[strl-5],"(sp",3)) { + mode=17; + } + if (!strncmp(&str[strl-5],"(sb",3)) { + mode=18; + } + if (mode != DEFAULT) { /* memory relative */ + addr_modeP->mode=mode; + j=strl-5; /* temp for end of disp[0] */ + i=0; + do { + strl-=1; + if (str[strl] == ')') i++; + if (str[strl] == '(') i--; + } while (strl>-1 && i != 0); + if (i != 0) { + as_warn("Invalid syntax in Memory Relative addressing mode"); + return(0); + } + addr_modeP->disp[1]=str; + addr_modeP->disp[0]=str+strl+1; + str[j]='\000'; /* null terminate disp[0] */ + str[strl]='\000'; /* null terminate disp[1] */ + return (-1); + } + } + switch (str[strl-3]) { + case'r':case'R': + if (str[strl - 2] >= '0' && str[strl - 2] < '8' && str[strl - 4] == '(') { + addr_modeP->mode=str[strl-2]-'0'+8; + addr_modeP->disp[0]=str; + str[strl-4]=0; + return (-1); /* reg rel */ + } + default: + if (!strncmp(&str[strl-4],"(fp",3)) { + mode=24; + } + if (!strncmp(&str[strl-4],"(sp",3)) { + mode=25; + } + if (!strncmp(&str[strl-4],"(sb",3)) { + mode=26; + } + if (!strncmp(&str[strl-4],"(pc",3)) { + mode=27; + } + if (mode != DEFAULT) { + addr_modeP->mode=mode; + addr_modeP->disp[0]=str; + str[strl-4]='\0'; + return (-1); /* memory space */ + } + } + } + /* no trailing ')' do we have a ']' ? */ + if (str[strl - 1] == ']') { + switch (str[strl-2]) { + case'b':mode=28;break; + case'w':mode=29;break; + case'd':mode=30;break; + case'q':mode=31;break; + default:; + as_warn("Invalid scaled-indexed mode, use (b,w,d,q)"); + if (str[strl - 3] != ':' || str[strl - 6] != '[' || + str[strl - 5] == 'r' || str[strl - 4] < '0' || str[strl - 4] > '7') { + as_warn("Syntax in scaled-indexed mode, use [Rn:m] where n=[0..7] m={b,w,d,q}"); + } + } /* scaled index */ + { + if (recursive_level>0) { + as_warn("Scaled-indexed addressing mode combined with scaled-index"); + return(0); + } + addr_modeP->am_size+=1; /* scaled index byte */ + j=str[strl-4]-'0'; /* store temporary */ + str[strl-6]='\000'; /* nullterminate for recursive call */ + i=addr_mode(str,addr_modeP,1); + if (!i || addr_modeP->mode == 20) { + as_warn("Invalid or illegal addressing mode combined with scaled-index"); + return(0); + } + addr_modeP->scaled_mode=addr_modeP->mode; /* store the inferior mode */ + addr_modeP->mode=mode; + addr_modeP->scaled_reg=j+1; + return (-1); + } + } + } + addr_modeP->mode = DEFAULT; /* default to whatever */ + addr_modeP->disp[0]=str; + return (-1); +} + +/* ptr points at string + addr_modeP points at struct with result + This routine calls addr_mode to determine the general addr.mode of + the operand. When this is ready it parses the displacements for size + specifying suffixes and determines size of immediate mode via ns32k-opcode. + Also builds index bytes if needed. + */ +int get_addr_mode(ptr,addr_modeP) +char *ptr; +addr_modeS *addr_modeP; +{ + int tmp; + addr_mode(ptr,addr_modeP,0); + if (addr_modeP->mode == DEFAULT || addr_modeP->scaled_mode == -1) { + /* resolve ambigious operands, this shouldn't + be necessary if one uses standard NSC operand + syntax. But the sequent compiler doesn't!!! + This finds a proper addressinging mode if it + is implicitly stated. See ns32k-opcode.h */ + (void)evaluate_expr(&exprP,ptr); /* this call takes time Sigh! */ + if (addr_modeP->mode == DEFAULT) { + if (exprP.X_add_symbol || exprP.X_subtract_symbol) { + addr_modeP->mode=desc->default_model; /* we have a label */ + } else { + addr_modeP->mode=desc->default_modec; /* we have a constant */ + } + } else { + if (exprP.X_add_symbol || exprP.X_subtract_symbol) { + addr_modeP->scaled_mode=desc->default_model; + } else { + addr_modeP->scaled_mode=desc->default_modec; + } + } + /* must put this mess down in addr_mode to handle the scaled case better */ + } + /* It appears as the sequent compiler wants an absolute when we have a + label without @. Constants becomes immediates besides the addr case. + Think it does so with local labels too, not optimum, pcrel is better. + When I have time I will make gas check this and select pcrel when possible + Actually that is trivial. + */ + if (tmp=addr_modeP->scaled_reg) { /* build indexbyte */ + tmp--; /* remember regnumber comes incremented for flagpurpose */ + tmp|=addr_modeP->scaled_mode<<3; + addr_modeP->index_byte=(char)tmp; + addr_modeP->am_size+=1; + } + if (disp_test[addr_modeP->mode]) { /* there was a displacement, probe for length specifying suffix*/ + { + register char c; + register char suffix; + register char suffix_sub; + register int i; + register char *toP; + register char *fromP; + + addr_modeP->pcrel=0; + if (disp_test[addr_modeP->mode]) { /* there is a displacement */ + if (addr_modeP->mode == 27 || addr_modeP->scaled_mode == 27) { /* do we have pcrel. mode */ + addr_modeP->pcrel=1; + } + addr_modeP->im_disp=1; + for (i=0;i<2;i++) { + suffix_sub=suffix=0; + if (toP=addr_modeP->disp[i]) { /* suffix of expression, the largest size rules */ + fromP=toP; + while (c = *fromP++) { + *toP++=c; + if (c == ':') { + switch (*fromP) { + case '\0': + as_warn("Premature end of suffix--Defaulting to d"); + suffix=4; + continue; + case 'b':suffix_sub=1;break; + case 'w':suffix_sub=2;break; + case 'd':suffix_sub=4;break; + default: + as_warn("Bad suffix after ':' use {b|w|d} Defaulting to d"); + suffix=4; + } + fromP++; + toP--; /* So we write over the ':' */ + if (suffix<suffix_sub) suffix=suffix_sub; + } + } + *toP='\0'; /* terminate properly */ + addr_modeP->disp_suffix[i]=suffix; + addr_modeP->am_size+=suffix ? suffix : 4; + } + } + } + } + } else { + if (addr_modeP->mode == 20) { /* look in ns32k_opcode for size */ + addr_modeP->disp_suffix[0]=addr_modeP->am_size=desc->im_size; + addr_modeP->im_disp=0; + } + } + return addr_modeP->mode; +} + + +/* read an optionlist */ +void optlist(str,optionP,default_map) +char *str; /* the string to extract options from */ +struct option *optionP; /* how to search the string */ +unsigned long *default_map; /* default pattern and output */ +{ + register int i,j,k,strlen1,strlen2; + register char *patternP,*strP; + strlen1=strlen(str); + if (strlen1<1) { + as_fatal("Very short instr to option, ie you can't do it on a NULLstr"); + } + for (i = 0; optionP[i].pattern != 0; i++) { + strlen2=strlen(optionP[i].pattern); + for (j=0;j<strlen1;j++) { + patternP=optionP[i].pattern; + strP = &str[j]; + for (k=0;k<strlen2;k++) { + if (*(strP++) != *(patternP++)) break; + } + if (k == strlen2) { /* match */ + *default_map|=optionP[i].or; + *default_map&=optionP[i].and; + } + } + } +} +/* search struct for symbols + This function is used to get the short integer form of reg names + in the instructions lmr, smr, lpr, spr + return true if str is found in list */ + +int list_search(str,optionP,default_map) +char *str; /* the string to match */ +struct option *optionP; /* list to search */ +unsigned long *default_map; /* default pattern and output */ +{ + register int i; + for (i = 0; optionP[i].pattern != 0; i++) { + if (!strncmp(optionP[i].pattern,str,20)) { /* use strncmp to be safe */ + *default_map|=optionP[i].or; + *default_map&=optionP[i].and; + return -1; + } + } + as_warn("No such entry in list. (cpu/mmu register)"); + return 0; +} +static segT evaluate_expr(resultP,ptr) +expressionS *resultP; +char *ptr; +{ + register char *tmp_line; + register segT segment; + tmp_line = input_line_pointer; + input_line_pointer = ptr; + segment = expression(&exprP); + input_line_pointer = tmp_line; + return(segment); +} + +/* Convert operands to iif-format and adds bitfields to the opcode. + Operands are parsed in such an order that the opcode is updated from + its most significant bit, that is when the operand need to alter the + opcode. + Be carefull not to put to objects in the same iif-slot. + */ + +void encode_operand(argc,argv,operandsP,suffixP,im_size,opcode_bit_ptr) +int argc; +char **argv; +char *operandsP; +char *suffixP; +char im_size; +char opcode_bit_ptr; +{ + register int i,j; + int pcrel,tmp,b,loop,pcrel_adjust; + for (loop=0;loop<argc;loop++) { + i=operandsP[loop<<1]-'1'; /* what operand are we supposed to work on */ + if (i>3) as_fatal("Internal consistency error. check ns32k-opcode.h"); + pcrel=0; + pcrel_adjust=0; + tmp=0; + switch (operandsP[(loop<<1)+1]) { + case 'f': /* operand of sfsr turns out to be a nasty specialcase */ + opcode_bit_ptr-=5; + case 'F': /* 32 bit float general form */ + case 'L': /* 64 bit float */ + case 'Q': /* quad-word */ + case 'B': /* byte */ + case 'W': /* word */ + case 'D': /* double-word */ + case 'A': /* double-word gen-address-form ie no regs allowed */ + get_addr_mode(argv[i],&addr_modeP); + iif.instr_size+=addr_modeP.am_size; + if (opcode_bit_ptr == desc->opcode_size) b = 4; else b = 6; + for (j=b;j<(b+2);j++) { + if (addr_modeP.disp[j-b]) { + IIF(j, + 2, + addr_modeP.disp_suffix[j-b], + (unsigned long)addr_modeP.disp[j-b], + 0, + addr_modeP.pcrel, + iif.instr_size-addr_modeP.am_size, /* this aint used (now) */ + addr_modeP.im_disp, + IND(BRANCH,BYTE), + NULL, + addr_modeP.scaled_reg ? addr_modeP.scaled_mode:addr_modeP.mode, + 0); + } + } + opcode_bit_ptr-=5; + iif.iifP[1].object|=((long)addr_modeP.mode)<<opcode_bit_ptr; + if (addr_modeP.scaled_reg) { + j=b/2; + IIF(j,1,1, (unsigned long)addr_modeP.index_byte,0,0,0,0,0, NULL,-1,0); + } + break; + case 'b': /* multiple instruction disp */ + freeptr++; /* OVE:this is an useful hack */ + tmp = (int) sprintf(freeptr, + "((%s-1)*%d)\000", + argv[i], desc->im_size); + argv[i]=freeptr; + freeptr=(char*)tmp; + pcrel-=1; /* make pcrel 0 inspite of what case 'p': wants */ + /* fall thru */ + case 'p': /* displacement - pc relative addressing */ + pcrel+=1; + /* fall thru */ + case 'd': /* displacement */ + iif.instr_size+=suffixP[i] ? suffixP[i] : 4; + IIF(12, 2, suffixP[i], (unsigned long)argv[i], 0, + pcrel, pcrel_adjust, 1, IND(BRANCH,BYTE), NULL,-1,0); + break; + case 'H': /* sequent-hack: the linker wants a bit set when bsr */ + pcrel=1; + iif.instr_size+=suffixP[i] ? suffixP[i] : 4; + IIF(12, 2, suffixP[i], (unsigned long)argv[i], 0, + pcrel, pcrel_adjust, 1, IND(BRANCH,BYTE), NULL,-1,1);break; + case 'q': /* quick */ + opcode_bit_ptr-=4; + IIF(11,2,42,(unsigned long)argv[i],0,0,0,0,0, + bit_fix_new(4,opcode_bit_ptr,-8,7,0,1,0),-1,0); + break; + case 'r': /* register number (3 bits) */ + list_search(argv[i],opt6,&tmp); + opcode_bit_ptr-=3; + iif.iifP[1].object|=tmp<<opcode_bit_ptr; + break; + case 'O': /* setcfg instruction optionslist */ + optlist(argv[i],opt3,&tmp); + opcode_bit_ptr-=4; + iif.iifP[1].object|=tmp<<15; + break; + case 'C': /* cinv instruction optionslist */ + optlist(argv[i],opt4,&tmp); + opcode_bit_ptr-=4; + iif.iifP[1].object|=tmp<<15;/*insert the regtype in opcode */ + break; + case 'S': /* stringinstruction optionslist */ + optlist(argv[i],opt5,&tmp); + opcode_bit_ptr-=4; + iif.iifP[1].object|=tmp<<15; + break; + case 'u':case 'U': /* registerlist */ + IIF(10,1,1,0,0,0,0,0,0,NULL,-1,0); + switch (operandsP[(i<<1)+1]) { + case 'u': /* restore, exit */ + optlist(argv[i],opt1,&iif.iifP[10].object); + break; + case 'U': /* save,enter */ + optlist(argv[i],opt2,&iif.iifP[10].object); + break; + } + iif.instr_size+=1; + break; + case 'M': /* mmu register */ + list_search(argv[i],mmureg,&tmp); + opcode_bit_ptr-=4; + iif.iifP[1].object|=tmp<<opcode_bit_ptr; + break; + case 'P': /* cpu register */ + list_search(argv[i],cpureg,&tmp); + opcode_bit_ptr-=4; + iif.iifP[1].object|=tmp<<opcode_bit_ptr; + break; + case 'g': /* inss exts */ + iif.instr_size+=1; /* 1 byte is allocated after the opcode */ + IIF(10,2,1, + (unsigned long)argv[i], /* i always 2 here */ + 0,0,0,0,0, + bit_fix_new(3,5,0,7,0,0,0), /* a bit_fix is targeted to the byte */ + -1,0); + case 'G': + IIF(11,2,42, + (unsigned long)argv[i], /* i always 3 here */ + 0,0,0,0,0, + bit_fix_new(5,0,1,32,-1,0,-1),-1,0); + break; + case 'i': + iif.instr_size+=1; + b=2+i; /* put the extension byte after opcode */ + IIF(b,2,1,0,0,0,0,0,0,0,-1,0); + default: + as_fatal("Bad opcode-table-option, check in file ns32k-opcode.h"); + } + } +} + +/* in: instruction line + out: internal structure of instruction + that has been prepared for direct conversion to fragment(s) and + fixes in a systematical fashion + Return-value = recursive_level + */ +/* build iif of one assembly text line */ +int parse(line,recursive_level) +char *line; +int recursive_level; +{ + register char *lineptr,c,suffix_separator; + register int i; + int argc,arg_type; + char sqr,sep; + char suffix[MAX_ARGS],*argv[MAX_ARGS];/* no more than 4 operands */ + if (recursive_level <= 0) { /* called from md_assemble */ + for (lineptr=line; (*lineptr) != '\0' && (*lineptr) != ' '; lineptr++); + c = *lineptr; + *lineptr = '\0'; + desc = (struct ns32k_opcode*) hash_find(inst_hash_handle,line); + if (!desc) { + as_fatal("No such opcode"); + } + *lineptr = c; + } else { + lineptr = line; + } + argc = 0; + if (*desc->operands != NULL) { + if (*lineptr++ != '\0') { + sqr='['; + sep=','; + while (*lineptr != '\0') { + if (desc->operands[argc << 1]) { + suffix[argc] = 0; + arg_type = + desc->operands[(argc << 1) + 1]; + switch (arg_type) { + case 'd': + case 'b': + case 'p': + case 'H': /* the operand is supposed to be a displacement */ + /* Hackwarning: do not forget to update the 4 cases above when editing ns32k-opcode.h */ + suffix_separator = ':'; + break; + default: + suffix_separator = '\255'; /* if this char occurs we loose */ + } + suffix[argc] = 0; /* 0 when no ':' is encountered */ + argv[argc] = freeptr; + *freeptr = '\0'; + while ((c = *lineptr) != '\0' && c != sep) { + if (c == sqr) { + if (sqr == '[') { + sqr = ']'; + sep = '\0'; + } else { + sqr = '['; + sep = ','; + } + } + if (c == suffix_separator) { /* ':' - label/suffix separator */ + switch (lineptr[1]) { + case 'b': suffix[argc] = 1; break; + case 'w': suffix[argc] = 2; break; + case 'd': suffix[argc] = 4; break; + default: as_warn("Bad suffix, defaulting to d"); + suffix[argc] = 4; + if (lineptr[1] == '\0' || lineptr[1] == sep) { + lineptr += 1; + continue; + } + } + lineptr += 2; + continue; + } + *freeptr++ = c; + lineptr++; + } + *freeptr++ = '\0'; + argc += 1; + if (*lineptr == '\0') continue; + lineptr += 1; + } else { + as_fatal("Too many operands passed to instruction"); + } + } + } + } + if (argc != strlen(desc->operands) / 2) { + if (strlen(desc->default_args) != 0) { /* we can apply default, dont goof */ + if (parse(desc->default_args,1) != 1) { /* check error in default */ + as_fatal("Wrong numbers of operands in default, check ns32k-opcodes.h"); + } + } else { + as_fatal("Wrong number of operands"); + } + + } + for (i = 0; i < IIF_ENTRIES; i++) { + iif.iifP[i].type = 0; /* mark all entries as void*/ + } + + /* build opcode iif-entry */ + iif.instr_size = desc->opcode_size / 8; + IIF(1,1,iif.instr_size,desc->opcode_seed,0,0,0,0,0,0,-1,0); + + /* this call encodes operands to iif format */ + if (argc) { + encode_operand(argc, + argv, + &desc->operands[0], + &suffix[0], + desc->im_size, + desc->opcode_size); + } + return(recursive_level); +} + + +/* Convert iif to fragments. + From this point we start to dribble with functions in other files than + this one.(Except hash.c) So, if it's possible to make an iif for an other + CPU, you don't need to know what frags, relax, obstacks, etc is in order + to port this assembler. You only need to know if it's possible to reduce + your cpu-instruction to iif-format (takes some work) and adopt the other + md_? parts according to given instructions + Note that iif was invented for the clean ns32k`s architecure. + */ +void convert_iif() { + int i; + int j; + fragS *inst_frag; + char *inst_offset; + char **inst_opcode; + char *memP; + segT segment; + int l; + int k; + int rem_size; /* count the remaining bytes of instruction */ + char type; + char size = 0; + int size_so_far = 0; /* used to calculate pcrel_adjust */ + int pcrel_symbols=0; /* kludge by jkp@hut.fi to make + movd _foo(pc),_bar(pc) work. + It should be done with two frags + for one insn, but I don't understand + enough to make it work */ + + rem_size=iif.instr_size; + memP=frag_more(iif.instr_size); /* make sure we have enough bytes for instruction */ + inst_opcode=memP; + inst_offset=(char*)(memP-frag_now->fr_literal); + inst_frag=frag_now; + for (i=0;i<IIF_ENTRIES;i++) { /* jkp kludge alert */ + if (iif.iifP[i].type && iif.iifP[i].size == 0 && + iif.iifP[i].pcrel) { + evaluate_expr(&exprP,(char*)iif.iifP[i].object); + if (exprP.X_add_symbol || exprP.X_subtract_symbol) + pcrel_symbols++; + } + } + for (i=0;i<IIF_ENTRIES;i++) { + if (type=iif.iifP[i].type) { /* the object exist, so handle it */ + switch (size=iif.iifP[i].size) { + case 42: size=0; /* it's a bitfix that operates on an existing object*/ + if (iif.iifP[i].bit_fixP->fx_bit_base) { /* expand fx_bit_base to point at opcode */ + iif.iifP[i].bit_fixP->fx_bit_base=(long)inst_opcode; + } + case 8: /* bignum or doublefloat */ + memset(memP, '\0', 8); + case 1:case 2:case 3:case 4:/* the final size in objectmemory is known */ + j=(unsigned long)iif.iifP[i].bit_fixP; + switch (type) { + case 1: /* the object is pure binary */ + if (j || iif.iifP[i].pcrel) { + fix_new_ns32k(frag_now, + (long)(memP-frag_now->fr_literal), + size, + 0, + 0, + iif.iifP[i].object, + iif.iifP[i].pcrel, + (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/ + iif.iifP[i].im_disp, + j, + iif.iifP[i].bsr); /* sequent hack */ + } else { /* good, just put them bytes out */ + switch (iif.iifP[i].im_disp) { + case 0: + md_number_to_chars(memP,iif.iifP[i].object,size);break; + case 1: + md_number_to_disp(memP,iif.iifP[i].object,size);break; + default: as_fatal("iif convert internal pcrel/binary"); + } + } + memP+=size; + rem_size-=size; + break; + case 2: /* the object is a pointer at an expression, so unpack + it, note that bignums may result from the expression + */ + if ((segment = evaluate_expr(&exprP, (char*)iif.iifP[i].object)) == SEG_BIG || size == 8) { + if ((k=exprP.X_add_number)>0) { /* we have a bignum ie a quad */ + /* this can only happens in a long suffixed instruction */ + memset(memP, '\0', size); /* size normally is 8 */ + if (k*2>size) as_warn("Bignum too big for long"); + if (k == 3) memP += 2; + for (l=0;k>0;k--,l+=2) { + md_number_to_chars(memP+l,generic_bignum[l>>1],sizeof(LITTLENUM_TYPE)); + } + } else { /* flonum */ + LITTLENUM_TYPE words[4]; + + switch (size) { + case 4: + gen_to_words(words,2,8); + md_number_to_imm(memP ,(long)words[0],sizeof(LITTLENUM_TYPE)); + md_number_to_imm(memP+sizeof(LITTLENUM_TYPE),(long)words[1],sizeof(LITTLENUM_TYPE)); + break; + case 8: + gen_to_words(words,4,11); + md_number_to_imm(memP ,(long)words[0],sizeof(LITTLENUM_TYPE)); + md_number_to_imm(memP+sizeof(LITTLENUM_TYPE) ,(long)words[1],sizeof(LITTLENUM_TYPE)); + md_number_to_imm(memP+2*sizeof(LITTLENUM_TYPE),(long)words[2],sizeof(LITTLENUM_TYPE)); + md_number_to_imm(memP+3*sizeof(LITTLENUM_TYPE),(long)words[3],sizeof(LITTLENUM_TYPE)); + break; + } + } + memP+=size; + rem_size-=size; + break; + } + if (j || + exprP.X_add_symbol || + exprP.X_subtract_symbol || + iif.iifP[i].pcrel) { /* fixit */ + /* the expression was undefined due to an undefined label */ + /* create a fix so we can fix the object later */ + exprP.X_add_number+=iif.iifP[i].object_adjust; + fix_new_ns32k(frag_now, + (long)(memP-frag_now->fr_literal), + size, + exprP.X_add_symbol, + exprP.X_subtract_symbol, + exprP.X_add_number, + iif.iifP[i].pcrel, + (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/ + iif.iifP[i].im_disp, + j, + iif.iifP[i].bsr); /* sequent hack */ + + } else { /* good, just put them bytes out */ + switch (iif.iifP[i].im_disp) { + case 0: + md_number_to_imm(memP,exprP.X_add_number,size);break; + case 1: + md_number_to_disp(memP,exprP.X_add_number,size);break; + default: as_fatal("iif convert internal pcrel/pointer"); + } + } + memP+=size; + rem_size-=size; + break; + default: as_fatal("Internal logic error in iif.iifP[n].type"); + } + break; + case 0: /* To bad, the object may be undefined as far as its final + nsize in object memory is concerned. The size of the object + in objectmemory is not explicitly given. + If the object is defined its length can be determined and + a fix can replace the frag. + */ + { + int temp; + segment = evaluate_expr(&exprP, (char*)iif.iifP[i].object); + if (((exprP.X_add_symbol || exprP.X_subtract_symbol) && + !iif.iifP[i].pcrel) || pcrel_symbols >= 2 /*jkp*/) { /* OVE: hack, clamp to 4 bytes */ + size=4; /* we dont wan't to frag this, use 4 so it reaches */ + fix_new_ns32k(frag_now, + (long)(memP-frag_now->fr_literal), + size, + exprP.X_add_symbol, + exprP.X_subtract_symbol, + exprP.X_add_number, + pcrel_symbols >= 2 ? iif.iifP[i].pcrel : 0, /*jkp*//* never iif.iifP[i].pcrel, */ + (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/ + 1, /* always iif.iifP[i].im_disp, */ + 0,0); + memP+=size; + rem_size-=4; + break; /* exit this absolute hack */ + } + + if (exprP.X_add_symbol || exprP.X_subtract_symbol) { /* frag it */ + if (exprP.X_subtract_symbol) { /* We cant relax this case */ + as_fatal("Can't relax difference"); + } else { + /* at this stage we must undo some of the effect caused + by frag_more, ie we must make sure that frag_var causes + frag_new to creat a valid fix-size in the frag it`s closing + */ + temp = -(rem_size-4); + obstack_blank_fast(&frags,temp); + /* we rewind none, some or all of the requested size we + requested by the first frag_more for this iif chunk. + Note: that we allocate 4 bytes to an object we NOT YET + know the size of, thus rem_size-4. + */ + (void) frag_variant(rs_machine_dependent, + 4, + 0, + IND(BRANCH,UNDEF), /* expecting the worst */ + exprP.X_add_symbol, + exprP.X_add_number, + (char*)inst_opcode, + (char)size_so_far, /*iif.iifP[i].pcrel_adjust);*/ + iif.iifP[i].bsr); /* sequent linker hack */ + rem_size -= 4; + if (rem_size > 0) { + memP = frag_more(rem_size); + } + } + } else {/* Double work, this is done in md_number_to_disp */ + /* exprP.X_add_number; fixme-soon what was this supposed to be? xoxorich. */ + if (-64 <= exprP.X_add_number && exprP.X_add_number <= 63) { + size = 1; + } else { + if (-8192 <= exprP.X_add_number && exprP.X_add_number <= 8191) { + size = 2; + + /* Dave Taylor <taylor@think.com> says: Note: The reason the lower + limit is -0x1f000000 and not -0x20000000 is that, according to + Nat'l Semi's data sheet on the ns32532, ``the pattern 11100000 + for the most significant byte of the displacement is reserved by + National for future enhancements''. */ + } else if (/* -0x40000000 <= exprP.X_add_number && + exprP.X_add_number <= 0x3fffffff */ + -0x1f000000 <= exprP.X_add_number && + exprP.X_add_number <= 0x1fffffff) { + size = 4; + } else { + as_warn("Displacement too large for :d"); + size = 4; + } + } + /* rewind the bytes not used */ + temp = -(4-size); + md_number_to_disp(memP,exprP.X_add_number,size); + obstack_blank_fast(&frags,temp); + memP += size; + rem_size -= 4; /* we allocated this amount */ + } + } + break; + default: + as_fatal("Internal logic error in iif.iifP[].type"); + } + size_so_far += size; + size = 0; + } + } +} + +void md_assemble(line) +char *line; +{ + freeptr=freeptr_static; + parse(line,0); /* explode line to more fix form in iif */ + convert_iif(); /* convert iif to frags, fix's etc */ +#ifdef SHOW_NUM + printf(" \t\t\t%s\n",line); +#endif +} + + +void md_begin() { + /* build a hashtable of the instructions */ + register const struct ns32k_opcode *ptr; + register char *stat; + inst_hash_handle=hash_new(); + for (ptr=ns32k_opcodes;ptr<endop;ptr++) { + if (*(stat=hash_insert(inst_hash_handle,ptr->name,(char*)ptr))) { + as_fatal("Can't hash %s: %s", ptr->name,stat); /*fatal*/ + exit(0); + } + } + freeptr_static=(char*)malloc(PRIVATE_SIZE); /* some private space please! */ +} + + +void + md_end() { + free(freeptr_static); + } + +/* Must be equal to MAX_PRECISON in atof-ieee.c */ +#define MAX_LITTLENUMS 6 + +/* Turn the string pointed to by litP into a floating point constant of type + type, and emit the appropriate bytes. The number of LITTLENUMS emitted + is stored in *sizeP. An error message is returned, or NULL on OK. + */ +char * + md_atof(type,litP,sizeP) +char type; +char *litP; +int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + + switch (type) { + case 'f': + prec = 2; + break; + + case 'd': + prec = 4; + break; + default: + *sizeP = 0; + return "Bad call to MD_ATOF()"; + } + t = atof_ns32k(input_line_pointer, type, words); + if (t) + input_line_pointer=t; + + *sizeP = prec * sizeof(LITTLENUM_TYPE); + for (wordP = words +prec; prec--;) { + md_number_to_chars(litP, (long)(*--wordP), sizeof(LITTLENUM_TYPE)); + litP+=sizeof(LITTLENUM_TYPE); + } + return ""; /* Someone should teach Dean about null pointers */ +} + +/* Convert number to chars in correct order */ + +void + md_number_to_chars(buf, value, nbytes) +char *buf; +long value; +int nbytes; +{ + while (nbytes--) { +#ifdef SHOW_NUM + printf("%x ",value & 0xff); +#endif + *buf++ = value; /* Lint wants & MASK_CHAR. */ + value >>= BITS_PER_CHAR; + } +} /* md_number_to_chars() */ + + +/* This is a variant of md_numbers_to_chars. The reason for its' existence + is the fact that ns32k uses Huffman coded displacements. This implies + that the bit order is reversed in displacements and that they are prefixed + with a size-tag. + + binary: msb->lsb + 0xxxxxxx byte + 10xxxxxx xxxxxxxx word + 11xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx double word + + This must be taken care of and we do it here! + */ +static void md_number_to_disp(buf, val, n) +char *buf; +long val; +char n; +{ + switch (n) { + case 1: + if (val < -64 || val > 63) + as_warn("Byte displacement out of range. line number not valid"); + val &= 0x7f; +#ifdef SHOW_NUM + printf("%x ",val & 0xff); +#endif + *buf++ = val; + break; + case 2: + if (val < -8192 || val > 8191) + as_warn("Word displacement out of range. line number not valid"); + val&=0x3fff; + val|=0x8000; +#ifdef SHOW_NUM + printf("%x ",val>>8 & 0xff); +#endif + *buf++=(val>>8); +#ifdef SHOW_NUM + printf("%x ",val & 0xff); +#endif + *buf++=val; + break; + case 4: + + /* Dave Taylor <taylor@think.com> says: Note: The reason the + lower limit is -0x1f000000 and not -0x20000000 is that, + according to Nat'l Semi's data sheet on the ns32532, ``the + pattern 11100000 for the most significant byte of the + displacement is reserved by National for future + enhancements''. */ + + if (val < -0x1f000000 || val >= 0x20000000) + as_warn("Double word displacement out of range"); + val|=0xc0000000; +#ifdef SHOW_NUM + printf("%x ",val>>24 & 0xff); +#endif + *buf++=(val>>24); +#ifdef SHOW_NUM + printf("%x ",val>>16 & 0xff); +#endif + *buf++=(val>>16); +#ifdef SHOW_NUM + printf("%x ",val>>8 & 0xff); +#endif + *buf++=(val>>8); +#ifdef SHOW_NUM + printf("%x ",val & 0xff); +#endif + *buf++=val; + break; + default: + as_fatal("Internal logic error. line %s, file \"%s\"", __LINE__, __FILE__); + } +} + +static void md_number_to_imm(buf,val,n) +char *buf; +long val; +char n; +{ + switch (n) { + case 1: +#ifdef SHOW_NUM + printf("%x ",val & 0xff); +#endif + *buf++=val; + break; + case 2: +#ifdef SHOW_NUM + printf("%x ",val>>8 & 0xff); +#endif + *buf++=(val>>8); +#ifdef SHOW_NUM + printf("%x ",val & 0xff); +#endif + *buf++=val; + break; + case 4: +#ifdef SHOW_NUM + printf("%x ",val>>24 & 0xff); +#endif + *buf++=(val>>24); +#ifdef SHOW_NUM + printf("%x ",val>>16 & 0xff); +#endif + *buf++=(val>>16); +#ifdef SHOW_NUM + printf("%x ",val>>8 & 0xff); +#endif + *buf++=(val>>8); +#ifdef SHOW_NUM + printf("%x ",val & 0xff); +#endif + *buf++=val; + break; + default: + as_fatal("Internal logic error. line %s, file \"%s\"", __LINE__, __FILE__); + } +} + +/* Translate internal representation of relocation info into target format. + + OVE: on a ns32k the twiddling continues at an even deeper level + here we have to distinguish between displacements and immediates. + + The sequent has a bit for this. It also has a bit for relocobjects that + points at the target for a bsr (BranchSubRoutine) !?!?!?! + + This md_ri.... is tailored for sequent. + */ + +#ifdef comment +void + md_ri_to_chars(the_bytes, ri) +char *the_bytes; +struct reloc_info_generic *ri; +{ + if (ri->r_bsr) { ri->r_pcrel = 0; } /* sequent seems to want this */ + md_number_to_chars(the_bytes, ri->r_address, sizeof(ri->r_address)); + md_number_to_chars(the_bytes+4, ((long)(ri->r_symbolnum ) + | (long)(ri->r_pcrel << 24 ) + | (long)(ri->r_length << 25 ) + | (long)(ri->r_extern << 27 ) + | (long)(ri->r_bsr << 28 ) + | (long)(ri->r_disp << 29 )), + 4); + /* the first and second md_number_to_chars never overlaps (32bit cpu case) */ +} +#endif /* comment */ + +#ifdef OBJ_AOUT +void tc_aout_fix_to_chars(where, fixP, segment_address_in_file) +char *where; +struct fix *fixP; +relax_addressT segment_address_in_file; +{ + /* + * In: length of relocation (or of address) in chars: 1, 2 or 4. + * Out: GNU LD relocation length code: 0, 1, or 2. + */ + + static unsigned char nbytes_r_length[] = { 42, 0, 1, 42, 2 }; + long r_symbolnum; + + know(fixP->fx_addsy != NULL); + + md_number_to_chars(where, + fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, + 4); + + r_symbolnum = (S_IS_DEFINED(fixP->fx_addsy) + ? S_GET_TYPE(fixP->fx_addsy) + : fixP->fx_addsy->sy_number); + + md_number_to_chars(where, + ((long)(r_symbolnum) + | (long)(fixP->fx_pcrel << 24) + | (long)(nbytes_r_length[fixP->fx_size] << 25) + | (long)((!S_IS_DEFINED(fixP->fx_addsy)) << 27) + | (long)(fixP->fx_bsr << 28) + | (long)(fixP->fx_im_disp << 29)), + 4); + + return; +} /* tc_aout_fix_to_chars() */ +#endif /* OBJ_AOUT */ + +/* fast bitfiddling support */ +/* mask used to zero bitfield before oring in the true field */ + +static unsigned long l_mask[] = { + 0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8, + 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80, + 0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800, + 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000, + 0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000, + 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000, + 0xff000000, 0xfe000000, 0xfc000000, 0xf8000000, + 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000, +}; +static unsigned long r_mask[] = { + 0x00000000, 0x00000001, 0x00000003, 0x00000007, + 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, + 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, + 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, + 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, + 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, + 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, + 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, +}; +#define MASK_BITS 31 +/* Insert bitfield described by field_ptr and val at buf + This routine is written for modification of the first 4 bytes pointed + to by buf, to yield speed. + The ifdef stuff is for selection between a ns32k-dependent routine + and a general version. (My advice: use the general version!) + */ + +static void + md_number_to_field(buf,val,field_ptr) +register char *buf; +register long val; +register bit_fixS *field_ptr; +{ + register unsigned long object; + register unsigned long mask; + /* define ENDIAN on a ns32k machine */ +#ifdef ENDIAN + register unsigned long *mem_ptr; +#else + register char *mem_ptr; +#endif + if (field_ptr->fx_bit_min <= val && val <= field_ptr->fx_bit_max) { +#ifdef ENDIAN + if (field_ptr->fx_bit_base) { /* override buf */ + mem_ptr=(unsigned long*)field_ptr->fx_bit_base; + } else { + mem_ptr=(unsigned long*)buf; + } +#else + if (field_ptr->fx_bit_base) { /* override buf */ + mem_ptr=(char*)field_ptr->fx_bit_base; + } else { + mem_ptr=buf; + } +#endif + mem_ptr+=field_ptr->fx_bit_base_adj; +#ifdef ENDIAN /* we have a nice ns32k machine with lowbyte at low-physical mem */ + object = *mem_ptr; /* get some bytes */ +#else /* OVE Goof! the machine is a m68k or dito */ + /* That takes more byte fiddling */ + object=0; + object|=mem_ptr[3] & 0xff; + object<<=8; + object|=mem_ptr[2] & 0xff; + object<<=8; + object|=mem_ptr[1] & 0xff; + object<<=8; + object|=mem_ptr[0] & 0xff; +#endif + mask=0; + mask|=(r_mask[field_ptr->fx_bit_offset]); + mask|=(l_mask[field_ptr->fx_bit_offset+field_ptr->fx_bit_size]); + object&=mask; + val+=field_ptr->fx_bit_add; + object|=((val<<field_ptr->fx_bit_offset) & (mask ^ 0xffffffff)); +#ifdef ENDIAN + *mem_ptr=object; +#else + mem_ptr[0]=(char)object; + object>>=8; + mem_ptr[1]=(char)object; + object>>=8; + mem_ptr[2]=(char)object; + object>>=8; + mem_ptr[3]=(char)object; +#endif + } else { + as_warn("Bit field out of range"); + } +} + +/* Apply a fixS (fixup of an instruction or data that we didn't have + enough info to complete immediately) to the data in a frag. + + On the ns32k, everything is in a different format, so we have broken + out separate functions for each kind of thing we could be fixing. + They all get called from here. */ + +void + md_apply_fix(fixP, val) +fixS *fixP; +long val; +{ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + + if (fixP->fx_bit_fixP) { /* Bitfields to fix, sigh */ + md_number_to_field (buf, val, fixP->fx_bit_fixP); + } else switch (fixP->fx_im_disp) { + + case 0: /* Immediate field */ + md_number_to_imm (buf, val, fixP->fx_size); + break; + + case 1: /* Displacement field */ + md_number_to_disp (buf, + fixP->fx_pcrel? val + fixP->fx_pcrel_adjust: val, + fixP->fx_size); + break; + + case 2: /* Pointer in a data object */ + md_number_to_chars (buf, val, fixP->fx_size); + break; + } +} + +/* Convert a relaxed displacement to ditto in final output */ + +void + md_convert_frag(headers, fragP) +object_headers *headers; +register fragS *fragP; +{ + long disp; + long ext = 0; + + /* Address in gas core of the place to store the displacement. */ + register char *buffer_address = fragP->fr_fix + fragP->fr_literal; + /* Address in object code of the displacement. */ + register int object_address = fragP->fr_fix + fragP->fr_address; + + know(fragP->fr_symbol); + + /* The displacement of the address, from current location. */ + disp = (S_GET_VALUE(fragP->fr_symbol) + fragP->fr_offset) - object_address; + disp += fragP->fr_pcrel_adjust; + + switch (fragP->fr_subtype) { + case IND(BRANCH,BYTE): + ext = 1; + break; + case IND(BRANCH,WORD): + ext = 2; + break; + case IND(BRANCH,DOUBLE): + ext = 4; + break; + } + if (ext) { + md_number_to_disp(buffer_address, (long)disp, (int)ext); + fragP->fr_fix += ext; + } +} /* md_convert_frag() */ + + + +/* This function returns the estimated size a variable object will occupy, + one can say that we tries to guess the size of the objects before we + actually know it */ + +int md_estimate_size_before_relax(fragP, segment) +register fragS *fragP; +segT segment; +{ + int old_fix; + old_fix = fragP->fr_fix; + switch (fragP->fr_subtype) { + case IND(BRANCH,UNDEF): + if (S_GET_SEGMENT(fragP->fr_symbol) == segment) { + /* the symbol has been assigned a value */ + fragP->fr_subtype = IND(BRANCH,BYTE); + } else { + /* we don't relax symbols defined in an other segment + the thing to do is to assume the object will occupy 4 bytes */ + fix_new_ns32k(fragP, + (int)(fragP->fr_fix), + 4, + fragP->fr_symbol, + (symbolS *)0, + fragP->fr_offset, + 1, + fragP->fr_pcrel_adjust, + 1, + 0, + fragP->fr_bsr); /*sequent hack */ + fragP->fr_fix+=4; + /* fragP->fr_opcode[1]=0xff; */ + frag_wane(fragP); + break; + } + case IND(BRANCH,BYTE): + fragP->fr_var+=1; + break; + default: + break; + } + return fragP->fr_var + fragP->fr_fix - old_fix; +} + +int md_short_jump_size = 3; +int md_long_jump_size = 5; +int md_reloc_size = 8; /* Size of relocation record */ + +void + md_create_short_jump(ptr,from_addr,to_addr,frag,to_symbol) +char *ptr; +long from_addr, + to_addr; +fragS *frag; +symbolS *to_symbol; +{ + long offset; + + offset = to_addr - from_addr; + md_number_to_chars(ptr, (long)0xEA ,1); + md_number_to_disp(ptr+1,(long)offset,2); +} + +void + md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol) +char *ptr; +long from_addr, + to_addr; +fragS *frag; +symbolS *to_symbol; +{ + long offset; + + offset= to_addr - from_addr; + md_number_to_chars(ptr, (long)0xEA, 2); + md_number_to_disp(ptr+2,(long)offset,4); +} + +/* JF this is a new function to parse machine-dep options */ +int + md_parse_option(argP,cntP,vecP) +char **argP; +int *cntP; +char ***vecP; +{ + switch (**argP) { + case 'm': + (*argP)++; + + if (!strcmp(*argP,"32032")) { + cpureg = cpureg_032; + mmureg = mmureg_032; + } else if (!strcmp(*argP, "32532")) { + cpureg = cpureg_532; + mmureg = mmureg_532; + } else + as_warn("Unknown -m option ignored"); + + while (**argP) + (*argP)++; + break; + + default: + return 0; + } + return 1; +} + +/* + * bit_fix_new() + * + * Create a bit_fixS in obstack 'notes'. + * This struct is used to profile the normal fix. If the bit_fixP is a + * valid pointer (not NULL) the bit_fix data will be used to format the fix. + */ +bit_fixS *bit_fix_new(size, offset, min, max, add, base_type, base_adj) +char size; /* Length of bitfield */ +char offset; /* Bit offset to bitfield */ +long base_type; /* 0 or 1, if 1 it's exploded to opcode ptr */ +long base_adj; +long min; /* Signextended min for bitfield */ +long max; /* Signextended max for bitfield */ +long add; /* Add mask, used for huffman prefix */ +{ + register bit_fixS * bit_fixP; + + bit_fixP = (bit_fixS *)obstack_alloc(¬es,sizeof(bit_fixS)); + + bit_fixP->fx_bit_size = size; + bit_fixP->fx_bit_offset = offset; + bit_fixP->fx_bit_base = base_type; + bit_fixP->fx_bit_base_adj = base_adj; + bit_fixP->fx_bit_max = max; + bit_fixP->fx_bit_min = min; + bit_fixP->fx_bit_add = add; + + return(bit_fixP); +} + +void + fix_new_ns32k(frag, where, size, add_symbol, sub_symbol, offset, pcrel, + pcrel_adjust, im_disp, bit_fixP, bsr) +fragS *frag; /* Which frag? */ +int where; /* Where in that frag? */ +int size; /* 1, 2 or 4 usually. */ +symbolS *add_symbol; /* X_add_symbol. */ +symbolS *sub_symbol; /* X_subtract_symbol. */ +long offset; /* X_add_number. */ +int pcrel; /* TRUE if PC-relative relocation. */ +char pcrel_adjust; /* not zero if adjustment of pcrel offset is needed */ +char im_disp; /* true if the value to write is a displacement */ +bit_fixS *bit_fixP; /* pointer at struct of bit_fix's, ignored if NULL */ +char bsr; /* sequent-linker-hack: 1 when relocobject is a bsr */ + +{ + fixS *fixP = fix_new(frag, where, size, add_symbol, sub_symbol, + offset, pcrel, NO_RELOC); + + fixP->fx_pcrel_adjust = pcrel_adjust; + fixP->fx_im_disp = im_disp; + fixP->fx_bit_fixP = bit_fixP; + fixP->fx_bsr = bsr; +} /* fix_new_ns32k() */ + +/* We have no need to default values of symbols. */ + +symbolS * + md_undefined_symbol (name) +char *name; +{ + return 0; +} + +/* Parse an operand that is machine-specific. + We just return without modifying the expression if we have nothing + to do. */ + +/* ARGSUSED */ +void + md_operand (expressionP) +expressionS *expressionP; +{ +} + +/* Round up a section size to the appropriate boundary. */ +long + md_section_align (segment, size) +segT segment; +long size; +{ + return size; /* Byte alignment is fine */ +} + +/* Exactly what point is a PC-relative offset relative TO? + On the National warts, they're relative to the address of the offset, + with some funny adjustments in some circumstances during blue moons. + (??? Is this right? FIXME-SOON) */ +long + md_pcrel_from (fixP) +fixS *fixP; +{ + long res; + res = fixP->fx_where + fixP->fx_frag->fr_address; +#ifdef TE_SEQUENT + if (fixP->fx_frag->fr_bsr) + res += 0x12; /* FOO Kludge alert! */ +#endif + return(res); +} + +/* + * Local Variables: + * comment-column: 0 + * End: + */ + +/* end of tc-ns32k.c */ diff --git a/gnu/usr.bin/as/config/tc-ns32k.h b/gnu/usr.bin/as/config/tc-ns32k.h new file mode 100644 index 000000000000..c3c09db56f5e --- /dev/null +++ b/gnu/usr.bin/as/config/tc-ns32k.h @@ -0,0 +1,60 @@ +/* tc-ns32k.h -- Opcode table for National Semi 32k processor + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "bit_fix.h" + +#define NO_LISTING + +#define tc_aout_pre_write_hook(x) {;} /* not used */ +#define tc_crawl_symbol_chain(a) {;} /* not used */ +#define tc_headers_hook(a) {;} /* not used */ + +#ifndef DEF_MODEC +#define DEF_MODEC 20 +#endif + +#ifndef DEF_MODEL +#define DEF_MODEL 20 +#endif + +#define MAX_ARGS 4 +#define ARG_LEN 50 + +#if __STDC__ == 1 + +void fix_new_ns32k(fragS *frag, + int where, + int size, + struct symbol *add_symbol, + struct symbol *sub_symbol, + long offset, + int pcrel, + int pcrel_adjust, + int im_disp, + bit_fixS *bit_fixP, /* really bit_fixS */ + int bsr); + +#else /* not __STDC__ */ + +void fix_new_ns32k(); + +#endif /* not __STDC__ */ + + +/* end of tc-ns32k.h */ diff --git a/gnu/usr.bin/as/config/tc-rs6000.c b/gnu/usr.bin/as/config/tc-rs6000.c new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-rs6000.c diff --git a/gnu/usr.bin/as/config/tc-rs6000.h b/gnu/usr.bin/as/config/tc-rs6000.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-rs6000.h diff --git a/gnu/usr.bin/as/config/tc-sparc.c b/gnu/usr.bin/as/config/tc-sparc.c new file mode 100644 index 000000000000..4dd57dcf6e8c --- /dev/null +++ b/gnu/usr.bin/as/config/tc-sparc.c @@ -0,0 +1,1766 @@ +/* tc-sparc.c -- Assemble for the SPARC + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef lint +static char rcsid[] = "$Id: tc-sparc.c,v 1.2 1993/12/12 17:02:13 jkh Exp $"; +#endif + +#define cypress 1234 + +#include <stdio.h> +#include <ctype.h> + +#include "as.h" + +/* careful, this file includes data *declarations* */ +#include "opcode/sparc.h" + +#define DEBUG_SPARC 1 +void md_begin(); +void md_end(); +void md_number_to_chars(); +void md_assemble(); +char *md_atof(); +void md_convert_frag(); +void md_create_short_jump(); +void md_create_long_jump(); +int md_estimate_size_before_relax(); +void md_ri_to_chars(); +symbolS *md_undefined_symbol(); +static void sparc_ip(); + +static enum sparc_architecture current_architecture = v6; +static int architecture_requested = 0; +static int warn_on_bump = 0; + +const relax_typeS md_relax_table[] = { + 0 }; + +/* handle of the OPCODE hash table */ +static struct hash_control *op_hash = NULL; + +static void s_seg(), s_proc(), s_data1(), s_reserve(), s_common(), s_empty(); +extern void s_globl(), s_long(), s_short(), s_space(), cons(); +extern void s_align_bytes(), s_ignore(); + +const pseudo_typeS md_pseudo_table[] = { + { "align", s_align_bytes, 0 }, /* Defaulting is invalid (0) */ + { "empty", s_empty, 0 }, + { "common", s_common, 0 }, + { "global", s_globl, 0 }, + { "half", cons, 2 }, + { "optim", s_ignore, 0 }, + { "proc", s_proc, 0 }, + { "reserve", s_reserve, 0 }, + { "seg", s_seg, 0 }, + { "skip", s_space, 0 }, + { "word", cons, 4 }, + { NULL, 0, 0 }, +}; + +const int md_short_jump_size = 4; +const int md_long_jump_size = 4; +const int md_reloc_size = 12; /* Size of relocation record */ + +/* This array holds the chars that always start a comment. If the + pre-processor is disabled, these aren't very useful */ +const char comment_chars[] = "!"; /* JF removed '|' from comment_chars */ + +/* This array holds the chars that only start a comment at the beginning of + a line. If the line seems to have the form '# 123 filename' + .line and .file directives will appear in the pre-processed output */ +/* Note that input_file.c hand checks for '#' at the beginning of the + first line of the input file. This is because the compiler outputs + #NO_APP at the beginning of its output. */ +/* Also note that comments started like this one will always + work if '/' isn't otherwise defined. */ +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[] = "rRsSfFdDxXpP"; + +/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be + changed in read.c. Ideally it shouldn't have to know about it at all, + but nothing is ideal around here. + */ + +static unsigned char octal[256]; +#define isoctal(c) octal[c] + static unsigned char toHex[256]; + +struct sparc_it { + char *error; + unsigned long opcode; + struct nlist *nlistp; + expressionS exp; + int pcrel; + enum reloc_type reloc; +} the_insn, set_insn; + +#if __STDC__ == 1 +#if DEBUG_SPARC +static void print_insn(struct sparc_it *insn); +#endif +static int getExpression(char *str); +#else /* not __STDC__ */ +#if DEBUG_SPARC +static void print_insn(); +#endif +static int getExpression(); +#endif /* not __STDC__ */ + +static char *expr_end; +static int special_case; + +/* + * Instructions that require wierd handling because they're longer than + * 4 bytes. + */ +#define SPECIAL_CASE_SET 1 +#define SPECIAL_CASE_FDIV 2 + +/* + * sort of like s_lcomm + * + */ +static int max_alignment = 15; + +static void s_reserve() { + char *name; + char *p; + char c; + int align; + int size; + int temp; + symbolS *symbolP; + + name = input_line_pointer; + c = get_symbol_end(); + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE(); + + if (*input_line_pointer != ',') { + as_bad("Expected comma after name"); + ignore_rest_of_line(); + return; + } + + ++input_line_pointer; + + if ((size = get_absolute_expression()) < 0) { + as_bad("BSS length (%d.) <0! Ignored.", size); + ignore_rest_of_line(); + return; + } /* bad length */ + + *p = 0; + symbolP = symbol_find_or_make(name); + *p = c; + + if (strncmp(input_line_pointer, ",\"bss\"", 6) != 0) { + as_bad("bad .reserve segment: `%s'", input_line_pointer); + return; + } /* if not bss */ + + input_line_pointer += 6; + SKIP_WHITESPACE(); + + if (*input_line_pointer == ',') { + ++input_line_pointer; + + SKIP_WHITESPACE(); + if (*input_line_pointer == '\n') { + as_bad("Missing alignment"); + return; + } + + align = get_absolute_expression(); + if (align > max_alignment){ + align = max_alignment; + as_warn("Alignment too large: %d. assumed.", align); + } else if (align < 0) { + align = 0; + as_warn("Alignment negative. 0 assumed."); + } +#ifdef MANY_SEGMENTS +#define SEG_BSS SEG_E2 + record_alignment(SEG_E2, align); +#else + record_alignment(SEG_BSS, align); +#endif + + /* convert to a power of 2 alignment */ + for (temp = 0; (align & 1) == 0; align >>= 1, ++temp) ;; + + if (align != 1) { + as_bad("Alignment not a power of 2"); + ignore_rest_of_line(); + return; + } /* not a power of two */ + + align = temp; + + /* Align */ + align = ~((~0) << align); /* Convert to a mask */ + local_bss_counter = (local_bss_counter + align) & (~align); + } /* if has optional alignment */ + + if (S_GET_OTHER(symbolP) == 0 + && S_GET_DESC(symbolP) == 0 + && ((S_GET_SEGMENT(symbolP) == SEG_BSS + && S_GET_VALUE(symbolP) == local_bss_counter) + || !S_IS_DEFINED(symbolP))) { + S_SET_VALUE(symbolP, local_bss_counter); + S_SET_SEGMENT(symbolP, SEG_BSS); + symbolP->sy_frag = &bss_address_frag; + local_bss_counter += size; + } else { + as_warn("Ignoring attempt to re-define symbol from %d. to %d.", + S_GET_VALUE(symbolP), local_bss_counter); + } /* if not redefining */ + + demand_empty_rest_of_line(); + return; +} /* s_reserve() */ + +static void s_common() { + register char *name; + register char c; + register char *p; + register int temp; + register symbolS * symbolP; + + name = input_line_pointer; + c = get_symbol_end(); + /* just after name is now '\0' */ + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE(); + if (* input_line_pointer != ',') { + as_bad("Expected comma after symbol-name"); + ignore_rest_of_line(); + return; + } + input_line_pointer ++; /* skip ',' */ + if ((temp = get_absolute_expression ()) < 0) { + as_bad(".COMMon length (%d.) <0! Ignored.", temp); + ignore_rest_of_line(); + return; + } + *p = 0; + symbolP = symbol_find_or_make(name); + *p = c; + if (S_IS_DEFINED(symbolP)) { + as_bad("Ignoring attempt to re-define symbol"); + ignore_rest_of_line(); + return; + } + if (S_GET_VALUE(symbolP) != 0) { + if (S_GET_VALUE(symbolP) != temp) { + as_warn("Length of .comm \"%s\" is already %d. Not changed to %d.", + S_GET_NAME(symbolP), S_GET_VALUE(symbolP), temp); + } + } else { + S_SET_VALUE(symbolP, temp); + S_SET_EXTERNAL(symbolP); + } + know(symbolP->sy_frag == &zero_address_frag); + if (strncmp(input_line_pointer, ",\"bss\"", 6) != 0 + && strncmp(input_line_pointer, ",\"data\"", 7) != 0) { + p=input_line_pointer; + while (*p && *p != '\n') + p++; + c= *p; + *p='\0'; + as_bad("bad .common segment: `%s'", input_line_pointer); + *p=c; + return; + } + input_line_pointer += 6 + (input_line_pointer[2] == 'd'); /* Skip either */ + demand_empty_rest_of_line(); + return; +} /* s_common() */ + +static void s_seg() { + + if (strncmp(input_line_pointer, "\"text\"", 6) == 0) { + input_line_pointer += 6; + s_text(); + return; + } + if (strncmp(input_line_pointer, "\"data\"", 6) == 0) { + input_line_pointer += 6; + s_data(); + return; + } + if (strncmp(input_line_pointer, "\"data1\"", 7) == 0) { + input_line_pointer += 7; + s_data1(); + return; + } + if (strncmp(input_line_pointer, "\"bss\"", 5) == 0) { + input_line_pointer += 5; + /* We only support 2 segments -- text and data -- for now, so + things in the "bss segment" will have to go into data for now. + You can still allocate SEG_BSS stuff with .lcomm or .reserve. */ + subseg_new(SEG_DATA, 255); /* FIXME-SOMEDAY */ + return; + } + as_bad("Unknown segment type"); + demand_empty_rest_of_line(); + return; +} /* s_seg() */ + +static void s_data1() { + subseg_new(SEG_DATA, 1); + demand_empty_rest_of_line(); + return; +} /* s_data1() */ + +static void s_proc() { + extern char is_end_of_line[]; + + while (!is_end_of_line[*input_line_pointer]) { + ++input_line_pointer; + } + ++input_line_pointer; + return; +} /* s_proc() */ + +/* + * GI: This is needed for compatability with Sun's assembler - which + * otherwise generates a warning when certain "suspect" instructions + * appear in the delay slot of a branch. And more seriously without + * this directive in certain cases Sun's assembler will rearrange + * code thinking it knows how to alter things when it doesn't. + */ +static void +s_empty() +{ + demand_empty_rest_of_line(); + return; +} /* s_empty() */ + +/* This function is called once, at assembler startup time. It should + set up all the tables, etc. that the MD part of the assembler will need. */ +void md_begin() { + register char *retval = NULL; + int lose = 0; + register unsigned int i = 0; + + op_hash = hash_new(); + if (op_hash == NULL) + as_fatal("Virtual memory exhausted"); + + while (i < NUMOPCODES) { + const char *name = sparc_opcodes[i].name; + retval = hash_insert(op_hash, name, &sparc_opcodes[i]); + if (retval != NULL && *retval != '\0') { + fprintf (stderr, "internal error: can't hash `%s': %s\n", + sparc_opcodes[i].name, retval); + lose = 1; + } + do + { + if (sparc_opcodes[i].match & sparc_opcodes[i].lose) { + fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n", + sparc_opcodes[i].name, sparc_opcodes[i].args); + lose = 1; + } + ++i; + } while (i < NUMOPCODES + && !strcmp(sparc_opcodes[i].name, name)); + } + + if (lose) + as_fatal("Broken assembler. No assembly attempted."); + + for (i = '0'; i < '8'; ++i) + octal[i] = 1; + for (i = '0'; i <= '9'; ++i) + toHex[i] = i - '0'; + for (i = 'a'; i <= 'f'; ++i) + toHex[i] = i + 10 - 'a'; + for (i = 'A'; i <= 'F'; ++i) + toHex[i] = i + 10 - 'A'; + +#if 0 + if (flagseen['k']) + GOT_symbol = symbol_find_or_make("__GLOBAL_OFFSET_TABLE_"); +#endif +} /* md_begin() */ + +void md_end() { + return; +} /* md_end() */ + +void md_assemble(str) +char *str; +{ + char *toP; + int rsd; + + know(str); + sparc_ip(str); + + /* See if "set" operand is absolute and small; skip sethi if so. */ + if (special_case == SPECIAL_CASE_SET && the_insn.exp.X_seg == SEG_ABSOLUTE) { + if (the_insn.exp.X_add_number >= -(1<<12) + && the_insn.exp.X_add_number < (1<<12)) { + the_insn.opcode = 0x80102000 /* or %g0,imm,... */ + | (the_insn.opcode & 0x3E000000) /* dest reg */ + | (the_insn.exp.X_add_number & 0x1FFF); /* imm */ + special_case = 0; /* No longer special */ + the_insn.reloc = NO_RELOC; /* No longer relocated */ + } + } + + toP = frag_more(4); + /* put out the opcode */ + md_number_to_chars(toP, the_insn.opcode, 4); + + /* put out the symbol-dependent stuff */ + if (the_insn.reloc != NO_RELOC) { + fix_new(frag_now, /* which frag */ + (toP - frag_now->fr_literal), /* where */ + 4, /* size */ + the_insn.exp.X_add_symbol, + the_insn.exp.X_subtract_symbol, + the_insn.exp.X_add_number, + the_insn.pcrel, + the_insn.reloc, + the_insn.exp.X_got_symbol); + } + switch (special_case) { + + case SPECIAL_CASE_SET: + special_case = 0; + know(the_insn.reloc == RELOC_HI22); + /* See if "set" operand has no low-order bits; skip OR if so. */ + if (the_insn.exp.X_seg == SEG_ABSOLUTE + && ((the_insn.exp.X_add_number & 0x3FF) == 0)) + return; + toP = frag_more(4); + rsd = (the_insn.opcode >> 25) & 0x1f; + the_insn.opcode = 0x80102000 | (rsd << 25) | (rsd << 14); + md_number_to_chars(toP, the_insn.opcode, 4); + fix_new(frag_now, /* which frag */ + (toP - frag_now->fr_literal), /* where */ + 4, /* size */ + the_insn.exp.X_add_symbol, + the_insn.exp.X_subtract_symbol, + the_insn.exp.X_add_number, + the_insn.pcrel, + RELOC_LO10, + the_insn.exp.X_got_symbol); + return; + + case SPECIAL_CASE_FDIV: + /* According to information leaked from Sun, the "fdiv" instructions + on early SPARC machines would produce incorrect results sometimes. + The workaround is to add an fmovs of the destination register to + itself just after the instruction. This was true on machines + with Weitek 1165 float chips, such as the Sun-4/260 and /280. */ + special_case = 0; + assert(the_insn.reloc == NO_RELOC); + toP = frag_more(4); + rsd = (the_insn.opcode >> 25) & 0x1f; + the_insn.opcode = 0x81A00020 | (rsd << 25) | rsd; /* fmovs dest,dest */ + md_number_to_chars(toP, the_insn.opcode, 4); + return; + + case 0: + return; + + default: + as_fatal("failed sanity check."); + } +} /* md_assemble() */ + +static void sparc_ip(str) +char *str; +{ + char *error_message = ""; + char *s; + const char *args; + char c; + struct sparc_opcode *insn; + char *argsStart; + unsigned long opcode; + unsigned int mask = 0; + int match = 0; + int comma = 0; + + for (s = str; islower(*s) || (*s >= '0' && *s <= '3'); ++s) + ; + switch (*s) { + + case '\0': + break; + + case ',': + comma = 1; + + /*FALLTHROUGH */ + + case ' ': + *s++ = '\0'; + break; + + default: + as_bad("Unknown opcode: `%s'", str); + exit(1); + } + if ((insn = (struct sparc_opcode *) hash_find(op_hash, str)) == NULL) { + as_bad("Unknown opcode: `%s'", str); + return; + } + if (comma) { + *--s = ','; + } + argsStart = s; + for (;;) { + opcode = insn->match; + memset(&the_insn, '\0', sizeof(the_insn)); + the_insn.reloc = NO_RELOC; + + /* + * Build the opcode, checking as we go to make + * sure that the operands match + */ + for (args = insn->args; ; ++args) { + switch (*args) { + + case 'M': + case 'm': + if (strncmp(s, "%asr", 4) == 0) { + s += 4; + + if (isdigit(*s)) { + long num = 0; + + while (isdigit(*s)) { + num = num*10 + *s-'0'; + ++s; + } + + if (num < 16 || 31 < num) { + error_message = ": asr number must be between 15 and 31"; + goto error; + } /* out of range */ + + opcode |= (*args == 'M' ? RS1(num) : RD(num)); + continue; + } else { + error_message = ": expecting %asrN"; + goto error; + } /* if %asr followed by a number. */ + + } /* if %asr */ + break; + + + case '\0': /* end of args */ + if (*s == '\0') { + match = 1; + } + break; + + case '+': + if (*s == '+') { + ++s; + continue; + } + if (*s == '-') { + continue; + } + break; + + case '[': /* these must match exactly */ + case ']': + case ',': + case ' ': + if (*s++ == *args) + continue; + break; + + case '#': /* must be at least one digit */ + if (isdigit(*s++)) { + while (isdigit(*s)) { + ++s; + } + continue; + } + break; + + case 'C': /* coprocessor state register */ + if (strncmp(s, "%csr", 4) == 0) { + s += 4; + continue; + } + break; + + case 'b': /* next operand is a coprocessor register */ + case 'c': + case 'D': + if (*s++ == '%' && *s++ == 'c' && isdigit(*s)) { + mask = *s++; + if (isdigit(*s)) { + mask = 10 * (mask - '0') + (*s++ - '0'); + if (mask >= 32) { + break; + } + } else { + mask -= '0'; + } + switch (*args) { + + case 'b': + opcode |= mask << 14; + continue; + + case 'c': + opcode |= mask; + continue; + + case 'D': + opcode |= mask << 25; + continue; + } + } + break; + + case 'r': /* next operand must be a register */ + case 's': + case '1': + case '2': + case 'd': + case 'x': + if (*s++ == '%') { + switch (c = *s++) { + + case 'f': /* frame pointer */ + if (*s++ == 'p') { + mask = 0x1e; + break; + } + goto error; + + case 'g': /* global register */ + if (isoctal(c = *s++)) { + mask = c - '0'; + break; + } + goto error; + + case 'i': /* in register */ + if (isoctal(c = *s++)) { + mask = c - '0' + 24; + break; + } + goto error; + + case 'l': /* local register */ + if (isoctal(c = *s++)) { + mask= (c - '0' + 16) ; + break; + } + goto error; + + case 'o': /* out register */ + if (isoctal(c = *s++)) { + mask= (c - '0' + 8) ; + break; + } + goto error; + + case 's': /* stack pointer */ + if (*s++ == 'p') { + mask= 0xe; + break; + } + goto error; + + case 'r': /* any register */ + if (!isdigit(c = *s++)) { + goto error; + } + /* FALLTHROUGH */ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (isdigit(*s)) { + if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) { + goto error; + } + } else { + c -= '0'; + } + mask= c; + break; + + case 'x': + opcode |= (mask << 25) | mask; + continue; + + default: + goto error; + } + /* + * Got the register, now figure out where + * it goes in the opcode. + */ + switch (*args) { + + case '1': + opcode |= mask << 14; + continue; + + case '2': + opcode |= mask; + continue; + + case 'd': + opcode |= mask << 25; + continue; + + case 'r': + opcode |= (mask << 25) | (mask << 14); + continue; + case 'x': + opcode |= (mask << 25) | mask; + continue; + } + } + break; + + case 'e': /* next operand is a floating point register */ + case 'v': + case 'V': + + case 'f': + case 'B': + case 'R': + + case 'g': + case 'H': + case 'J': { + char format; + + if (*s++ == '%' + + && ((format = *s) == 'f') + + && isdigit(*++s)) { + + + + for (mask = 0; isdigit(*s); ++s) { + mask = 10 * mask + (*s - '0'); + } /* read the number */ + + if ((*args == 'u' + || *args == 'v' + || *args == 'B' + || *args == 'H') + && (mask & 1)) { + break; + } /* register must be even numbered */ + + if ((*args == 'U' + || *args == 'V' + || *args == 'R' + || *args == 'J') + && (mask & 3)) { + break; + } /* register must be multiple of 4 */ + + if (format == 'f') { + if (mask >= 32) { + error_message = ": There are only 32 f registers; [0-31]"; + goto error; + } /* on error */ + } /* if not an 'f' register. */ + } /* on error */ + + switch (*args) { + + case 'v': + case 'V': + case 'e': + opcode |= RS1(mask); + continue; + + + case 'f': + case 'B': + case 'R': + opcode |= RS2(mask); + continue; + + case 'g': + case 'H': + case 'J': + opcode |= RD(mask); + continue; + } /* pack it in. */ + + know(0); + break; + } /* float arg */ + + case 'F': + if (strncmp(s, "%fsr", 4) == 0) { + s += 4; + continue; + } + break; + + case 'h': /* high 22 bits */ +#ifdef PIC + the_insn.reloc = flagseen['k']? + RELOC_BASE22: + RELOC_HI22; +#else + the_insn.reloc = RELOC_HI22; +#endif + goto immediate; + + case 'l': /* 22 bit PC relative immediate */ + the_insn.reloc = RELOC_WDISP22; + the_insn.pcrel = 1; + goto immediate; + + case 'L': /* 30 bit immediate */ +#ifdef PIC + the_insn.reloc = flagseen['k']? + RELOC_JMP_TBL: + RELOC_WDISP30; +#else + the_insn.reloc = RELOC_WDISP30; +#endif + the_insn.pcrel = 1; + goto immediate; + + case 'n': /* 22 bit immediate */ + the_insn.reloc = RELOC_22; + goto immediate; + + case 'i': /* 13 bit immediate */ + the_insn.reloc = RELOC_BASE13; + + /*FALLTHROUGH */ + + immediate: + if (*s == ' ') + s++; + if (*s == '%') { + if ((c = s[1]) == 'h' && s[2] == 'i') { + the_insn.reloc = RELOC_HI22; + s+=3; + } else if (c == 'l' && s[2] == 'o') { + the_insn.reloc = RELOC_LO10; + s+=3; + } else + break; + } + /* Note that if the getExpression() fails, we + will still have created U entries in the + symbol table for the 'symbols' in the input + string. Try not to create U symbols for + registers, etc. */ + { + /* This stuff checks to see if the + expression ends in +%reg If it does, + it removes the register from the + expression, and re-sets 's' to point + to the right place */ + + char *s1; + + for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++) ;; + + if (s1 != s && isdigit(s1[-1])) { + if (s1[-2] == '%' && s1[-3] == '+') { + s1 -= 3; + *s1 = '\0'; + (void) getExpression(s); + *s1 = '+'; + s = s1; + continue; + } else if (strchr("goli0123456789", s1[-2]) && s1[-3] == '%' && s1[-4] == '+') { + s1 -= 4; + *s1 = '\0'; + (void) getExpression(s); + *s1 = '+'; + s = s1; + continue; + } + } + } + (void)getExpression(s); +#ifdef PIC + if (the_insn.exp.X_got_symbol) { + switch(the_insn.reloc) { + case RELOC_HI22: + the_insn.reloc = RELOC_PC22; + the_insn.pcrel = 1; + break; + case RELOC_LO10: + the_insn.reloc = RELOC_PC10; + the_insn.pcrel = 1; + break; + default: + break; + } + } +#endif + s = expr_end; + continue; + + case 'a': + if (*s++ == 'a') { + opcode |= ANNUL; + continue; + } + break; + + case 'A': { + char *push = input_line_pointer; + expressionS e; + + input_line_pointer = s; + + if (expression(&e) == SEG_ABSOLUTE) { + opcode |= e.X_add_number << 5; + s = input_line_pointer; + input_line_pointer = push; + continue; + } /* if absolute */ + + break; + } /* alternate space */ + + case 'p': + if (strncmp(s, "%psr", 4) == 0) { + s += 4; + continue; + } + break; + + case 'q': /* floating point queue */ + if (strncmp(s, "%fq", 3) == 0) { + s += 3; + continue; + } + break; + + case 'Q': /* coprocessor queue */ + if (strncmp(s, "%cq", 3) == 0) { + s += 3; + continue; + } + break; + + case 'S': + if (strcmp(str, "set") == 0) { + special_case = SPECIAL_CASE_SET; + continue; + } else if (strncmp(str, "fdiv", 4) == 0) { + special_case = SPECIAL_CASE_FDIV; + continue; + } + break; + + case 't': + if (strncmp(s, "%tbr", 4) != 0) + break; + s += 4; + continue; + + case 'w': + if (strncmp(s, "%wim", 4) != 0) + break; + s += 4; + continue; + + case 'y': + if (strncmp(s, "%y", 2) != 0) + break; + s += 2; + continue; + + default: + as_fatal("failed sanity check."); + } /* switch on arg code */ + break; + } /* for each arg that we expect */ + error: + if (match == 0) { + /* Args don't match. */ + if (((unsigned) (&insn[1] - sparc_opcodes)) < NUMOPCODES + && !strcmp(insn->name, insn[1].name)) { + ++insn; + s = argsStart; + continue; + } else { + as_bad("Illegal operands%s", error_message); + return; + } + } else { + if (insn->architecture > current_architecture) { + if (!architecture_requested || warn_on_bump) { + + if (warn_on_bump) { + as_warn("architecture bumped from \"%s\" to \"%s\" on \"%s\"", + architecture_pname[current_architecture], + architecture_pname[insn->architecture], + str); + } /* if warning */ + + current_architecture = insn->architecture; + } else { + as_bad("architecture mismatch on \"%s\" (\"%s\"). current architecture is \"%s\"", + str, + architecture_pname[insn->architecture], + architecture_pname[current_architecture]); + return; + } /* if bump ok else error */ + } /* if architecture higher */ + } /* if no match */ + + break; + } /* forever looking for a match */ + + the_insn.opcode = opcode; +#if DEBUG_SPARC + if (flagseen['D']) + print_insn(&the_insn); +#endif + return; +} /* sparc_ip() */ + +static int getExpression(str) +char *str; +{ + char *save_in; + segT seg; + + save_in = input_line_pointer; + input_line_pointer = str; + switch (seg = expression(&the_insn.exp)) { + + case SEG_ABSOLUTE: + switch (the_insn.reloc) { + case RELOC_LO10: + the_insn.exp.X_add_number &= ~(~(0) << 10); + break; + case RELOC_HI22: + the_insn.exp.X_add_number &= (~(0) << 10); + break; + default: + break; + } + break; + case SEG_TEXT: + case SEG_DATA: + case SEG_BSS: + case SEG_UNKNOWN: + case SEG_DIFFERENCE: + case SEG_BIG: + case SEG_ABSENT: + break; + + default: + the_insn.error = "bad segment"; + expr_end = input_line_pointer; + input_line_pointer=save_in; + return 1; + } + switch (the_insn.reloc) { + case RELOC_BASE10: + case RELOC_BASE13: + case RELOC_BASE22: + if (the_insn.exp.X_add_symbol) + the_insn.exp.X_add_symbol->sy_forceout = 1; + break; + default: + break; + } + expr_end = input_line_pointer; + input_line_pointer = save_in; + return 0; +} /* getExpression() */ + + +/* + This is identical to the md_atof in m68k.c. I think this is right, + but I'm not sure. + + Turn a string in input_line_pointer into a floating point constant of type + type, and store the appropriate bytes in *litP. The number of LITTLENUMS + emitted is stored in *sizeP. An error message is returned, or NULL on OK. + */ + +/* Equal to MAX_PRECISION in atof-ieee.c */ +#define MAX_LITTLENUMS 6 + +char *md_atof(type,litP,sizeP) +char type; +char *litP; +int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + char *atof_ieee(); + + switch (type) { + + case 'f': + case 'F': + case 's': + case 'S': + prec = 2; + break; + + case 'd': + case 'D': + case 'r': + case 'R': + prec = 4; + break; + + case 'x': + case 'X': + prec = 6; + break; + + case 'p': + case 'P': + prec = 6; + break; + + default: + *sizeP=0; + return "Bad call to MD_ATOF()"; + } + t=atof_ieee(input_line_pointer,type,words); + if (t) + input_line_pointer=t; + *sizeP=prec * sizeof(LITTLENUM_TYPE); + for (wordP=words;prec--;) { + md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE)); + litP+=sizeof(LITTLENUM_TYPE); + } + return ""; /* Someone should teach Dean about null pointers */ +} /* md_atof() */ + +/* + * Write out big-endian. + */ +void md_number_to_chars(buf,val,n) +char *buf; +long val; +int n; +{ + + switch (n) { + + case 4: + *buf++ = val >> 24; + *buf++ = val >> 16; + case 2: + *buf++ = val >> 8; + case 1: + *buf = val; + break; + + default: + as_fatal("failed sanity check."); + } + return; +} /* md_number_to_chars() */ + +static void reloc_check(val, bits) +long val; +int bits; +{ + if (((val & (-1 << bits)) != 0) + && ((val & (-1 << bits)) != (-1 << (bits - 0)))) { + as_warn("Relocation overflow. Value truncated."); + } /* on overflow */ + + return; +} /* reloc_check() */ + +/* Apply a fixS to the frags, now that we know the value it ought to + hold. */ + +void md_apply_fix(fixP, val) +fixS *fixP; +long val; +{ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + +#if DEBUG_SPARC + static char *Reloc[] = { + "RELOC_8", "RELOC_16", "RELOC_32", + "RELOC_DISP8", "RELOC_DISP16", "RELOC_DISP32", + "RELOC_WDISP30", "RELOC_WDISP22", + "RELOC_HI22", + "RELOC_22", "RELOC_13", + "RELOC_LO10", "RELOC_SFA_BASE", "RELOC_SFA_OFF13", + "RELOC_BASE10", "RELOC_BASE13", "RELOC_BASE22", "RELOC_PC10", + "RELOC_PC22", "RELOC_JMP_TBL", "RELOC_SEGOFF16", + "RELOC_GLOB_DAT", "RELOC_JMP_SLOT", "RELOC_RELATIVE", + "NO_RELOC" + }; + if (flagseen['D']) + fprintf(stderr, "md_apply_fix: \"%s\" \"%s\", val %d -- %s\n", + ((fixP->fx_addsy != NULL) + ? ((S_GET_NAME(fixP->fx_addsy) != NULL) + ? S_GET_NAME(fixP->fx_addsy) + : "???") + : "0"), + ((fixP->fx_subsy != NULL) + ? ((S_GET_NAME(fixP->fx_subsy) != NULL) + ? S_GET_NAME(fixP->fx_subsy) + : "???") + : "0"), + val, Reloc[fixP->fx_r_type]); +#endif + + assert(fixP->fx_size == 4); + assert(fixP->fx_r_type < NO_RELOC); + + fixP->fx_addnumber = val; /* Remember value for emit_reloc */ + + /* + * This is a hack. There should be a better way to + * handle this. + */ + if (fixP->fx_r_type == RELOC_WDISP30 && fixP->fx_addsy) { + val += fixP->fx_where + fixP->fx_frag->fr_address; + } + + switch (fixP->fx_r_type) { + + /* Michael Bloom <mb@ttidca.tti.com> says... [This] change was + made to match the behavior of Sun's assembler. Some broken + loaders depend on that. At least one such loader actually + adds the section data to what it finds in the addend. (It + should only be using the addend like Sun's loader seems to). + This caused incorrect relocation: (addend + adjustment) + became ( ( 2 * addend ) + adjustment ). [and there should + be no cases that reach here anyway. */ + case RELOC_32: + buf[0] = 0; /* val >> 24; */ + buf[1] = 0; /* val >> 16; */ + buf[2] = 0; /* val >> 8; */ + buf[3] = 0; /* val; */ + break; + +#if 0 + case RELOC_8: /* These don't seem to ever be needed. */ + case RELOC_16: + case RELOC_DISP8: + case RELOC_DISP16: + case RELOC_DISP32: +#endif + + case RELOC_JMP_TBL: + case RELOC_WDISP30: + val = (val >>= 2) + 1; + reloc_check(val, 30); + + buf[0] |= (val >> 24) & 0x3f; + buf[1]= (val >> 16); + buf[2] = val >> 8; + buf[3] = val; + break; + + + case RELOC_HI22: + reloc_check(val >> 10, 22); + + if (!fixP->fx_addsy) { + buf[1] |= (val >> 26) & 0x3f; + buf[2] = val >> 18; + buf[3] = val >> 10; + } else { + buf[2]=0; + buf[3]=0; + } + break; + + case RELOC_PC22: + case RELOC_22: + reloc_check(val, 22); + + buf[1] |= (val >> 16) & 0x3f; + buf[2] = val >> 8; + buf[3] = val & 0xff; + break; + + case RELOC_13: + reloc_check(val, 13); + + buf[2] = (val >> 8) & 0x1f; + buf[3] = val & 0xff; + break; + + + case RELOC_PC10: + case RELOC_LO10: + case RELOC_BASE10: + reloc_check(val, 10); + + if (!fixP->fx_addsy) { + buf[2] |= (val >> 8) & 0x03; + buf[3] = val; + } else + buf[3]=0; + break; +#if 0 + case RELOC_SFA_BASE: + case RELOC_SFA_OFF13: +#endif + case RELOC_BASE13: + reloc_check(val, 13); + + buf[2] |= (val >> 8) & 0x1f; + buf[3] = val; + break; + + case RELOC_WDISP22: + val = (val >>= 2) + 1; + /* FALLTHROUGH */ + case RELOC_BASE22: + reloc_check(val, 22); + + buf[1] |= (val >> 16) & 0x3f; + buf[2] = val >> 8; + buf[3] = val; + break; + +#if 0 + case RELOC_PC10: + case RELOC_PC22: + case RELOC_JMP_TBL: + case RELOC_SEGOFF16: + case RELOC_GLOB_DAT: + case RELOC_JMP_SLOT: + case RELOC_RELATIVE: +#endif + + case NO_RELOC: + default: + as_bad("bad relocation type: 0x%02x", fixP->fx_r_type); + break; + } +} /* md_apply_fix() */ + +/* should never be called for sparc */ +void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol) +char *ptr; +long from_addr; +long to_addr; +fragS *frag; +symbolS *to_symbol; +{ + as_fatal("sparc_create_short_jmp\n"); +} /* md_create_short_jump() */ + +/* Translate internal representation of relocation info to target format. + + On sparc: first 4 bytes are normal unsigned long address, next three + bytes are index, most sig. byte first. Byte 7 is broken up with + bit 7 as external, bits 6 & 5 unused, and the lower + five bits as relocation type. Next 4 bytes are long addend. */ +/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */ +void tc_aout_fix_to_chars(where, fixP, segment_address_in_file) +char *where; +fixS *fixP; +relax_addressT segment_address_in_file; +{ + long r_index; + long r_extern; + long r_addend = 0; + long r_address; +#ifdef PIC + int kflag = 0; +#endif + + know(fixP->fx_addsy); + + if (!S_IS_DEFINED(fixP->fx_addsy)) { + r_extern = 1; + r_index = fixP->fx_addsy->sy_number; + } else { + r_extern = 0; + r_index = S_GET_TYPE(fixP->fx_addsy); +#ifdef PIC + if (flagseen['k']) { + switch (fixP->fx_r_type) { + case RELOC_BASE10: + case RELOC_BASE13: + case RELOC_BASE22: + r_index = fixP->fx_addsy->sy_number; + if (S_IS_EXTERNAL(fixP->fx_addsy)) + r_extern = 1; + kflag = 1; + break; + + case RELOC_32: + if (!S_IS_EXTERNAL(fixP->fx_addsy)) + break; + r_index = fixP->fx_addsy->sy_number; + /*kflag = 1;*/ + break; + + default: + break; + } + } +#endif + } + + /* this is easy */ + md_number_to_chars(where, + r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, + 4); + + /* now the fun stuff */ + where[4] = (r_index >> 16) & 0x0ff; + where[5] = (r_index >> 8) & 0x0ff; + where[6] = r_index & 0x0ff; + where[7] = ((r_extern << 7) & 0x80) | (0 & 0x60) | (fixP->fx_r_type & 0x1F); + + /* Also easy */ + if (fixP->fx_addsy->sy_frag) { + r_addend = fixP->fx_addsy->sy_frag->fr_address; + } + + if (fixP->fx_pcrel) { +#ifdef PIC + if (fixP->fx_gotsy) { + r_addend = r_address; + r_addend += fixP->fx_addnumber; + } else +#endif + r_addend -= r_address; + } else { +#ifdef PIC + if (kflag) + r_addend = 0; + else +#endif + r_addend = fixP->fx_addnumber; + } + + md_number_to_chars(&where[8], r_addend, 4); + + return; +} /* tc_aout_fix_to_chars() */ + +/* should never be called for sparc */ +void md_convert_frag(headers, fragP) +object_headers *headers; +register fragS *fragP; +{ + as_fatal("sparc_convert_frag\n"); +} /* md_convert_frag() */ + +/* should never be called for sparc */ +void md_create_long_jump(ptr, from_addr, to_addr, frag, to_symbol) +char *ptr; +long from_addr, to_addr; +fragS *frag; +symbolS *to_symbol; +{ + as_fatal("sparc_create_long_jump\n"); +} /* md_create_long_jump() */ + +/* should never be called for sparc */ +int md_estimate_size_before_relax(fragP, segtype) +fragS *fragP; +segT segtype; +{ + as_fatal("sparc_estimate_size_before_relax\n"); + return(1); +} /* md_estimate_size_before_relax() */ + +#if DEBUG_SPARC +/* for debugging only */ +static void print_insn(insn) +struct sparc_it *insn; +{ + static char *Reloc[] = { + "RELOC_8", + "RELOC_16", + "RELOC_32", + "RELOC_DISP8", + "RELOC_DISP16", + "RELOC_DISP32", + "RELOC_WDISP30", + "RELOC_WDISP22", + "RELOC_HI22", + "RELOC_22", + "RELOC_13", + "RELOC_LO10", + "RELOC_SFA_BASE", + "RELOC_SFA_OFF13", + "RELOC_BASE10", + "RELOC_BASE13", + "RELOC_BASE22", + "RELOC_PC10", + "RELOC_PC22", + "RELOC_JMP_TBL", + "RELOC_SEGOFF16", + "RELOC_GLOB_DAT", + "RELOC_JMP_SLOT", + "RELOC_RELATIVE", + "NO_RELOC" + }; + + if (insn->error) { + fprintf(stderr, "ERROR: %s\n", insn->error); + } + fprintf(stderr, "opcode=0x%08x\n", insn->opcode); + fprintf(stderr, "reloc = %s\n", Reloc[insn->reloc]); + fprintf(stderr, "exp = {\n"); + fprintf(stderr, "\t\tX_add_symbol = %s\n", + ((insn->exp.X_add_symbol != NULL) + ? ((S_GET_NAME(insn->exp.X_add_symbol) != NULL) + ? S_GET_NAME(insn->exp.X_add_symbol) + : "???") + : "0")); + fprintf(stderr, "\t\tX_sub_symbol = %s\n", + ((insn->exp.X_subtract_symbol != NULL) + ? (S_GET_NAME(insn->exp.X_subtract_symbol) + ? S_GET_NAME(insn->exp.X_subtract_symbol) + : "???") + : "0")); + fprintf(stderr, "\t\tX_got_symbol = %s\n", + ((insn->exp.X_got_symbol != NULL) + ? (S_GET_NAME(insn->exp.X_got_symbol) + ? S_GET_NAME(insn->exp.X_got_symbol) + : "???") + : "0")); + fprintf(stderr, "\t\tX_add_number = %d\n", + insn->exp.X_add_number); + fprintf(stderr, "}\n"); + return; +} /* print_insn() */ +#endif + +/* Set the hook... */ + +/* void emit_sparc_reloc(); + void (*md_emit_relocations)() = emit_sparc_reloc; */ + +#ifdef comment + +/* + * Sparc/AM29K relocations are completely different, so it needs + * this machine dependent routine to emit them. + */ +#if defined(OBJ_AOUT) || defined(OBJ_BOUT) +void emit_sparc_reloc(fixP, segment_address_in_file) +register fixS *fixP; +relax_addressT segment_address_in_file; +{ + struct reloc_info_generic ri; + register symbolS *symbolP; + extern char *next_object_file_charP; + /* long add_number; */ + + memset((char *) &ri, '\0', sizeof(ri)); + for (; fixP; fixP = fixP->fx_next) { + + if (fixP->fx_r_type >= NO_RELOC) { + as_fatal("fixP->fx_r_type = %d\n", fixP->fx_r_type); + } + + if ((symbolP = fixP->fx_addsy) != NULL) { + ri.r_address = fixP->fx_frag->fr_address + + fixP->fx_where - segment_address_in_file; + if ((S_GET_TYPE(symbolP)) == N_UNDF) { + ri.r_extern = 1; + ri.r_index = symbolP->sy_number; + } else { + ri.r_extern = 0; + ri.r_index = S_GET_TYPE(symbolP); + } + if (symbolP && symbolP->sy_frag) { + ri.r_addend = symbolP->sy_frag->fr_address; + } + ri.r_type = fixP->fx_r_type; + if (fixP->fx_pcrel) { + /* ri.r_addend -= fixP->fx_where; */ + ri.r_addend -= ri.r_address; + } else { + ri.r_addend = fixP->fx_addnumber; + } + + md_ri_to_chars(next_object_file_charP, &ri); + next_object_file_charP += md_reloc_size; + } + } + return; +} /* emit_sparc_reloc() */ +#endif /* aout or bout */ +#endif /* comment */ + +/* + * md_parse_option + * Invocation line includes a switch not recognized by the base assembler. + * See if it's a processor-specific option. These are: + * + * -bump + * Warn on architecture bumps. See also -A. + * + * -Av6, -Av7, -Av8 + * Select the architecture. Instructions or features not + * supported by the selected architecture cause fatal errors. + * + * The default is to start at v6, and bump the architecture up + * whenever an instruction is seen at a higher level. + * + * If -bump is specified, a warning is printing when bumping to + * higher levels. + * + * If an architecture is specified, all instructions must match + * that architecture. Any higher level instructions are flagged + * as errors. + * + * if both an architecture and -bump are specified, the + * architecture starts at the specified level, but bumps are + * warnings. + * + */ +int md_parse_option(argP, cntP, vecP) +char **argP; +int *cntP; +char ***vecP; +{ + char *p; + const char **arch; + + if (!strcmp(*argP,"bump")){ + warn_on_bump = 1; + + } else if (**argP == 'A'){ + p = (*argP) + 1; + + for (arch = architecture_pname; *arch != NULL; ++arch){ + if (strcmp(p, *arch) == 0){ + break; + } /* found a match */ + } /* walk the pname table */ + + if (*arch == NULL){ + as_bad("unknown architecture: %s", p); + } else { + current_architecture = (enum sparc_architecture) (arch - architecture_pname); + architecture_requested = 1; + } +#ifdef PIC + } else if (**argP == 'k') { + /* Predefine GOT symbol */ + GOT_symbol = symbol_find_or_make("__GLOBAL_OFFSET_TABLE_"); +#endif + } else { + /* Unknown option */ + (*argP)++; + return 0; + } + **argP = '\0'; /* Done parsing this switch */ + return 1; +} /* md_parse_option() */ + +/* We have no need to default values of symbols. */ + +/* ARGSUSED */ +symbolS *md_undefined_symbol(name) +char *name; +{ + return 0; +} /* md_undefined_symbol() */ + +/* Parse an operand that is machine-specific. + We just return without modifying the expression if we have nothing + to do. */ + +/* ARGSUSED */ +void md_operand(expressionP) +expressionS *expressionP; +{ +} /* md_operand() */ + +/* Round up a section size to the appropriate boundary. */ +long md_section_align(segment, size) +segT segment; +long size; +{ + return((size + 7) & ~7); /* Round all sects to multiple of 8 */ +} /* md_section_align() */ + +/* Exactly what point is a PC-relative offset relative TO? + On the sparc, they're relative to the address of the offset, plus + its size. This gets us to the following instruction. + (??? Is this right? FIXME-SOON) */ +long md_pcrel_from(fixP) +fixS *fixP; +{ +#ifdef PIC + /* + * _GLOBAL_OFFSET_TABLE_ refs are relative to the offset of the + * current instruction. We omit fx_size from the computation (which + * is always 4 anyway). + */ + if (fixP->fx_gotsy) + return fixP->fx_where + fixP->fx_frag->fr_address; + else +#endif + return(fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address); +} /* md_pcrel_from() */ + +void tc_aout_pre_write_hook(headers) +object_headers *headers; +{ + H_SET_VERSION(headers, 1); + return; +} /* tc_aout_pre_write_hook() */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of tc-sparc.c */ diff --git a/gnu/usr.bin/as/config/tc-sparc.h b/gnu/usr.bin/as/config/tc-sparc.h new file mode 100644 index 000000000000..2b00c5bd4c0a --- /dev/null +++ b/gnu/usr.bin/as/config/tc-sparc.h @@ -0,0 +1,54 @@ +/* tc-sparc.h - Macros and type defines for the sparc. + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, + or (at your option) any later version. + + GAS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with GAS; see the file COPYING. If not, write + to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * $Id: tc-sparc.h,v 1.1 1993/11/03 00:54:54 paul Exp $ + */ + +#define TC_SPARC 1 + +#define NO_LISTING +#define LOCAL_LABELS_FB +#define WORKING_DOT_WORD + +#ifdef OBJ_BOUT +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE ((0x103 << 16) | BMAGIC) /* Magic number for header */ +#else +#ifdef OBJ_AOUT +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE ((0x103 << 16) | OMAGIC) /* Magic number for header */ +#endif /* OBJ_AOUT */ +#endif /* OBJ_BOUT */ + +#define AOUT_MACHTYPE 3 + +#define tc_headers_hook(a) {;} /* don't need it. */ +#define tc_crawl_symbol_chain(a) {;} /* don't need it. */ + +void tc_aout_pre_write_hook(); + +#define LISTING_HEADER "SPARC GAS " + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of tc-sparc.h */ diff --git a/gnu/usr.bin/as/config/tc-tahoe.c b/gnu/usr.bin/as/config/tc-tahoe.c new file mode 100644 index 000000000000..68dc5b9fbb24 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-tahoe.c @@ -0,0 +1,1924 @@ +/* tc-tahoe.c + Not part of GAS yet. */ + +#include "as.h" +#include "obstack.h" + + /* this bit glommed from tahoe-inst.h */ + +typedef unsigned char byte; +typedef byte tahoe_opcodeT; + +/* + * This is part of tahoe-ins-parse.c & friends. + * We want to parse a tahoe instruction text into a tree defined here. + */ + +#define TIT_MAX_OPERANDS (4) /* maximum number of operands in one + single tahoe instruction */ + +struct top /* tahoe instruction operand */ +{ + int top_ndx; /* -1, or index register. eg 7=[R7] */ + int top_reg; /* -1, or register number. eg 7 = R7 or (R7) */ + byte top_mode; /* Addressing mode byte. This byte, defines + which of the 11 modes opcode is. */ + + char top_access; /* Access type wanted for this opperand + 'b'branch ' 'no-instruction 'amrvw' */ + char top_width; /* Operand width expected, one of "bwlq?-:!" */ + + char *top_error; /* Say if operand is inappropriate */ + + expressionS exp_of_operand; /* The expression as parsed by expression()*/ + + byte top_dispsize; /* Number of bytes in the displacement if we + can figure it out */ +}; + +/* The addressing modes for an operand. These numbers are the acutal values + for certain modes, so be carefull if you screw with them. */ +#define TAHOE_DIRECT_REG (0x50) +#define TAHOE_REG_DEFERRED (0x60) + +#define TAHOE_REG_DISP (0xE0) +#define TAHOE_REG_DISP_DEFERRED (0xF0) + +#define TAHOE_IMMEDIATE (0x8F) +#define TAHOE_IMMEDIATE_BYTE (0x88) +#define TAHOE_IMMEDIATE_WORD (0x89) +#define TAHOE_IMMEDIATE_LONGWORD (0x8F) +#define TAHOE_ABSOLUTE_ADDR (0x9F) + +#define TAHOE_DISPLACED_RELATIVE (0xEF) +#define TAHOE_DISP_REL_DEFERRED (0xFF) + +#define TAHOE_AUTO_DEC (0x7E) +#define TAHOE_AUTO_INC (0x8E) +#define TAHOE_AUTO_INC_DEFERRED (0x9E) +/* INDEXED_REG is decided by the existance or lack of a [reg] */ + +/* These are encoded into top_width when top_access=='b' + and it's a psuedo op.*/ +#define TAHOE_WIDTH_ALWAYS_JUMP '-' +#define TAHOE_WIDTH_CONDITIONAL_JUMP '?' +#define TAHOE_WIDTH_BIG_REV_JUMP '!' +#define TAHOE_WIDTH_BIG_NON_REV_JUMP ':' + +/* The hex code for certain tahoe commands and modes. + This is just for readability. */ +#define TAHOE_JMP (0x71) +#define TAHOE_PC_REL_LONG (0xEF) +#define TAHOE_BRB (0x11) +#define TAHOE_BRW (0x13) +/* These, when 'ored' with, or added to, a register number, + set up the number for the displacement mode. */ +#define TAHOE_PC_OR_BYTE (0xA0) +#define TAHOE_PC_OR_WORD (0xC0) +#define TAHOE_PC_OR_LONG (0xE0) + +struct tit /* get it out of the sewer, it stands for + tahoe instruction tree (Geeze!) */ +{ + tahoe_opcodeT tit_opcode; /* The opcode. */ + byte tit_operands; /* How many operands are here. */ + struct top tit_operand[TIT_MAX_OPERANDS]; /* Operands */ + char *tit_error; /* "" or fatal error text */ +}; + +/* end: tahoe-inst.h */ + +/* tahoe.c - tahoe-specific - + Not part of gas yet. + */ + +#include "opcode/tahoe.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 or a quoted string. */ +const char comment_chars[] = "#;"; + +/* These chars only start a comment at the beginning of a line. */ +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 0d1.234E-12 (see exp chars above) + Note: The Tahoe port doesn't support floating point constants. This is + consistant with 'as' If it's needed, I can always add it later. */ +const char FLT_CHARS[] = "df"; + +/* 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. + (The tahoe has plenty of room, so the change currently isn't needed.) + */ + +static struct tit t; /* A tahoe instruction after decoding. */ + +void float_cons (); +/* A table of pseudo ops (sans .), the function called, and an integer op + that the function is called with. */ + +const pseudo_typeS md_pseudo_table[] = +{ + {"dfloat", float_cons, 'd'}, + {"ffloat", float_cons, 'f'}, + {0} +}; + +/* + * For Tahoe, relative addresses of "just the right length" are pretty easy. + * The branch displacement is always the last operand, even in + * synthetic instructions. + * For Tahoe, 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 four states are listed below. + * The "how long" refers merely to the displacement length. + * The address usually has some constant bytes in it as well. + * + +States for Tahoe address relaxing. +1. TAHOE_WIDTH_ALWAYS_JUMP (-) + Format: "b-" + Tahoe opcodes are: (Hex) + jr 11 + jbr 11 + Simple branch. + Always, 1 byte opcode, then displacement/absolute. + If word or longword, change opcode to brw or jmp. + + +2. TAHOE_WIDTH_CONDITIONAL_JUMP (?) + J<cond> where <cond> is a simple flag test. + Format: "b?" + Tahoe opcodes are: (Hex) + jneq/jnequ 21 + jeql/jeqlu 31 + jgtr 41 + jleq 51 + jgeq 81 + jlss 91 + jgtru a1 + jlequ b1 + jvc c1 + jvs d1 + jlssu/jcs e1 + jgequ/jcc f1 + Always, you complement 4th bit to reverse the condition. + Always, 1-byte opcode, then 1-byte displacement. + +3. TAHOE_WIDTH_BIG_REV_JUMP (!) + Jbc/Jbs where cond tests a memory bit. + Format: "rlvlb!" + Tahoe opcodes are: (Hex) + jbs 0e + jbc 1e + Always, you complement 4th bit to reverse the condition. + Always, 1-byte opcde, longword, longword-address, 1-word-displacement + +4. TAHOE_WIDTH_BIG_NON_REV_JUMP (:) + JaoblXX/Jbssi + Format: "rlmlb:" + Tahoe opcodes are: (Hex) + aojlss 2f + jaoblss 2f + aojleq 3f + jaobleq 3f + jbssi 5f + Always, we cannot reverse the sense of the branch; we have a word + displacement. + +We need to modify the opcode is for class 1, 2 and 3 instructions. +After relax() we may complement the 4th bit of 2 or 3 to reverse sense of +branch. + +We sometimes store context in the operand literal. This way we can figure out +after relax() what the original addressing mode was. (Was is pc_rel, or +pc_rel_disp? That sort of thing.) */ + +/* These displacements are relative to the START address of the + displacement which is at the start of the displacement, not the end of + the instruction. The hardware pc_rel is at the end of the instructions. + That's why all the displacements have the length of the displacement added + to them. (WF + length(word)) + + 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)) +#define RELAX_STATE(what) ((what) >> 2) +#define RELAX_LENGTH(length) ((length) && 3) + +#define STATE_ALWAYS_BRANCH (1) +#define STATE_CONDITIONAL_BRANCH (2) +#define STATE_BIG_REV_BRANCH (3) +#define STATE_BIG_NON_REV_BRANCH (4) +#define STATE_PC_RELATIVE (5) + +#define STATE_BYTE (0) +#define STATE_WORD (1) +#define STATE_LONG (2) +#define STATE_UNDF (3) /* Symbol undefined in pass1 */ + +/* This is the table used by gas to figure out relaxing modes. The fields are + forward_branch reach, backward_branch reach, number of bytes it would take, + where the next biggest branch is. */ +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 */ + /* Unconditional branch cases "jrb" + The relax part is the actual displacement */ + { + BF, BB, 1, C (1, 1) + }, /* brb B`foo 1,0 */ + { + WF, WB, 2, C (1, 2) + }, /* brw W`foo 1,1 */ + { + 0, 0, 5, 0 + }, /* Jmp L`foo 1,2 */ + { + 1, 1, 0, 0 + }, /* unused 1,3 */ + /* Reversible Conditional Branch. If the branch won't reach, reverse + it, and jump over a brw or a jmp that will reach. The relax part is the + actual address. */ + { + BF, BB, 1, C (2, 1) + }, /* b<cond> B`foo 2,0 */ + { + WF + 2, WB + 2, 4, C (2, 2) + }, /* brev over, brw W`foo, over: 2,1 */ + { + 0, 0, 7, 0 + }, /* brev over, jmp L`foo, over: 2,2 */ + { + 1, 1, 0, 0 + }, /* unused 2,3 */ + /* Another type of reversable branch. But this only has a word + displacement. */ + { + 1, 1, 0, 0 + }, /* unused 3,0 */ + { + WF, WB, 2, C(3, 2) + }, /* jbX W`foo 3,1 */ + { + 0, 0, 8, 0 + }, /* jrevX over, jmp L`foo, over: 3,2 */ + { + 1, 1, 0, 0 + }, /* unused 3,3 */ + /* These are the non reversable branches, all of which have a word + displacement. If I can't reach, branch over a byte branch, to a + jump that will reach. The jumped branch jumps over the reaching + branch, to continue with the flow of the program. It's like playing + leap frog. */ + { + 1, 1, 0, 0 + }, /* unused 4,0 */ + { + WF, WB, 2, C (4, 2) + }, /* aobl_ W`foo 4,1 */ + { + 0, 0, 10, 0 + }, /*aobl_ W`hop,br over,hop: jmp L^foo,over 4,2*/ + { + 1, 1, 0, 0 + }, /* unused 4,3 */ + /* Normal displacement mode, no jumping or anything like that. + The relax points to one byte before the address, thats why all + the numbers are up by one. */ + { + BF + 1, BB + 1, 2, C (5, 1) + }, /* B^"foo" 5,0 */ + { + WF + 1, WB + 1, 3, C (5, 2) + }, /* W^"foo" 5,1 */ + { + 0, 0, 5, 0 + }, /* L^"foo" 5,2 */ + { + 1, 1, 0, 0 + }, /* unused 5,3 */ +}; + +#undef C +#undef BF +#undef BB +#undef WF +#undef WB +/* End relax stuff */ + +static struct hash_control *op_hash = NULL; /* handle of the OPCODE hash table + NULL means any use before md_begin() will + crash */ + +/* Init function. Build the hash table. */ +void +md_begin() +{ + struct tot *tP; + char *errorval = ""; + int synthetic_too = 1; /* If 0, just use real opcodes. */ + + if ((op_hash = hash_new())){ + for (tP= totstrs; *tP->name && !*errorval; tP++){ + errorval = hash_insert (op_hash, tP->name, &tP->detail); + } + if (synthetic_too){ + for (tP = synthetic_totstrs; *tP->name && !*errorval; tP++){ + errorval = hash_insert (op_hash, tP->name, &tP->detail); + } + } + }else{ + errorval = "Virtual memory exceeded"; + } + if (*errorval) + as_fatal(errorval); +}/* md_begin */ + +void +md_end() +{ +}/* md_end */ + +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 'a': + as_warn("The -a option doesn't exits. (Dispite what the man page says!"); + + case 'J': + as_warn("JUMPIFY (-J) not implemented, use psuedo ops instead."); + 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; + + default: + return 0; + + } + return 1; +} + +/* The functions in this section take numbers in the machine format, and + munges them into Tahoe byte order. + They exist primarily for cross assembly purpose. */ +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 = nbytes; + long int v = value; + + con += nbytes - 1; /* Tahoes is (Bleah!) big endian */ + 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); +} + +#ifdef comment +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. */ +{ + md_number_to_chars(con, value, nbytes); +} +#endif /* comment */ + +void + md_apply_fix(fixP, val) +fixS *fixP; +long val; +{ + char *place = fixP->fx_where + fixP->fx_frag->fr_literal; + md_number_to_chars(place, val, fixP->fx_size); + return; +} /* md_apply_fix() */ + +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. */ +{ + md_number_to_chars(con, value, 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. */ +{ + md_number_to_chars(con, value, nbytes); +} + +/* Put the bits in an order that a tahoe will understand, despite the ordering + of the native machine. + On Tahoe: first 4 bytes are normal unsigned big endian long, + next three bytes are symbolnum, in kind of 3 byte big endian (least sig. byte last). + The last byte is broken up with bit 7 as pcrel, + bits 6 & 5 as length, + bit 4 as extern and the last nibble as 'undefined'. */ + +#if comment +void +md_ri_to_chars (ri_p, ri) + struct relocation_info *ri_p, ri; +{ + byte the_bytes[sizeof(struct relocation_info)]; + /* The reason I can't just encode these directly into ri_p is that + ri_p may point to ri. */ + + /* 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_extern << 4) & 0x10) | ((ri.r_length << 5) & 0x60) | + ((ri.r_pcrel << 7) & 0x80)) & 0xf0; + + bcopy (the_bytes, (char *) ri_p, sizeof (struct relocation_info)); +} +#endif /* comment */ + +/* Put the bits in an order that a tahoe will understand, despite the ordering + of the native machine. + On Tahoe: first 4 bytes are normal unsigned big endian long, + next three bytes are symbolnum, in kind of 3 byte big endian (least sig. byte last). + The last byte is broken up with bit 7 as pcrel, + bits 6 & 5 as length, + bit 4 as extern and the last nibble as 'undefined'. */ + +void tc_aout_fix_to_chars(where, fixP, segment_address_in_file) +char *where; +fixS *fixP; +relax_addressT segment_address_in_file; +{ + /* + * In: length of relocation (or of address) in chars: 1, 2 or 4. + * Out: GNU LD relocation length code: 0, 1, or 2. + */ + + static unsigned char nbytes_r_length[] = { 42, 0, 1, 42, 2 }; + long r_symbolnum; + + know(fixP->fx_addsy != NULL); + + md_number_to_chars(where, + fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, + 4); + + r_symbolnum = (S_IS_DEFINED(fixP->fx_addsy) + ? S_GET_TYPE(fixP->fx_addsy) + : fixP->fx_addsy->sy_number); + + where[4] = (r_symbolnum >> 16) & 0x0ff; + where[5] = (r_symbolnum >> 8) & 0x0ff; + where[6] = r_symbolnum & 0x0ff; + where[7] = (((fixP->fx_pcrel << 7) & 0x80) + | ((nbytes_r_length[fixP->fx_size] << 5) & 0x60) + | ((!S_IS_DEFINED(fixP->fx_addsy) << 4) & 0x10)); + + return; +} /* tc_aout_fix_to_chars() */ + +/* Relocate byte stuff */ + +/* This is for broken word. */ +const int md_short_jump_size = 3; + +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++ = TAHOE_BRW; + md_number_to_chars (ptr, offset, 2); +} + +const int md_long_jump_size = 6; +const int md_reloc_size = 8; /* Size of relocation record */ + +void +md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + long from_addr, to_addr; + fragS *frag; + symbolS *to_symbol; +{ + long offset; + + offset = to_addr - (from_addr + 4); + *ptr++ = TAHOE_JMP; + *ptr++ = TAHOE_PC_REL_LONG; + md_number_to_chars (ptr, offset, 4); +} + +/* + * md_estimate_size_before_relax() + * + * Called just before relax(). + * Any symbol that is now undefined will not become defined, so we assumed + * that it will be resolved by the linker. + * Return the correct fr_subtype in the frag, for relax() + * Return the initial "guess for fr_var" to caller. (How big I think this + * will be.) + * 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; + segT segment_type; /* N_DATA or N_TEXT. */ +{ + register char *p; + register int old_fr_fix; +/* int pc_rel; FIXME: remove this */ + + old_fr_fix = fragP->fr_fix; + switch (fragP->fr_subtype){ + case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_UNDF): + if (S_GET_SEGMENT(fragP->fr_symbol) == segment_type) { + /* The symbol was in the same segment as the opcode, and it's + a real pc_rel case so it's a relaxable case. */ + fragP->fr_subtype = ENCODE_RELAX(STATE_PC_RELATIVE, STATE_BYTE); + }else{ + /* This case is still undefined, so asume it's a long word for the + linker to fix. */ + p = fragP->fr_literal + old_fr_fix; + *p |= TAHOE_PC_OR_LONG; + /* We now know how big it will be, one long word. */ + fragP->fr_fix += 1 + 4; + fix_new (fragP, old_fr_fix + 1, 4, fragP->fr_symbol, 0, + fragP->fr_offset, 1, NO_RELOC); + frag_wane (fragP); + } + break; + + case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_UNDF): + if (S_GET_SEGMENT(fragP->fr_symbol) == segment_type){ + fragP->fr_subtype = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE); + }else{ + p = fragP->fr_literal + old_fr_fix; + *fragP->fr_opcode ^= 0x10; /* Reverse sense of branch. */ + *p++ = 6; + *p++ = TAHOE_JMP; + *p++ = TAHOE_PC_REL_LONG; + fragP->fr_fix += 1 + 1 + 1 + 4; + fix_new (fragP, old_fr_fix + 3, 4, fragP->fr_symbol, 0, + fragP->fr_offset, 1, NO_RELOC); + frag_wane (fragP); + } + break; + + case ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_UNDF): + if (S_GET_SEGMENT(fragP->fr_symbol) == segment_type){ + fragP->fr_subtype = + ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_WORD); + }else{ + p = fragP->fr_literal + old_fr_fix; + *fragP->fr_opcode ^= 0x10; /* Reverse sense of branch. */ + *p++ = 0; + *p++ = 6; + *p++ = TAHOE_JMP; + *p++ = TAHOE_PC_REL_LONG; + fragP->fr_fix += 2 + 2 + 4; + fix_new (fragP, old_fr_fix + 4, 4, fragP->fr_symbol, 0, + fragP->fr_offset, 1, NO_RELOC); + frag_wane (fragP); + } + break; + + case ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_UNDF): + if (S_GET_SEGMENT(fragP->fr_symbol) == segment_type){ + fragP->fr_subtype = ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_WORD); + }else{ + p = fragP->fr_literal + old_fr_fix; + *p++ = 2; + *p++ = 0; + *p++ = TAHOE_BRB; + *p++ = 6; + *p++ = TAHOE_JMP; + *p++ = TAHOE_PC_REL_LONG; + fragP->fr_fix += 2 + 2 + 2 + 4; + fix_new (fragP, old_fr_fix + 6, 4, fragP->fr_symbol, 0, + fragP->fr_offset, 1, NO_RELOC); + frag_wane (fragP); + } + break; + + case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_UNDF): + if (S_GET_SEGMENT(fragP->fr_symbol) == segment_type){ + fragP->fr_subtype = ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE); + }else{ + p = fragP->fr_literal + old_fr_fix; + *fragP->fr_opcode = TAHOE_JMP; + *p++ = TAHOE_PC_REL_LONG; + fragP->fr_fix += 1 + 4; + fix_new (fragP, old_fr_fix + 1, 4, fragP->fr_symbol, 0, + fragP->fr_offset, 1, NO_RELOC); + 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 (headers, fragP) +object_headers *headers; + 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 = 0; /* 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 = RELAX_LENGTH(fragP->fr_subtype); + 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 = S_GET_VALUE(symbolP) + fragP->fr_offset; + address_of_var = fragP->fr_address + where; + switch (fragP->fr_subtype){ + case ENCODE_RELAX(STATE_PC_RELATIVE, STATE_BYTE): + /* *addressP holds the registers number, plus 0x10, if it's deferred + mode. To set up the right mode, just OR the size of this displacement */ + /* Byte displacement. */ + *addressP++ |= TAHOE_PC_OR_BYTE; + *addressP = target_address - (address_of_var + 2); + extension = 2; + break; + + case ENCODE_RELAX(STATE_PC_RELATIVE, STATE_WORD): + /* Word displacement. */ + *addressP++ |= TAHOE_PC_OR_WORD; + md_number_to_chars(addressP, target_address - (address_of_var + 3), 2); + extension = 3; + break; + + case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_LONG): + /* Long word displacement. */ + *addressP++ |= TAHOE_PC_OR_LONG; + md_number_to_chars(addressP, target_address - (address_of_var + 5), 4); + extension = 5; + break; + + case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE): + *addressP = target_address - (address_of_var + 1); + extension = 1; + break; + + case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD): + *opcodeP ^= 0x10; /* Reverse sense of test. */ + *addressP++ = 3; /* Jump over word branch */ + *addressP++ = TAHOE_BRW; + md_number_to_chars (addressP, target_address - (address_of_var + 4), 2); + extension = 4; + break; + + case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_LONG): + *opcodeP ^= 0x10; /* Reverse sense of test. */ + *addressP++ = 6; + *addressP++ = TAHOE_JMP; + *addressP++ = TAHOE_PC_REL_LONG; + md_number_to_chars (addressP, target_address, 4); + extension = 7; + break; + + case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE): + *addressP = target_address - (address_of_var + 1); + extension = 1; + break; + + case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_WORD): + *opcodeP = TAHOE_BRW; + md_number_to_chars (addressP, target_address - (address_of_var + 2), 2); + extension = 2; + break; + + case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_LONG): + *opcodeP = TAHOE_JMP; + *addressP++ = TAHOE_PC_REL_LONG; + md_number_to_chars(addressP, target_address - (address_of_var + 5), 4); + extension = 5; + break; + + case ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_WORD): + md_number_to_chars (addressP, target_address - (address_of_var + 2), 2); + extension = 2; + break; + + case ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_LONG): + *opcodeP ^= 0x10; + *addressP++ = 0; + *addressP++ = 6; + *addressP++ = TAHOE_JMP; + *addressP++ = TAHOE_PC_REL_LONG; + md_number_to_chars (addressP, target_address, 4); + extension = 8; + break; + + case ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_WORD): + md_number_to_chars (addressP, target_address - (address_of_var + 2), 2); + extension = 2; + break; + + case ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_LONG): + *addressP++ = 0; + *addressP++ = 2; + *addressP++ = TAHOE_BRB; + *addressP++ = 6; + *addressP++ = TAHOE_JMP; + *addressP++ = TAHOE_PC_REL_LONG; + md_number_to_chars (addressP, target_address, 4); + extension = 10; + break; + + default: + BAD_CASE (fragP->fr_subtype); + break; + } + fragP->fr_fix += extension; +} /* md_convert_frag */ + + +/* This is the stuff for md_assemble. */ +#define FP_REG 13 +#define SP_REG 14 +#define PC_REG 15 +#define BIGGESTREG PC_REG + +/* + * Parse the string pointed to by START + * If it represents a valid register, point START to the character after + * the last valid register char, and return the register number (0-15). + * If invalid, leave START alone, return -1. + * The format has to be exact. I don't do things like eat leading zeros + * or the like. + * Note: This doesn't check for the next character in the string making + * this invalid. Ex: R123 would return 12, it's the callers job to check + * what start is point to apon return. + * + * Valid registers are R1-R15, %1-%15, FP (13), SP (14), PC (15) + * Case doesn't matter. + */ +int +tahoe_reg_parse(start) + char **start; /* A pointer to the string to parse. */ +{ + register char *regpoint = *start; + register int regnum = -1; + + switch(*regpoint++){ + case '%': /* Registers can start with a %, + R or r, and then a number. */ + case 'R': + case 'r': + if (isdigit(*regpoint)){ + /* Got the first digit. */ + regnum = *regpoint++ - '0'; + if ((regnum == 1) && isdigit(*regpoint)){ + /* Its a two digit number. */ + regnum = 10 + (*regpoint++ - '0'); + if (regnum > BIGGESTREG){ /* Number too big? */ + regnum = -1; + } + } + } + break; + case 'F': /* Is it the FP */ + case 'f': + switch(*regpoint++){ + case 'p': + case 'P': + regnum = FP_REG; + } + break; + case 's': /* How about the SP */ + case 'S': + switch(*regpoint++){ + case 'p': + case 'P': + regnum = SP_REG; + } + break; + case 'p': /* OR the PC even */ + case 'P': + switch(*regpoint++){ + case 'c': + case 'C': + regnum = PC_REG; + } + break; + } + + if (regnum != -1){ /* No error, so move string pointer */ + *start = regpoint; + } + return regnum; /* Return results */ +} /* tahoe_reg_parse */ + +/* + * This chops up an operand and figures out its modes and stuff. + * It's a little touchy about extra characters. + * Optex to start with one extra character so it can be overwritten for + * the backward part of the parsing. + * You can't put a bunch of extra characters in side to + * make the command look cute. ie: * foo ( r1 ) [ r0 ] + * If you like doing a lot of typing, try COBOL! + * Actually, this parser is a little weak all around. It's designed to be + * used with compliers, so I emphisise correct decoding of valid code quickly + * rather that catching every possable error. + * Note: This uses the expression function, so save input_line_pointer before + * calling. + * + * Sperry 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 + * w write + * v bit field address: like 'a' but registers are OK + * + * letter 2: data type (i.e. width, alignment) + * + * b byte + * w word + * l longword + * q quadword (Even regs < 14 allowed) (if 12, you get a warning) + * - unconditional synthetic jbr operand + * ? simple synthetic reversable branch operand + * ! complex synthetic reversable branch operand + * : complex synthetic non-reversable branch operand + * + * The '-?!:' letter 2's are not for external consumption. They are used + * by GAS for psuedo ops relaxing code. + * + * After parsing topP has: + * + * top_ndx: -1, or the index register. eg 7=[R7] + * top_reg: -1, or register number. eg 7 = R7 or (R7) + * top_mode: The addressing mode byte. This byte, defines which of + * the 11 modes opcode is. + * top_access: Access type wanted for this opperand 'b'branch ' ' + * no-instruction 'amrvw' + * top_width: Operand width expected, one of "bwlq?-:!" + * exp_of_operand: The expression as parsed by expression() + * top_dispsize: Number of bytes in the displacement if we can figure it + * out and it's relavent. + * + * Need syntax checks built. + */ + +void +tip_op (optex,topP) + char *optex; /* The users text input, with one leading character */ + struct top *topP;/* The tahoe instruction with some fields already set: + in: access, width + out: ndx, reg, mode, error, dispsize */ + +{ + int mode = 0; /* This operand's mode. */ + char segfault = *optex; /* To keep the back parsing from freaking. */ + char *point = optex+1; /* Parsing from front to back. */ + char *end; /* Parsing from back to front. */ + int reg = -1; /* major register, -1 means absent */ + int imreg = -1; /* Major register in immediate mode */ + int ndx = -1; /* index register number, -1 means absent */ + char dec_inc = ' '; /* Is the SP auto-incremented '+' or + auto-decremented '-' or neither ' '. */ + int immediate = 0; /* 1 if '$' immediate mode */ + int call_width = 0; /* If the caller casts the displacement */ + int abs_width = 0; /* The width of the absolute displacment */ + int com_width = 0; /* Displacement width required by branch */ + int deferred = 0; /* 1 if '*' deferral is used */ + byte disp_size = 0; /* How big is this operand. 0 == don't know */ + char *op_bad = ""; /* Bad operand error */ + + char *tp, *temp, c; /* Temporary holders */ + + char access = topP->top_access; /* Save on a deref. */ + char width = topP->top_width; + + int really_none = 0; /* Empty expressions evaluate to 0 + but I need to know if it's there or not */ + expressionS *expP; /* -> expression values for this operand */ + + /* Does this command restrict the displacement size. */ + if (access == 'b') + com_width = (width == 'b' ? 1 : + (width == 'w' ? 2 : + (width == 'l' ? 4 : 0))); + + *optex = '\0'; /* This is kind of a back stop for all + the searches to fail on if needed.*/ + if (*point == '*') { /* A dereference? */ + deferred = 1; + point++; + } + + /* Force words into a certain mode */ + /* Bitch, Bitch, Bitch! */ + /* + * Using the ^ operator is ambigous. If I have an absolute label + * called 'w' set to, say 2, and I have the expression 'w^1', do I get + * 1, forced to be in word displacement mode, or do I get the value of + * 'w' or'ed with 1 (3 in this case). + * The default is 'w' as an offset, so that's what I use. + * Stick with `, it does the same, and isn't ambig. + */ + + if (*point != '\0' && ((point[1] == '^') || (point[1] == '`'))) + switch(*point){ + case 'b': + case 'B': + case 'w': + case 'W': + case 'l': + case 'L': + if (com_width) + as_warn("Casting a branch displacement is bad form, and is ignored."); + else{ + c = (isupper(*point) ? tolower(*point) : *point); + call_width = ((c == 'b') ? 1 : + ((c == 'w') ? 2 : 4)); + } + point += 2; + break; + } + + /* Setting immediate mode */ + if (*point == '$'){ + immediate = 1; + point++; + } + + /* + * I've pulled off all the easy stuff off the front, move to the end and + * yank. + */ + + for(end = point;*end != '\0';end++) /* Move to the end. */ + ; + + if(end != point) /* Null string? */ + end--; + + if (end > point && *end == ' ' && end[-1] != '\'') + end--; /* Hop white space */ + + /* Is this an index reg. */ + if ((*end == ']') && (end[-1] != '\'')){ + temp = end; + + /* Find opening brace. */ + for(--end;(*end != '[' && end != point);end--) + ; + + /* If I found the opening brace, get the index register number. */ + if (*end == '['){ + tp = end + 1; /* tp should point to the start of a reg. */ + ndx = tahoe_reg_parse(&tp); + if (tp != temp){ /* Reg. parse error. */ + ndx = -1; + } else { + end--; /* Found it, move past brace. */ + } + if (ndx == -1){ + op_bad = "Couldn't parse the [index] in this operand."; + end = point; /* Force all the rest of the tests to fail. */ + } + }else{ + op_bad = "Couldn't find the opening '[' for the index of this operand."; + end = point; /* Force all the rest of the tests to fail. */ + } + } + + /* Post increment? */ + if (*end == '+'){ + dec_inc = '+'; +/* was: *end--; */ + end--; + } + + /* register in parens? */ + if ((*end == ')') && (end[-1] != '\'')){ + temp = end; + + /* Find opening paren. */ + for(--end;(*end != '(' && end != point);end--) + ; + + /* If I found the opening paren, get the register number. */ + if (*end == '('){ + tp = end + 1; + reg = tahoe_reg_parse(&tp); + if (tp != temp){ + /* Not a register, but could be part of the expression. */ + reg = -1; + end = temp; /* Rest the pointer back */ + } else { + end--; /* Found the reg. move before opening paren. */ + } + }else{ + op_bad = "Couldn't find the opening '(' for the deref of this operand."; + end = point; /* Force all the rest of the tests to fail. */ + } + } + + /* Pre decrement? */ + if (*end == '-'){ + if (dec_inc != ' '){ + op_bad = "Operand can't be both pre-inc and post-dec."; + end = point; + }else{ + dec_inc = '-'; +/* was: *end--; */ + end--; + } + } + + /* + * Everything between point and end is the 'expression', unless it's + * a register name. + */ + + c = end[1]; + end[1] = '\0'; + + tp = point; + imreg = tahoe_reg_parse(&point); /* Get the immediate register + if it is there.*/ + if (*point != '\0'){ + /* If there is junk after point, then the it's not immediate reg. */ + point = tp; + imreg = -1; + } + + if (imreg != -1 && reg != -1) + op_bad = "I parsed 2 registers in this operand."; + + /* + * Evaluate whats left of the expression to see if it's valid. + * Note again: This assumes that the calling expression has saved + * input_line_pointer. (Nag, nag, nag!) + */ + + if (*op_bad == '\0'){ + /* statement has no syntax goofs yet: lets sniff the expression */ + input_line_pointer = point; + expP = &(topP->exp_of_operand); + switch (expression (expP)){ + /* If expression == SEG_PASS1, expression() will have set + need_pass_2 = 1. */ + case SEG_ABSENT: + /* No expression. For BSD4.2 compatibility, missing expression is + absolute 0 */ + expP->X_seg = SEG_ABSOLUTE; + expP->X_add_number = 0; + really_none = 1; + case SEG_ABSOLUTE: + /* 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 so. */ + expP->X_add_symbol = NULL; + expP->X_subtract_symbol = NULL; + /* How many bytes are needed to express this abs value? */ + abs_width = + ((((expP->X_add_number & 0xFFFFFF80) == 0) || + ((expP->X_add_number & 0xFFFFFF80) == 0xFFFFFF80)) ? 1 : + (((expP->X_add_number & 0xFFFF8000) == 0) || + ((expP->X_add_number & 0xFFFF8000) == 0xFFFF8000)) ? 2 : 4); + case SEG_TEXT: + case SEG_DATA: + case SEG_BSS: + case SEG_UNKNOWN: + break; + + case SEG_DIFFERENCE: + /* + * Major bug. We can't handle the case of a + * SEG_DIFFERENCE expression in a synthetic opcode + * 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 = 1; + case SEG_PASS1: + op_bad = "Can't relocate expression error."; + break; + + case SEG_BIG: + /* This is an error. Tahoe doesn't allow any expressions + bigger that a 32 bit long word. Any bigger has to be referenced + by address. */ + op_bad = "Expression is too large for a 32 bits."; + break; + + default: + as_fatal("Complier Bug: I got segment %d in tip_op.",expP->X_seg); + break; + } + if (*input_line_pointer != '\0'){ + op_bad = "Junk at end of expression."; + } + } + + end[1] = c; + + /* I'm done, so restore optex */ + *optex = segfault; + + + /* + * At this point in the game, we (in theory) have all the components of + * the operand at least parsed. Now it's time to check for syntax/semantic + * errors, and build the mode. + * This is what I have: + * deferred = 1 if '*' + * call_width = 0,1,2,4 + * abs_width = 0,1,2,4 + * com_width = 0,1,2,4 + * immediate = 1 if '$' + * ndx = -1 or reg num + * dec_inc = '-' or '+' or ' ' + * reg = -1 or reg num + * imreg = -1 or reg num + * topP->exp_of_operand + * really_none + */ + /* Is there a displacement size? */ + disp_size = (call_width ? call_width : + (com_width ? com_width : + abs_width ? abs_width : 0)); + + if (*op_bad == '\0'){ + if (imreg != -1){ + /* Rn */ + mode = TAHOE_DIRECT_REG; + if (deferred || immediate || (dec_inc != ' ') || + (reg != -1) || !really_none) + op_bad = "Syntax error in direct register mode."; + else if (ndx != -1) + op_bad = "You can't index a register in direct register mode."; + else if (imreg == SP_REG && access == 'r') + op_bad = + "SP can't be the source operand with direct register addressing."; + else if (access == 'a') + op_bad = "Can't take the address of a register."; + else if (access == 'b') + op_bad = "Direct Register can't be used in a branch."; + else if (width == 'q' && ((imreg % 2) || (imreg > 13))) + op_bad = "For quad access, the register must be even and < 14."; + else if (call_width) + op_bad = "You can't cast a direct register."; + + if (*op_bad == '\0'){ + /* No errors, check for warnings */ + if (width == 'q' && imreg == 12) + as_warn("Using reg 14 for quadwords can tromp the FP register."); + + reg = imreg; + } + + /* We know: imm = -1 */ + }else if (dec_inc == '-'){ + /* -(SP) */ + mode = TAHOE_AUTO_DEC; + if (deferred || immediate || !really_none) + op_bad = "Syntax error in auto-dec mode."; + else if (ndx != -1) + op_bad = "You can't have an index auto dec mode."; + else if (access == 'r') + op_bad = "Auto dec mode cant be used for reading."; + else if (reg != SP_REG) + op_bad = "Auto dec only works of the SP register."; + else if (access == 'b') + op_bad = "Auto dec can't be used in a branch."; + else if (width == 'q') + op_bad = "Auto dec won't work with quadwords."; + + /* We know: imm = -1, dec_inc != '-' */ + }else if (dec_inc == '+'){ + if (immediate || !really_none) + op_bad = "Syntax error in one of the auto-inc modes."; + else if (deferred){ + /* *(SP)+ */ + mode = TAHOE_AUTO_INC_DEFERRED; + if (reg != SP_REG) + op_bad = "Auto inc deferred only works of the SP register."; + else if (ndx != -1) + op_bad = "You can't have an index auto inc deferred mode."; + else if (access == 'b') + op_bad = "Auto inc can't be used in a branch."; + }else{ + /* (SP)+ */ + mode = TAHOE_AUTO_INC; + if (access == 'm' || access == 'w') + op_bad = "You can't write to an auto inc register."; + else if (reg != SP_REG) + op_bad = "Auto inc only works of the SP register."; + else if (access == 'b') + op_bad = "Auto inc can't be used in a branch."; + else if (width == 'q') + op_bad = "Auto inc won't work with quadwords."; + else if (ndx != -1) + op_bad = "You can't have an index in auto inc mode."; + } + + /* We know: imm = -1, dec_inc == ' ' */ + }else if (reg != -1){ + if ((ndx != -1) && (reg == SP_REG)) + op_bad = "You can't index the sp register."; + if (deferred){ + /* *<disp>(Rn) */ + mode = TAHOE_REG_DISP_DEFERRED; + if (immediate) + op_bad = "Syntax error in register displaced mode."; + }else if (really_none){ + /* (Rn) */ + mode = TAHOE_REG_DEFERRED; + /* if reg = SP then cant be indexed */ + }else{ + /* <disp>(Rn) */ + mode = TAHOE_REG_DISP; + } + + /* We know: imm = -1, dec_inc == ' ', Reg = -1 */ + }else{ + if (really_none) + op_bad = "An offest is needed for this operand."; + if (deferred && immediate){ + /* *$<ADDR> */ + mode = TAHOE_ABSOLUTE_ADDR; + disp_size = 4; + }else if (immediate){ + /* $<disp> */ + mode = TAHOE_IMMEDIATE; + if (ndx != -1) + op_bad = "You can't index a register in immediate mode."; + if (access == 'a') + op_bad = "Immediate access can't be used as an address."; + /* ponder the wisdom of a cast because it doesn't do any good. */ + }else if (deferred){ + /* *<disp> */ + mode = TAHOE_DISP_REL_DEFERRED; + }else{ + /* <disp> */ + mode = TAHOE_DISPLACED_RELATIVE; + } + } + } + + /* + * At this point, all the errors we can do have be checked for. + * We can build the 'top'. */ + + topP->top_ndx = ndx; + topP->top_reg = reg; + topP->top_mode = mode; + topP->top_error = op_bad; + topP->top_dispsize = disp_size; +} /* tip_op */ + +/* + * t i p ( ) + * + * This converts a string into a tahoe instruction. + * The string must be a bare single instruction in tahoe (with BSD4 frobs) + * format. + * It provides at most one fatal error message (which stops the scan) + * some warning messages as it finds them. + * The tahoe instruction is returned in exploded form. + * + * The exploded instruction is returned to a struct tit of your choice. + * #include "tahoe-inst.h" to know what a struct tit is. + * + */ + +static void +tip (titP, instring) + struct tit *titP; /* We build an exploded instruction here. */ + char *instring; /* Text of a vax instruction: we modify. */ +{ + register struct tot_wot *twP = NULL; /* How to bit-encode this opcode. */ + register char *p; /* 1/skip whitespace.2/scan vot_how */ + register char *q; /* */ + register unsigned char count; /* counts number of operands seen */ + register struct top *operandp;/* scan operands in struct tit */ + register char *alloperr = ""; /* error over all operands */ + register char c; /* Remember char, (we clobber it + with '\0' temporarily). */ + char *save_input_line_pointer; + + 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){ + titP->tit_error = "No operator"; + count = 0; + titP->tit_opcode = 0; + } 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. + */ + twP = (struct tot_wot *) hash_find(op_hash, instring); + *p = c; /* Restore char after op-code. */ + if (twP == 0){ + titP->tit_error = "Unknown operator"; + count = 0; + titP->tit_opcode = 0; + }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 tot. + */ + + count = 0; /* no operands seen yet */ + instring = p+(*p!='\0'); /* point past the operation code */ + /* tip_op() screws with the input_line_pointer, so save it before + I jump in */ + save_input_line_pointer = input_line_pointer; + for (p = twP->args, operandp = titP->tit_operand; + !*alloperr && *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]) + as_fatal("Compiler bug: ODD number of bytes in arg structure %s.", + twP->args); + else if (*instring){ + for (q = instring; (*q != ',' && *q != '\0'); q++){ + if (*q == '\'' && q[1] != '\0') /* Jump quoted characters */ + q++; + } + c = *q; + /* + * Q points to ',' or '\0' that ends argument. C is that + * character. + */ + *q = '\0'; + operandp->top_access = p[0]; + operandp->top_width = p[1]; + tip_op(instring-1, operandp); + *q = c; /* Restore input text. */ + if (*(operandp->top_error)){ + alloperr = operandp->top_error; + } + instring = q + (c ? 1 : 0); /* next operand (if any) */ + count++; /* won another argument, may have an operr */ + }else + alloperr = "Not enough operands"; + } + /* Restore the pointer. */ + input_line_pointer = save_input_line_pointer; + + if (!*alloperr){ + if (*instring == ' ') + instring++; /* Skip whitespace. */ + if (*instring) + alloperr = "Too many operands"; + } + titP->tit_error = alloperr; + } + } + + titP->tit_opcode = twP->code; /* The op-code. */ + titP->tit_operands = count; +} /* tip */ + +/* md_assemble() emit frags for 1 instruction */ +void +md_assemble (instruction_string) + char *instruction_string; /* A string: assemble 1 instruction. */ +{ + char *p; + register struct top *operandP; /* An operand. Scans all operands. */ +/* char c_save; fixme: remove this line */ /* What used to live after an expression. */ +/* struct frag *fragP; fixme: remove this line */ /* Fragment of code we just made. */ +/* register struct top *end_operandP; fixme: remove this line */ /* -> 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. */ + +/* tahoe_opcodeT opcode_as_number; fixme: remove this line */ /* The opcode as a number. */ + char *opcodeP; /* Where it is in a frag. */ +/* char *opmodeP; fixme: remove this line */ /* Where opcode type is, in a frag. */ + + int dispsize; /* From top_dispsize: tahoe_operand_width + (in bytes) */ + int is_undefined; /* 1 if operand expression's + segment not known yet. */ + int pc_rel; /* Is this operand pc relative? */ + + /* Decode the operand. */ + tip(&t, instruction_string); + + /* + * Check to see if this operand decode properly. + * Notice that we haven't made any frags yet. + * If it goofed, 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 (*t.tit_error){ + as_warn("Ignoring statement due to \"%s\"", t.tit_error); + }else{ + /* We saw no errors in any operands - try to make frag(s) */ + /* Emit op-code. */ + /* Remember where it is, in case we want to modify the op-code later. */ + opcodeP = frag_more(1); + *opcodeP = t.tit_opcode; + /* Now do each operand. */ + for (operandP = t.tit_operand; + operandP < t.tit_operand + t.tit_operands; + operandP++){ /* for each operand */ + expP = &(operandP->exp_of_operand); + if (operandP->top_ndx >= 0){ + /* Indexed addressing byte + Legality of indexed mode already checked: it is OK */ + FRAG_APPEND_1_CHAR(0x40 + operandP->top_ndx); + } /* if(top_ndx>=0) */ + + /* Here to make main operand frag(s). */ + this_add_number = expP->X_add_number; + this_add_symbol = expP->X_add_symbol; + to_seg = expP->X_seg; + know (to_seg == SEG_UNKNOWN||\ + to_seg == SEG_ABSOLUTE||\ + to_seg == SEG_DATA||\ + to_seg == SEG_TEXT||\ + to_seg == SEG_BSS); + is_undefined = (to_seg == SEG_UNKNOWN); + /* Do we know how big this opperand is? */ + dispsize = operandP->top_dispsize; + pc_rel = 0; + /* Deal with the branch possabilities. (Note, this doesn't include + jumps.)*/ + if (operandP->top_access == 'b'){ + /* Branches must be expressions. A psuedo branch can also jump to + an absolute address. */ + if (to_seg == now_seg || is_undefined){ + /* If is_undefined, then it might BECOME now_seg by relax time. */ + if (dispsize){ + /* I know how big the branch is supposed to be (it's a normal + branch), so I set up the frag, and let GAS do the rest. */ + p = frag_more (dispsize); + fix_new (frag_now, p - frag_now->fr_literal, dispsize, + this_add_symbol, 0, this_add_number, 1, NO_RELOC); + } else { + /* (to_seg==now_seg || to_seg == SEG_UNKNOWN) && dispsize==0 */ + /* If we don't know how big it is, then its a synthetic branch, + so we set up a simple relax state. */ + switch (operandP->top_width){ + case TAHOE_WIDTH_CONDITIONAL_JUMP: + /* Simple (conditional) jump. I may have to reverse the + condition of opcodeP, and then jump to my destination. + I set 1 byte aside for the branch off set, and could need 6 + more bytes for the pc_rel jump */ + frag_var (rs_machine_dependent, 7, 1, + ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, + is_undefined ? STATE_UNDF : STATE_BYTE), + this_add_symbol, this_add_number, opcodeP); + break; + case TAHOE_WIDTH_ALWAYS_JUMP: + /* Simple (unconditional) jump. I may have to convert this to + a word branch, or an absolute jump. */ + frag_var (rs_machine_dependent, 5, 1, + ENCODE_RELAX (STATE_ALWAYS_BRANCH, + is_undefined ? STATE_UNDF : STATE_BYTE), + this_add_symbol, this_add_number, opcodeP); + break; + /* The smallest size for the next 2 cases is word. */ + case TAHOE_WIDTH_BIG_REV_JUMP: + frag_var (rs_machine_dependent, 8, 2, + ENCODE_RELAX (STATE_BIG_REV_BRANCH, + is_undefined ? STATE_UNDF : STATE_WORD), + this_add_symbol, this_add_number, + opcodeP); + break; + case TAHOE_WIDTH_BIG_NON_REV_JUMP: + frag_var (rs_machine_dependent, 10, 2, + ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, + is_undefined ? STATE_UNDF : STATE_WORD), + this_add_symbol, this_add_number, + opcodeP); + break; + default: + as_fatal("Compliler bug: Got a case (%d) I wasn't expecting.", + operandP->top_width); + } + } + }else{ + /* to_seg != now_seg && to_seg != seg_unknown (still in branch) + In other words, I'm jumping out of my segment so extend the + branches to jumps, and let GAS fix them. */ + + /* These are "branches" what will always be branches around a jump + to the correct addresss in real life. + If to_seg is SEG_ABSOLUTE, just encode the branch in, + else let GAS fix the address. */ + + switch (operandP->top_width){ + /* The theory: + For SEG_ABSOLUTE, then mode is ABSOLUTE_ADDR, jump + to that addresss (not pc_rel). + For other segs, address is a long word PC rel jump. */ + case TAHOE_WIDTH_CONDITIONAL_JUMP: + /* b<cond> */ + /* To reverse the condition in a TAHOE branch, + complement bit 4 */ + *opcodeP ^= 0x10; + p = frag_more (7); + *p++ = 6; + *p++ = TAHOE_JMP; + *p++ = (operandP->top_mode == + TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR : + TAHOE_PC_REL_LONG); + fix_new (frag_now, p - frag_now->fr_literal, 4, + this_add_symbol, 0, this_add_number, + (to_seg != SEG_ABSOLUTE), NO_RELOC); + /* + * Now (eg) BLEQ 1f + * JMP foo + * 1: + */ + break; + case TAHOE_WIDTH_ALWAYS_JUMP: + /* br, just turn it into a jump */ + *opcodeP = TAHOE_JMP; + p = frag_more (5); + *p++ = (operandP->top_mode == + TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR : + TAHOE_PC_REL_LONG); + fix_new (frag_now, p - frag_now->fr_literal, 4, + this_add_symbol, 0, this_add_number, + (to_seg != SEG_ABSOLUTE), NO_RELOC); + /* Now (eg) JMP foo */ + break; + case TAHOE_WIDTH_BIG_REV_JUMP: + p = frag_more (8); + *opcodeP ^= 0x10; + *p++ = 0; + *p++ = 6; + *p++ = TAHOE_JMP; + *p++ = (operandP->top_mode == + TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR : + TAHOE_PC_REL_LONG); + fix_new (frag_now, p - frag_now->fr_literal, 4, + this_add_symbol, 0, this_add_number, + (to_seg != SEG_ABSOLUTE), NO_RELOC); + /* + * Now (eg) ACBx 1f + * JMP foo + * 1: + */ + break; + case TAHOE_WIDTH_BIG_NON_REV_JUMP: + p = frag_more (10); + *p++ = 0; + *p++ = 2; + *p++ = TAHOE_BRB; + *p++ = 6; + *p++ = TAHOE_JMP; + *p++ = (operandP->top_mode == + TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR : + TAHOE_PC_REL_LONG); + fix_new (frag_now, p - frag_now->fr_literal, 4, + this_add_symbol, 0, this_add_number, + (to_seg != SEG_ABSOLUTE), NO_RELOC); + /* + * Now (eg) xOBxxx 1f + * BRB 2f + * 1: JMP @#foo + * 2: + */ + break; + case 'b': + case 'w': + as_warn("Real branch displacements must be expressions."); + break; + default: + as_fatal("Complier error: I got an unknown synthetic branch :%c", + operandP->top_width); + break; + } + } + }else{ + /* It ain't a branch operand. */ + switch (operandP->top_mode){ + /* Auto-foo access, only works for one reg (SP) + so the only thing needed is the mode. */ + case TAHOE_AUTO_DEC: + case TAHOE_AUTO_INC: + case TAHOE_AUTO_INC_DEFERRED: + FRAG_APPEND_1_CHAR(operandP->top_mode); + break; + + /* Numbered Register only access. Only thing needed is the + mode + Register number */ + case TAHOE_DIRECT_REG: + case TAHOE_REG_DEFERRED: + FRAG_APPEND_1_CHAR(operandP->top_mode + operandP->top_reg); + break; + + /* An absolute address. It's size is always 5 bytes. + (mode_type + 4 byte address). */ + case TAHOE_ABSOLUTE_ADDR: + know((this_add_symbol == NULL)); + p = frag_more(5); + *p = TAHOE_ABSOLUTE_ADDR; + md_number_to_chars(p+1,this_add_number,4); + break; + + /* Immediate data. If the size isn't known, then it's an address + + and offset, which is 4 bytes big. */ + case TAHOE_IMMEDIATE: + if (this_add_symbol != NULL){ + p = frag_more (5); + *p++ = TAHOE_IMMEDIATE_LONGWORD; + fix_new (frag_now, p - frag_now->fr_literal, + 4, this_add_symbol,0,this_add_number, + 0, NO_RELOC); + }else{ + /* It's a integer, and I know it's size. */ + if ((unsigned) this_add_number < 0x40){ + /* Will it fit in a literal? */ + FRAG_APPEND_1_CHAR((byte) this_add_number); + }else{ + p = frag_more(dispsize+1); + switch(dispsize){ + case 1: + *p++ = TAHOE_IMMEDIATE_BYTE; + *p = (byte) this_add_number; + break; + case 2: + *p++ = TAHOE_IMMEDIATE_WORD; + md_number_to_chars(p,this_add_number,2); + break; + case 4: + *p++ = TAHOE_IMMEDIATE_LONGWORD; + md_number_to_chars(p,this_add_number,4); + break; + } + } + } + break; + + /* Distance from the PC. If the size isn't known, we have to relax + into it. The difference between this and disp(sp) is that + this offset is pc_rel, and disp(sp) isn't. + Note the drop through code. */ + + case TAHOE_DISPLACED_RELATIVE: + case TAHOE_DISP_REL_DEFERRED: + operandP->top_reg = PC_REG; + pc_rel = 1; + + /* Register, plus a displacement mode. Save the register number, + and weather its deffered or not, and relax the size if it isn't + known. */ + case TAHOE_REG_DISP: + case TAHOE_REG_DISP_DEFERRED: + if (operandP->top_mode == TAHOE_DISP_REL_DEFERRED || + operandP->top_mode == TAHOE_REG_DISP_DEFERRED) + operandP->top_reg += 0x10; /* deffered mode is always 0x10 higher + than it's non-deffered sibling. */ + + /* Is this a value out of this segment? + The first part of this conditional is a cludge to make gas + produce the same output as 'as' when there is a lable, in + the current segment, displaceing a register. It's strange, + and no one in their right mind would do it, but it's easy + to cludge. */ + if ((dispsize == 0 && !pc_rel) || + (to_seg != now_seg && !is_undefined && to_seg != SEG_ABSOLUTE)) + dispsize = 4; + + if (dispsize == 0){ + /* + * We have a SEG_UNKNOWN symbol, or the size isn't cast. + * 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, + is_undefined ? STATE_UNDF:STATE_BYTE), + this_add_symbol, this_add_number,0); + *p = operandP->top_reg; + }else{ + /* Either this is an abs, or a cast. */ + p = frag_more (dispsize + 1); + switch(dispsize){ + case 1: + *p = TAHOE_PC_OR_BYTE + operandP->top_reg; + break; + case 2: + *p = TAHOE_PC_OR_WORD + operandP->top_reg; + break; + case 4: + *p = TAHOE_PC_OR_LONG + operandP->top_reg; + break; + }; + fix_new (frag_now, p + 1 - frag_now->fr_literal, + dispsize, this_add_symbol,0,this_add_number, + pc_rel, NO_RELOC); + } + break; + default: + as_fatal("Barf, bad mode %x\n",operandP->top_mode); + } + } + } /* for(operandP) */ + } /* if(!need_pass_2 && !goofed) */ +} /* tahoe_assemble() */ + + +/* We have no need to default values of symbols. */ + +/* ARGSUSED */ +symbolS *md_undefined_symbol(name) +char *name; +{ + return 0; +} /* md_undefined_symbol() */ + +/* Parse an operand that is machine-specific. + We just return without modifying the expression if we have nothing + to do. */ + +/* ARGSUSED */ +void md_operand(expressionP) +expressionS *expressionP; +{ +} /* md_operand() */ + +/* Round up a section size to the appropriate boundary. */ +long md_section_align(segment, size) +segT segment; +long size; +{ + return((size + 7) & ~7); /* Round all sects to multiple of 8 */ +} /* md_section_align() */ + +/* Exactly what point is a PC-relative offset relative TO? + On the sparc, they're relative to the address of the offset, plus + its size. This gets us to the following instruction. + (??? Is this right? FIXME-SOON) */ +long md_pcrel_from(fixP) +fixS *fixP; +{ + return(fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address); +} /* md_pcrel_from() */ + +/* end of tc-tahoe.c */ diff --git a/gnu/usr.bin/as/config/tc-tahoe.h b/gnu/usr.bin/as/config/tc-tahoe.h new file mode 100644 index 000000000000..e63cb63a881f --- /dev/null +++ b/gnu/usr.bin/as/config/tc-tahoe.h @@ -0,0 +1,36 @@ +/* This file is tc-tahoe.h + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define TC_TAHOE 1 + +#define NO_LISTING + +#define tc_headers_hook(a) {;} /* don't need it. */ +#define tc_crawl_symbol_chain(a) {;} /* don't need it. */ +#define tc_aout_pre_write_hook(a) {;} + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of tc-tahoe.h */ diff --git a/gnu/usr.bin/as/config/tc-vax.c b/gnu/usr.bin/as/config/tc-vax.c new file mode 100644 index 000000000000..9133c8436352 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-vax.c @@ -0,0 +1,3073 @@ +/* tc-vax.c - vax-specific - + Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 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 "vax-inst.h" +#include "obstack.h" /* For FRAG_APPEND_1_CHAR macro in "frags.h" */ + +/* These chars start a comment anywhere in a source file (except inside + another comment */ +const char comment_chars[] = "#"; + +/* These chars only start a comment at the beginning of a line. */ +/* Note that for the VAX the are the same as comment_chars above. */ +const char line_comment_chars[] = "#"; + +/* Chars that can be used to separate mant from exp in floating point nums */ +const char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant */ +/* as in 0f123.456 */ +/* or 0H1.234E-12 (see exp chars above) */ +const char FLT_CHARS[] = "dDfFgGhH"; + +/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be + changed in read.c. Ideally it shouldn't have to know about it at all, + but nothing is ideal around here. + */ + +static expressionS /* Hold details of an operand expression */ + exp_of_operand[VIT_MAX_OPERANDS]; + +static struct vit + v; /* A vax instruction after decoding. */ + +LITTLENUM_TYPE big_operand_bits[VIT_MAX_OPERANDS][SIZE_OF_LARGE_NUMBER]; +/* Hold details of big operands. */ +FLONUM_TYPE float_operand[VIT_MAX_OPERANDS]; +/* Above is made to point into */ +/* big_operand_bits by md_begin(). */ + +/* + * For VAX, relative addresses of "just the right length" are easy. + * The branch displacement is always the last operand, even in + * synthetic instructions. + * For VAX, we encode the relax_substateTs (in e.g. fr_substate) as: + * + * 4 3 2 1 0 bit number + * ---/ /--+-------+-------+-------+-------+-------+ + * | what state ? | how long ? | + * ---/ /--+-------+-------+-------+-------+-------+ + * + * The "how long" bits are 00=byte, 01=word, 10=long. + * This is a Un*x convention. + * Not all lengths are legit for a given value of (what state). + * The "how long" refers merely to the displacement length. + * The address usually has some constant bytes in it as well. + * + + groups for VAX address relaxing. + + 1. "foo" pc-relative. + length of byte, word, long + + 2a. J<cond> where <cond> is a simple flag test. + length of byte, word, long. + VAX opcodes are: (Hex) + bneq/bnequ 12 + beql/beqlu 13 + bgtr 14 + bleq 15 + bgeq 18 + blss 19 + bgtru 1a + blequ 1b + bvc 1c + bvs 1d + bgequ/bcc 1e + blssu/bcs 1f + Always, you complement 0th bit to reverse condition. + Always, 1-byte opcode, then 1-byte displacement. + + 2b. J<cond> where cond tests a memory bit. + length of byte, word, long. + Vax opcodes are: (Hex) + bbs e0 + bbc e1 + bbss e2 + bbcs e3 + bbsc e4 + bbcc e5 + bbssi e6 + bbcci e7 + Always, you complement 0th bit to reverse condition. + Always, 1-byte opcde, longword-address, byte-address, 1-byte-displacement + + 2c. J<cond> where cond tests low-order memory bit + length of byte,word,long. + Vax opcodes are: (Hex) + blbs e8 + blbc e9 + Always, you complement 0th bit to reverse condition. + Always, 1-byte opcode, longword-address, 1-byte displacement. + + 3. Jbs/Jbr. + length of byte,word,long. + Vax opcodes are: (Hex) + bsbb 10 + brb 11 + These are like (2) but there is no condition to reverse. + Always, 1 byte opcode, then displacement/absolute. + + 4a. JacbX + length of word, long. + Vax opcodes are: (Hex) + acbw 3d + acbf 4f + acbd 6f + abcb 9d + acbl f1 + acbg 4ffd + acbh 6ffd + Always, we cannot reverse the sense of the branch; we have a word + displacement. + The double-byte op-codes don't hurt: we never want to modify the + opcode, so we don't care how many bytes are between the opcode and + the operand. + + 4b. JXobXXX + length of long, long, byte. + Vax opcodes are: (Hex) + aoblss f2 + aobleq f3 + sobgeq f4 + sobgtr f5 + Always, we cannot reverse the sense of the branch; we have a byte + displacement. + + The only time we need to modify the opcode is for class 2 instructions. + After relax() we may complement the lowest order bit of such instruction + to reverse sense of branch. + + For class 2 instructions, we store context of "where is the opcode literal". + We can change an opcode's lowest order bit without breaking anything else. + + We sometimes store context in the operand literal. This way we can figure out + after relax() what the original addressing mode was. + */ + +/* These displacements are relative to */ +/* the start address of the displacement. */ +/* The first letter is Byte, Word. */ +/* 2nd letter is Forward, Backward. */ +#define BF (1+ 127) +#define BB (1+-128) +#define WF (2+ 32767) +#define WB (2+-32768) +/* Dont need LF, LB because they always */ +/* reach. [They are coded as 0.] */ + + +#define C(a,b) ENCODE_RELAX(a,b) +/* This macro has no side-effects. */ +#define ENCODE_RELAX(what,length) (((what) << 2) + (length)) + +const relax_typeS + md_relax_table[] = +{ + { 1, 1, 0, 0 }, /* error sentinel 0,0 */ + { 1, 1, 0, 0 }, /* unused 0,1 */ + { 1, 1, 0, 0 }, /* unused 0,2 */ + { 1, 1, 0, 0 }, /* unused 0,3 */ + { BF + 1, BB + 1, 2, C(1, 1) }, /* B^"foo" 1,0 */ + { WF + 1, WB + 1, 3, C (1, 2) }, /* W^"foo" 1,1 */ + { 0, 0, 5, 0 }, /* L^"foo" 1,2 */ + { 1, 1, 0, 0 }, /* unused 1,3 */ + { BF, BB, 1, C(2, 1) }, /* b<cond> B^"foo" 2,0 */ + { WF + 2, WB + 2, 4, C (2, 2) }, /* br.+? brw X 2,1 */ + { 0, 0, 7, 0 }, /* br.+? jmp X 2,2 */ + { 1, 1, 0, 0 }, /* unused 2,3 */ + { BF, BB, 1, C (3, 1) }, /* brb B^foo 3,0 */ + { WF, WB, 2, C (3, 2) }, /* brw W^foo 3,1 */ + { 0, 0, 5, 0 }, /* Jmp L^foo 3,2 */ + { 1, 1, 0, 0 }, /* unused 3,3 */ + { 1, 1, 0, 0 }, /* unused 4,0 */ + { WF, WB, 2, C (4, 2) }, /* acb_ ^Wfoo 4,1 */ + { 0, 0, 10, 0 }, /* acb_,br,jmp L^foo4,2 */ + { 1, 1, 0, 0 }, /* unused 4,3 */ + { BF, BB, 1, C (5, 1) }, /* Xob___,,foo 5,0 */ + { WF + 4, WB + 4, 6, C (5, 2) }, /* Xob.+2,brb.+3,brw5,1 */ + { 0, 0, 9, 0 }, /* Xob.+2,brb.+6,jmp5,2 */ +}; + +#undef C +#undef BF +#undef BB +#undef WF +#undef WB + +void float_cons (); + +const pseudo_typeS md_pseudo_table[] = { + {"dfloat", float_cons, 'd'}, + {"ffloat", float_cons, 'f'}, + {"gfloat", float_cons, 'g'}, + {"hfloat", float_cons, 'h'}, + {0}, +}; + +#define STATE_PC_RELATIVE (1) +#define STATE_CONDITIONAL_BRANCH (2) +#define STATE_ALWAYS_BRANCH (3) /* includes BSB... */ +#define STATE_COMPLEX_BRANCH (4) +#define STATE_COMPLEX_HOP (5) + +#define STATE_BYTE (0) +#define STATE_WORD (1) +#define STATE_LONG (2) +#define STATE_UNDF (3) /* Symbol undefined in pass1 */ + + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +#if __STDC__ == 1 + +int flonum_gen2vax(char format_letter, FLONUM_TYPE *f, LITTLENUM_TYPE *words); +static void vip_end(void); +static void vip_op_defaults(char *immediate, char *indirect, char *displen); + +#else /* not __STDC__ */ + +int flonum_gen2vax(); +static void vip_end(); +static void vip_op_defaults(); + +#endif /* not __STDC__ */ + +void + md_begin () +{ + char *vip_begin (); + char *errtxt; + FLONUM_TYPE *fP; + int i; + + if (*(errtxt = vip_begin (1, "$", "*", "`"))) { + 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 value; /* The value of the bits. */ +int nbytes; /* Number of bytes in the output. */ +{ + int n; + long v; + + n = nbytes; + v = value; + while (nbytes--) { + *con++ = value; /* Lint wants & MASK_CHAR. */ + value >>= BITS_PER_CHAR; + } + /* XXX line number probably botched for this warning message. */ + if (value != 0 && value != -1) + as_bad("Displacement (%ld) long for instruction field length (%d).", v, n); +} + +/* Fix up some data or instructions after we find out the value of a symbol + that they reference. */ + +void /* Knows about order of bytes in address. */ + md_apply_fix(fixP, value) +fixS *fixP; /* Fixup struct pointer */ +long value; /* The value of the bits. */ +{ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + int nbytes; /* Number of bytes in the output. */ + + nbytes = fixP->fx_size; + while (nbytes--) { + *buf++ = value; /* Lint wants & MASK_CHAR. */ + value >>= BITS_PER_CHAR; + } +} + +long /* Knows about the byte order in a word. */ + md_chars_to_number (con, nbytes) +unsigned char con[]; /* Low order byte 1st. */ +int nbytes; /* Number of bytes in the input. */ +{ + long retval; + for (retval = 0, con += nbytes - 1; nbytes--; con--) { + retval <<= BITS_PER_CHAR; + retval |= *con; + } + return retval; +} + +/* vax:md_assemble() emit frags for 1 instruction */ + +void + md_assemble (instruction_string) +char *instruction_string; /* A string: assemble 1 instruction. */ +{ + /* We saw no errors in any operands - try to make frag(s) */ + int is_undefined; /* 1 if operand expression's */ + /* segment not known yet. */ + int length_code; + + 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. */ + /* fixme: unused? */ +/* struct frag *fragP; */ /* Fragment of code we just made. */ + register int goofed; /* 1: instruction_string bad for all passes. */ + register struct vop *end_operandP; /* -> slot just after last operand */ + /* Limit of the for (each operand). */ + register expressionS *expP; /* -> expression values for this operand */ + + /* These refer to an instruction operand expression. */ + segT to_seg; /* Target segment of the address. */ + register valueT this_add_number; + register struct symbol *this_add_symbol; /* +ve (minuend) symbol. */ + register struct symbol *this_subtract_symbol; /* -ve(subtrahend) symbol. */ + + long opcode_as_number; /* As a number. */ + char *opcode_as_chars; /* Least significant byte 1st. */ + /* As an array of characters. */ + char *opcode_low_byteP; /* Least significant byte 1st */ + /* richfix: unused? */ +/* 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=1. Notice that we don't make any frags yet. + * Should goofed be 1, 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 = 1; + } else { /* statement has no syntax goofs: lets sniff the expression */ + int can_be_short = 0; /* 1 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 = 1. */ + switch (to_seg = expression (expP)) { + case SEG_ABSENT: + /* for BSD4.2 compatibility, missing expression is absolute 0 */ + to_seg = expP->X_seg = SEG_ABSOLUTE; + expP->X_add_number = 0; + /* for SEG_ABSOLUTE, we shouldnt need to set X_subtract_symbol, X_add_symbol to any + particular value. But, we will program defensively. Since this situation occurs rarely + so it costs us little to do, and stops Dean worrying about the origin of random bits in + expressionS's. */ + expP->X_add_symbol = NULL; + expP->X_subtract_symbol = NULL; + case SEG_TEXT: + case SEG_DATA: + case SEG_BSS: + case SEG_ABSOLUTE: + case SEG_UNKNOWN: + break; + + case SEG_DIFFERENCE: + case SEG_PASS1: + /* + * Major bug. We can't handle the case of a + * SEG_DIFFERENCE expression in a VIT_OPCODE_SYNTHETIC + * variable-length instruction. + * We don't have a frag type that is smart enough to + * relax a SEG_DIFFERENCE, and so we just force all + * SEG_DIFFERENCEs to behave like SEG_PASS1s. + * Clearly, if there is a demand we can invent a new or + * modified frag type and then coding up a frag for this + * case will be easy. SEG_DIFFERENCE was invented for the + * .words after a CASE opcode, and was never intended for + * instruction operands. + */ + need_pass_2 = 1; + as_warn("Can't relocate expression"); + break; + + case SEG_BIG: + /* Preserve the bits. */ + if (expP->X_add_number > 0) { + bignum_copy(generic_bignum, expP->X_add_number, + floatP->low, SIZE_OF_LARGE_NUMBER); + } else { + know(expP->X_add_number < 0); + flonum_copy (&generic_floating_point_number, + floatP); + if (strchr("s i", operandP->vop_short)) { /* Could possibly become S^# */ + flonum_gen2vax(-expP->X_add_number, floatP, literal_float); + switch (-expP->X_add_number) { + case 'f': + can_be_short = + (literal_float[0] & 0xFC0F) == 0x4000 + && literal_float[1] == 0; + break; + + case 'd': + can_be_short = + (literal_float[0] & 0xFC0F) == 0x4000 + && literal_float[1] == 0 + && literal_float[2] == 0 + && literal_float[3] == 0; + break; + + case 'g': + can_be_short = + (literal_float[0] & 0xFF81) == 0x4000 + && literal_float[1] == 0 + && literal_float[2] == 0 + && literal_float[3] == 0; + break; + + case 'h': + can_be_short = ((literal_float[0] & 0xFFF8) == 0x4000 + && (literal_float[1] & 0xE000) == 0 + && literal_float[2] == 0 + && literal_float[3] == 0 + && literal_float[4] == 0 + && literal_float[5] == 0 + && literal_float[6] == 0 + && literal_float[7] == 0); + break; + + default: + BAD_CASE(-expP->X_add_number); + break; + } /* switch (float type) */ + } /* if (could want to become S^#...) */ + } /* bignum or flonum ? */ + + if (operandP->vop_short == 's' + || operandP->vop_short == 'i' + || (operandP->vop_short == ' ' + && operandP->vop_reg == 0xF + && (operandP->vop_mode & 0xE) == 0x8)) { + /* Saw a '#'. */ + if (operandP->vop_short == ' ') { /* We must chose S^ or I^. */ + if (expP->X_add_number > 0) { /* Bignum: Short literal impossible. */ + operandP->vop_short = 'i'; + operandP->vop_mode = 8; + operandP->vop_reg = 0xF; /* VAX PC. */ + } else { /* Flonum: Try to do it. */ + if (can_be_short) + { + operandP->vop_short = 's'; + operandP->vop_mode = 0; + operandP->vop_ndx = -1; + operandP->vop_reg = -1; + /* JF hope this is the right thing */ + expP->X_seg = SEG_ABSOLUTE; + } else { + operandP->vop_short = 'i'; + operandP->vop_mode = 8; + operandP->vop_reg = 0xF; /* VAX PC */ + } + } /* bignum or flonum ? */ + } /* if #, but no S^ or I^ seen. */ + /* No more ' ' case: either 's' or 'i'. */ + if (operandP->vop_short == 's') { + /* Wants to be a short literal. */ + if (expP->X_add_number > 0) { + as_warn ("Bignum not permitted in short literal. Immediate mode assumed."); + operandP->vop_short = 'i'; + operandP->vop_mode = 8; + operandP->vop_reg = 0xF; /* VAX PC. */ + } else { + if (!can_be_short) { + as_warn ("Can't do flonum short literal: immediate mode used."); + operandP->vop_short = 'i'; + operandP->vop_mode = 8; + operandP->vop_reg = 0xF; /* VAX PC. */ + } else { /* Encode short literal now. */ + int temp = 0; + + 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) { + memcpy(floatP->low, literal_float, 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 = 1; + } + operandP->vop_expr_end[1] = c_save; + } + } /* for (each operand) */ + + input_line_pointer = save_input_line_pointer; + + if (need_pass_2 || goofed) { + return; + } + + + /* 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); + memcpy(opcode_low_byteP, v.vit_opcode, 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, NO_RELOC); + } 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, NO_RELOC); + } else { + know(opcode_as_number & VIT_OPCODE_SYNTHETIC); + if (opcode_as_number & VIT_OPCODE_SPECIAL) { + if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP) { + /* br or jsb */ + *opcode_low_byteP = opcode_as_chars[0] + VAX_WIDEN_LONG; + know(opcode_as_chars[1] == 0); + p = frag_more (5); + p[0] = VAX_ABSOLUTE_MODE; /* @#... */ + md_number_to_chars(p + 1, this_add_number, 4); + /* Now (eg) JMP @#foo or JSB @#foo. */ + } else { + if (operandP->vop_width == VAX_WIDTH_WORD_JUMP) { + p = frag_more (10); + p[0] = 2; + p[1] = 0; + p[2] = VAX_BRB; + p[3] = 6; + p[4] = VAX_JMP; + p[5] = VAX_ABSOLUTE_MODE; /* @#... */ + md_number_to_chars(p + 6, this_add_number, 4); + /* + * Now (eg) ACBx 1f + * BRB 2f + * 1: JMP @#foo + * 2: + */ + } else { + know(operandP->vop_width == VAX_WIDTH_BYTE_JUMP); + p = frag_more (9); + p[0] = 2; + p[1] = VAX_BRB; + p[2] = 6; + p[3] = VAX_JMP; + p[4] = VAX_PC_RELATIVE_MODE + 1; /* @#... */ + md_number_to_chars(p + 5, this_add_number, 4); + /* + * Now (eg) xOBxxx 1f + * BRB 2f + * 1: JMP @#foo + * 2: + */ + } + } + } else { + /* b<cond> */ + *opcode_low_byteP ^= 1; + /* To reverse the condition in a VAX branch, complement the lowest order + bit. */ + p = frag_more (7); + p[0] = 6; + p[1] = VAX_JMP; + p[2] = VAX_ABSOLUTE_MODE; /* @#... */ + md_number_to_chars(p + 3, this_add_number, 4); + /* + * Now (eg) BLEQ 1f + * JMP @#foo + * 1: + */ + } + } + } else { /* to_seg != now_seg && to_seg != SEG_UNKNOWN && to_Seg != SEG_ABSOLUTE */ + if (nbytes > 0) { + /* Pc-relative. Conventional relocation. */ + know(!(opcode_as_number & VIT_OPCODE_SYNTHETIC)); + p = frag_more (nbytes); + fix_new(frag_now, p - frag_now->fr_literal, + nbytes, &abs_symbol, 0, this_add_number, 1, NO_RELOC); + } 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, NO_RELOC); + /* 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, NO_RELOC); + /* + * 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, NO_RELOC); + /* + * 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, NO_RELOC); + } + } + } + } + } else { + know(operandP->vop_access != 'b'); /* So it is ordinary operand. */ + know(operandP->vop_access != ' '); /* ' ' target-independent: elsewhere. */ + know(operandP->vop_access == 'a' + || operandP->vop_access == 'm' + || operandP->vop_access == 'r' + || operandP->vop_access == 'v' + || operandP->vop_access == 'w'); + if (operandP->vop_short == 's') { + if (to_seg == SEG_ABSOLUTE) { + if (this_add_number < 0 || this_add_number >= 64) { + as_warn("Short literal overflow(%d.), immediate mode assumed.", this_add_number); + operandP->vop_short = 'i'; + operandP->vop_mode = 8; + operandP->vop_reg = 0xF; + } + } else { + as_warn ("Forced short literal to immediate mode. now_seg=%s to_seg=%s", + segment_name(now_seg), segment_name(to_seg)); + operandP->vop_short = 'i'; + operandP->vop_mode = 8; + operandP->vop_reg = 0xF; + } + } + if (operandP->vop_reg >= 0 && (operandP->vop_mode < 8 + || (operandP->vop_reg != 0xF && operandP->vop_mode < 10))) { + /* One byte operand. */ + know(operandP->vop_mode > 3); + FRAG_APPEND_1_CHAR (operandP->vop_mode << 4 | operandP->vop_reg); + /* All 1-bytes except S^# happen here. */ + } else { /* {@}{q^}foo{(Rn)} or S^#foo */ + if (operandP->vop_reg == -1 && operandP->vop_short != 's') { + /* "{@}{q^}foo" */ + if (to_seg == now_seg) { + if (length == 0) { + know(operandP->vop_short == ' '); + p = frag_var(rs_machine_dependent, 10, 2, + ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE), + this_add_symbol, this_add_number, + opcode_low_byteP); + know(operandP->vop_mode == 10 + at); + *p = at << 4; + /* At is the only context we need to carry to */ + /* other side of relax() process. */ + /* Must be in the correct bit position of VAX */ + /* operand spec. byte. */ + } else { + know(length); + know(operandP->vop_short != ' '); + p = frag_more (length + 1); + /* JF is this array stuff really going to work? */ + p[0] = 0xF | ((at + "?\12\14?\16"[length]) << 4); + fix_new(frag_now, p + 1 - frag_now->fr_literal, + length, this_add_symbol, 0, + this_add_number, 1, NO_RELOC); + } + } 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, NO_RELOC); + } + } + } + } 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) + { + memset(p + 5, '\0', 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, NO_RELOC); + } + } + } + } else { /* {@}{q^}foo(Rn) */ + know((length == 0 && operandP->vop_short == ' ') + ||(length > 0 && operandP->vop_short != ' ')); + if (length == 0) { + if (to_seg == SEG_ABSOLUTE) { + register long test; + + test = this_add_number; + + if (test < 0) + test = ~test; + + length = test & 0xffff8000 ? 4 + : test & 0xffffff80 ? 2 + : 1; + } else { + length = 4; + } + } + p = frag_more (1 + length); + know(operandP->vop_reg >= 0); + p[0] = operandP->vop_reg + | ((at | "?\12\14?\16"[length]) << 4); + if (to_seg == SEG_ABSOLUTE) { + md_number_to_chars(p + 1, this_add_number, length); + } else { + fix_new(frag_now, p + 1 - frag_now->fr_literal, + length, this_add_symbol, 0, + this_add_number, 0, NO_RELOC); + } + } + } + } /* if (single-byte-operand) */ + } + } /* for (operandP) */ +} /* 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) +register fragS *fragP; +register segT segment; +{ + register char *p; + register int old_fr_fix; + + old_fr_fix = fragP->fr_fix; + switch (fragP->fr_subtype) { + case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_UNDF): + if (S_GET_SEGMENT(fragP->fr_symbol) == segment) { /* A relaxable case. */ + fragP->fr_subtype = ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE); + } else { + p = fragP->fr_literal + old_fr_fix; + p[0] |= VAX_PC_RELATIVE_MODE; /* Preserve @ bit. */ + fragP->fr_fix += 1 + 4; + fix_new(fragP, old_fr_fix + 1, 4, fragP->fr_symbol, 0, + fragP->fr_offset, 1, NO_RELOC); + frag_wane(fragP); + } + break; + + case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_UNDF): + if (S_GET_SEGMENT(fragP->fr_symbol) == segment) { + fragP->fr_subtype = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE); + } else { + p = fragP->fr_literal + old_fr_fix; + *fragP->fr_opcode ^= 1; /* Reverse sense of branch. */ + p[0] = 6; + p[1] = VAX_JMP; + p[2] = VAX_PC_RELATIVE_MODE; /* ...(PC) */ + fragP->fr_fix += 1 + 1 + 1 + 4; + fix_new(fragP, old_fr_fix + 3, 4, fragP->fr_symbol, 0, + fragP->fr_offset, 1, NO_RELOC); + frag_wane(fragP); + } + break; + + case ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_UNDF): + if (S_GET_SEGMENT(fragP->fr_symbol) == segment) { + fragP->fr_subtype = ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_WORD); + } else { + p = fragP->fr_literal + old_fr_fix; + p[0] = 2; + p[1] = 0; + p[2] = VAX_BRB; + p[3] = 6; + p[4] = VAX_JMP; + p[5] = VAX_PC_RELATIVE_MODE; /* ...(pc) */ + fragP->fr_fix += 2 + 2 + 1 + 1 + 4; + fix_new(fragP, old_fr_fix + 6, 4, fragP->fr_symbol, 0, + fragP->fr_offset, 1, NO_RELOC); + frag_wane(fragP); + } + break; + + case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_UNDF): + if (S_GET_SEGMENT(fragP->fr_symbol) == segment) { + fragP->fr_subtype = ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_BYTE); + } else { + p = fragP->fr_literal + old_fr_fix; + p[0] = 2; + p[1] = VAX_BRB; + p[2] = 6; + p[3] = VAX_JMP; + p[4] = VAX_PC_RELATIVE_MODE; /* ...(pc) */ + fragP->fr_fix += 1 + 2 + 1 + 1 + 4; + fix_new(fragP, old_fr_fix + 5, 4, fragP->fr_symbol, 0, + fragP->fr_offset, 1, NO_RELOC); + frag_wane(fragP); + } + break; + + case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_UNDF): + if (S_GET_SEGMENT(fragP->fr_symbol) == segment) { + fragP->fr_subtype = ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE); + } else { + p = fragP->fr_literal + old_fr_fix; + *fragP->fr_opcode += VAX_WIDEN_LONG; + p[0] = VAX_PC_RELATIVE_MODE; /* ...(PC) */ + fragP->fr_fix += 1 + 4; + fix_new(fragP, old_fr_fix + 1, 4, fragP->fr_symbol, 0, + fragP->fr_offset, 1, NO_RELOC); + 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 (headers, fragP) +object_headers *headers; +register fragS *fragP; +{ + char *addressP; /* -> _var to change. */ + char *opcodeP; /* -> opcode char(s) to change. */ + short int length_code; /* 2=long 1=word 0=byte */ + short int extension = 0; /* Size of relaxed address. */ + /* Added to fr_fix: incl. ALL var chars. */ + symbolS *symbolP; + long where; + long address_of_var; + /* Where, in file space, is _var of *fragP? */ + long target_address = 0; + /* 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 = S_GET_VALUE(symbolP) + 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; +} /* md_convert_frag() */ + +/* Translate internal format of relocation info into target format. + + On vax: first 4 bytes are normal unsigned long, next three bytes + are symbolnum, least sig. byte first. Last byte is broken up with + the upper nibble as nuthin, bit 3 as extern, bits 2 & 1 as length, and + bit 0 as pcrel. */ +#ifdef comment +void + md_ri_to_chars (the_bytes, ri) +char *the_bytes; +struct reloc_info_generic ri; +{ + /* this is easy */ + md_number_to_chars(the_bytes, ri.r_address, sizeof (ri.r_address)); + /* now the fun stuff */ + the_bytes[6] = (ri.r_symbolnum >> 16) & 0x0ff; + the_bytes[5] = (ri.r_symbolnum >> 8) & 0x0ff; + the_bytes[4] = ri.r_symbolnum & 0x0ff; + the_bytes[7] = (((ri.r_extern << 3) & 0x08) | ((ri.r_length << 1) & 0x06) | + ((ri.r_pcrel << 0) & 0x01)) & 0x0F; +} +#endif /* comment */ + +void tc_aout_fix_to_chars(where, fixP, segment_address_in_file) +char *where; +fixS *fixP; +relax_addressT segment_address_in_file; +{ + /* + * In: length of relocation (or of address) in chars: 1, 2 or 4. + * Out: GNU LD relocation length code: 0, 1, or 2. + */ + + static unsigned char nbytes_r_length[] = { 42, 0, 1, 42, 2 }; + long r_symbolnum; + + know(fixP->fx_addsy != NULL); + + md_number_to_chars(where, + fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, + 4); + + r_symbolnum = (S_IS_DEFINED(fixP->fx_addsy) + ? S_GET_TYPE(fixP->fx_addsy) + : fixP->fx_addsy->sy_number); + + where[6] = (r_symbolnum >> 16) & 0x0ff; + where[5] = (r_symbolnum >> 8) & 0x0ff; + where[4] = r_symbolnum & 0x0ff; + where[7] = ((((!S_IS_DEFINED(fixP->fx_addsy)) << 3) & 0x08) + | ((nbytes_r_length[fixP->fx_size] << 1) & 0x06) + | (((fixP->fx_pcrel << 0) & 0x01) & 0x0f)); + + return; +} /* tc_aout_fix_to_chars() */ +/* + * 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. + */ + +static struct hash_control *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 "opcode/vax.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; /* 1 means include jXXX op-codes. */ +char *immediate, *indirect, *displen; +{ + const struct vot *vP; /* scan votstrs */ + char *retval; /* error text */ + + 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. + */ +static void 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. */ + + 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; + memset(vitP->vit_opcode, '\0', 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 = (struct vot_wot *) hash_find(op_hash, instring); + *p = c; /* Restore char after op-code. */ + if (vwP == 0) { + vitP->vit_error = "Unknown operator"; + count = 0; + memset(vitP->vit_opcode, '\0', 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; /* 1 means want synthetic opcodes. */ +char my_immediate[200]; +char my_indirect[200]; +char my_displen[200]; + +char *vip (); + +main () +{ + char *p; + char *vip_begin (); + + printf ("0 means no synthetic instructions. "); + printf ("Value for vip_begin? "); + gets (answer); + sscanf (answer, "%d", &mysynth); + printf ("Synthetic opcodes %s be included.\n", mysynth ? "will" : "will not"); + printf ("enter immediate symbols eg enter # "); + gets (my_immediate); + printf ("enter indirect symbols eg enter @ "); + gets (my_indirect); + printf ("enter displen symbols eg enter ^ "); + gets (my_displen); + if (*(p = vip_begin (mysynth, my_immediate, my_indirect, my_displen))) { + error ("vip_begin=%s", p); + } + printf ("An empty input line will quit you from the vax instruction parser\n"); + for (;;) { + printf ("vax instruction: "); + fflush (stdout); + gets (answer); + if (!*answer) { + break; /* out of for each input text loop */ + } + mybug = vip (&myvit, answer); + if (*mybug) { + printf ("BUG:\"%s\"\n", mybug); + } + if (*myvit.vit_error) { + printf ("ERR:\"%s\"\n", myvit.vit_error); + } + printf ("opcode="); + for (mycount = myvit.vit_opcode_nbytes, p = myvit.vit_opcode; + mycount; + mycount--, p++ + ) { + printf ("%02x ", *p & 0xFF); + } + printf (" operand count=%d.\n", mycount = myvit.vit_operands); + for (myvop = myvit.vit_operand; mycount; mycount--, myvop++) { + printf ("mode=%xx reg=%xx ndx=%xx len='%c'=%c%c%d. expr=\"", + myvop->vop_mode, myvop->vop_reg, myvop->vop_ndx, + myvop->vop_short, myvop->vop_access, myvop->vop_width, + myvop->vop_nbytes); + for (p = myvop->vop_expr_begin; p <= myvop->vop_expr_end; p++) { + putchar (*p); + } + printf ("\"\n"); + if (*myvop->vop_error) { + printf (" err:\"%s\"\n", myvop->vop_error); + } + if (*myvop->vop_warn) { + printf (" wrn:\"%s\"\n", myvop->vop_warn); + } + } + } + vip_end (); + exit (); +} + +#endif /* #ifdef test */ + +/* end of vax_ins_parse.c */ + +/* JF this used to be a separate file also */ +/* vax_reg_parse.c - convert a VAX register name to a number */ + +/* Copyright (C) 1987 Free Software Foundation, Inc. A part of GNU. */ + +/* + * v a x _ r e g _ p a r s e ( ) + * + * Take 3 char.s, the last of which may be `\0` (non-existent) + * and return the VAX register number that they represent. + * + * Return -1 if they don't form a register name. Good names return + * a number from 0:15 inclusive. + * + * Case is not important in a name. + * + * Register names understood are: + * + * R0 + * R1 + * R2 + * R3 + * R4 + * R5 + * R6 + * R7 + * R8 + * R9 + * R10 + * R11 + * R12 AP + * R13 FP + * R14 SP + * R15 PC + * + */ + +#include <ctype.h> +#define AP (12) +#define FP (13) +#define SP (14) +#define PC (15) + +int /* return -1 or 0:15 */ + vax_reg_parse (c1, c2, c3) /* 3 chars of register name */ +char c1, c2, c3; /* c3 == 0 if 2-character reg name */ +{ + register int retval; /* return -1:15 */ + + retval = -1; + + if (isupper (c1)) + c1 = tolower (c1); + if (isupper (c2)) + c2 = tolower (c2); + if (isdigit (c2) && c1 == 'r') { + retval = c2 - '0'; + if (isdigit (c3)) { + retval = retval * 10 + c3 - '0'; + retval = (retval > 15) ? -1 : retval; + /* clamp the register value to 1 hex digit */ + } else if (c3) + retval = -1; /* c3 must be '\0' or a digit */ + } else if (c3) /* There are no three letter regs */ + retval = -1; + else if (c2 == 'p') { + switch (c1) { + case 's': + retval = SP; + break; + case 'f': + retval = FP; + break; + case 'a': + retval = AP; + break; + default: + retval = -1; + } + } else if (c1 == 'p' && c2 == 'c') + retval = PC; + else + retval = -1; + return (retval); +} + +/* + * v i p _ o p ( ) + * + * Parse a vax operand in DEC assembler notation. + * For speed, expect a string of whitespace to be reduced to a single ' '. + * This is the case for GNU AS, and is easy for other DEC-compatible + * assemblers. + * + * Knowledge about DEC VAX assembler operand notation lives here. + * This doesn't even know what a register name is, except it believes + * all register names are 2 or 3 characters, and lets vax_reg_parse() say + * what number each name represents. + * It does, however, know that PC, SP etc are special registers so it can + * detect addressing modes that are silly for those registers. + * + * Where possible, it delivers 1 fatal or 1 warning message if the operand + * is suspect. Exactly what we test for is still evolving. + */ + +/* + * B u g s + * + * Arg block. + * + * There were a number of 'mismatched argument type' bugs to vip_op. + * The most general solution is to typedef each (of many) arguments. + * We used instead a typedef'd argument block. This is less modular + * than using seperate return pointers for each result, but runs faster + * on most engines, and seems to keep programmers happy. It will have + * to be done properly if we ever want to use vip_op as a general-purpose + * module (it was designed to be). + * + * G^ + * + * Doesn't support DEC "G^" format operands. These always take 5 bytes + * to express, and code as modes 8F or 9F. Reason: "G^" deprives you of + * optimising to (say) a "B^" if you are lucky in the way you link. + * When someone builds a linker smart enough to convert "G^" to "B^", "W^" + * whenever possible, then we should implement it. + * If there is some other use for "G^", feel free to code it in! + * + * + * speed + * + * If I nested if ()s more, I could avoid testing (*err) which would save + * time, space and page faults. I didn't nest all those if ()s for clarity + * and because I think the mode testing can be re-arranged 1st to test the + * commoner constructs 1st. Does anybody have statistics on this? + * + * + * + * error messages + * + * In future, we should be able to 'compose' error messages in a scratch area + * and give the user MUCH more informative error messages. Although this takes + * a little more code at run-time, it will make this module much more self- + * documenting. As an example of what sucks now: most error messages have + * hardwired into them the DEC VAX metacharacters "#^@" which are nothing like + * the Un*x characters "$`*", that most users will expect from this AS. + */ + +/* + * 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) */ + +/* + * 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 + +static void vip_op_defaults(immediate, indirect, displen) /* can be called any time */ +char *immediate; /* Strings of characters for each job. */ +char *indirect; +char *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); + + return; +} +#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 1 if leading '@' (or Un*x '*') + * len takes one value from " bilsw". eg B^ -> 'b'. + * hash 1 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 1 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; /* 1 if leading '@' ('*') seen */ + char len; /* one of " bilsw" */ + int hash; /* 1 if leading '#' ('$') seen */ + int sign = 0; /* -1, 0 or +1 */ + int paren = 0; /* 1 if () surround register */ + int reg = 0; /* register number, -1:absent */ + int ndx = 0; /* 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 = NULL; /* preserve q in case we backup */ + int mode = 0; /* 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)) { /* 1 if *p == '@'(or '*' for Un*x) */ + p++; /* at is determined */ + if (*p == ' ') /* Expect all whitespace reduced to ' '. */ + p++; /* skip over whitespace */ + } + + /* + * This code is subtle. It tries to detect all legal (letter)'^' + * but it doesn't waste time explicitly testing for premature '\0' because + * this case is rejected as a mismatch against either (letter) or '^'. + */ + { + register char c; + + c = *p; + if (isupper (c)) + c = tolower (c); + if (DISPLENP (p[1]) && strchr ("bilws", len = c)) + p += 2; /* skip (letter) '^' */ + else /* no (letter) '^' seen */ + len = ' '; /* len is determined */ + } + + if (*p == ' ') /* Expect all whitespace reduced to ' '. */ + p++; /* skip over whitespace */ + + if (hash = IMMEDIATEP (*p)) /* 1 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<p or we got matching '[' */ + if (q < p) + err = "no '[' to match ']'"; + else { + /* + * Confusers like "[]" will eventually lose with a bad register + * name error. So again we don't need to check for early '\0'. + */ + if (q[3] == ']') + ndx = vax_reg_parse (q[1], q[2], 0); + else if (q[4] == ']') + ndx = vax_reg_parse (q[1], q[2], q[3]); + else + ndx = -1; + /* + * Since we saw a ']' we will demand a register name in the []. + * If luser hasn't given us one: be rude. + */ + if (ndx < 0) + err = "bad register in []"; + else if (ndx == PC) + err = "[PC] index banned"; + else + q--; /* point q just before "[...]" */ + } + } else + ndx = -1; /* no ']', so no iNDeX register */ + + /* + * If err = "..." then we lost: run away. + * Otherwise ndx == -1 if there was no "[...]". + * Otherwise, ndx is index register number, and q points before "[...]". + */ + + 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 = 1; /* assume we have "(...)" */ + while (q >= p && *q != '(') + q--; + /* either q<p or we got matching '(' */ + if (q < p) + err = "no '(' to match ')'"; + else { + /* + * Confusers like "()" will eventually lose with a bad register + * name error. So again we don't need to check for early '\0'. + */ + if (q[3] == ')') + reg = vax_reg_parse (q[1], q[2], 0); + else if (q[4] == ')') + reg = vax_reg_parse (q[1], q[2], q[3]); + else + reg = -1; + /* + * Since we saw a ')' we will demand a register name in the ')'. + * This is nasty: why can't our hypothetical assembler permit + * parenthesised expressions? BECAUSE I AM LAZY! That is why. + * Abuse luser if we didn't spy a register name. + */ + if (reg < 0) { + /* JF allow parenthasized expressions. I hope this works */ + paren = 0; + 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 == 1 and reg = register in "()". + */ + } else + paren = 0; + /* + * If err == "..." then we lost. + * Otherwise, q points just before "(Rn)", if any. + * If there was a "(...)" then paren == 1, and reg is the register. + */ + + /* + * We should only seek '-' of "-(...)" if: + * we saw "(...)" paren == 1 + * 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 0 + * len 's' definition + * hash 1 demand + * p:q demand not empty + * sign 0 by paren == 0 + * paren 0 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 0 + * len ' + * hash 0 + * p:q q<p + * sign -1 by definition + * paren 1 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 = 1; + paren = 0; + } + + /* + * Case of (Rn)+, which is slightly different. + * + * in: at + * len ' ' + * hash 0 + * p:q q<p + * sign +1 by definition + * paren 1 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 1 by definition + * p:q + * sign 0 + * paren 0 + * 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 == 0 + */ + + /* + * Case of Rn. We seperate this one because it has a few special + * errors the remaining modes lack. + * + * in: at optional + * len ' ' + * hash 0 by program logic + * p:q empty + * sign 0 by program logic + * paren 0 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 == 0 + * paren == 1 OR reg == -1 + */ + + /* + * Rest of cases fit into one bunch. + * + * in: at optional + * len ' ' or 'b' or 'w' or 'l' + * hash 0 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 <stdio.h> + +char answer[100]; /* human types into here */ +char *p; /* */ +char *myerr; +char *mywrn; +char *mybug; +char myaccess; +char mywidth; +char mymode; +char myreg; +char mylen; +char *myleft; +char *myright; +char myndx; +int my_operand_length; +char my_immediate[200]; +char my_indirect[200]; +char my_displen[200]; + +main () +{ + char *vip_op (); /* make cc happy */ + + printf ("enter immediate symbols eg enter # "); + gets (my_immediate); + printf ("enter indirect symbols eg enter @ "); + gets (my_indirect); + printf ("enter displen symbols eg enter ^ "); + gets (my_displen); + vip_op_defaults (my_immediate, my_indirect, my_displen); + for (;;) { + printf ("access,width (eg 'ab' or 'wh') [empty line to quit] : "); + fflush (stdout); + gets (answer); + if (!answer[0]) + exit (0); + myaccess = answer[0]; + mywidth = answer[1]; + switch (mywidth) { + case 'b': + my_operand_length = 1; + break; + case 'd': + my_operand_length = 8; + break; + case 'f': + my_operand_length = 4; + break; + case 'g': + my_operand_length = 16; + break; + case 'h': + my_operand_length = 32; + break; + case 'l': + my_operand_length = 4; + break; + case 'o': + my_operand_length = 16; + break; + case 'q': + my_operand_length = 8; + break; + case 'w': + my_operand_length = 2; + break; + case '!': + case '?': + case '-': + my_operand_length = 0; + break; + + default: + my_operand_length = 2; + printf ("I dn't understand access width %c\n", mywidth); + break; + } + printf ("VAX assembler instruction operand: "); + fflush (stdout); + gets (answer); + mybug = vip_op (answer, myaccess, mywidth, my_operand_length, + &mymode, &myreg, &mylen, &myleft, &myright, &myndx, + &myerr, &mywrn); + if (*myerr) { + printf ("error: \"%s\"\n", myerr); + if (*mybug) + printf (" bug: \"%s\"\n", mybug); + } else { + if (*mywrn) + printf ("warning: \"%s\"\n", mywrn); + mumble ("mode", mymode); + mumble ("register", myreg); + mumble ("index", myndx); + printf ("width:'%c' ", mylen); + printf ("expression: \""); + while (myleft <= myright) + putchar (*myleft++); + printf ("\"\n"); + } + } +} + +mumble (text, value) +char *text; +int value; +{ + printf ("%s:", text); + if (value >= 0) + printf ("%xx", value); + else + printf ("ABSENT"); + printf (" "); +} + +#endif /* ifdef TEST */ + +/* end: vip_op.c */ + +const int md_short_jump_size = 3; +const int md_long_jump_size = 6; +const int md_reloc_size = 8; /* Size of relocation record */ + +void + md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) +char *ptr; +long from_addr, to_addr; +fragS *frag; +symbolS *to_symbol; +{ + long offset; + + offset = to_addr - (from_addr + 1); + *ptr++ = 0x31; + md_number_to_chars(ptr, offset, 2); +} + +void + md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) +char *ptr; +long from_addr, to_addr; +fragS *frag; +symbolS *to_symbol; +{ + long offset; + + offset = to_addr - S_GET_VALUE(to_symbol); + *ptr++ = 0x17; + *ptr++ = 0x9F; + md_number_to_chars(ptr, offset, 4); + fix_new(frag, ptr - frag->fr_literal, 4, to_symbol, (symbolS *) 0, (long) 0, 0, NO_RELOC); +} + +#ifdef OBJ_VMS +extern char vms_name_mapping; +#endif + +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 OBJ_VMS + case '+': /* For g++ */ + break; + + case '1': /* For backward compatibility */ + break; + + case 'h': /* No hashing of mixed-case names */ + vms_name_mapping = 0; + (*argP)++; + if (**argP) vms_name_mapping = *((*argP)++) - '0'; + (*argP)--; + break; + + case 'H': /* Show new symbol after hash truncation */ + break; +#endif + + default: + return 0; + + } + return 1; +} + +/* We have no need to default values of symbols. */ + +/* ARGSUSED */ +symbolS * + md_undefined_symbol (name) +char *name; +{ + return 0; +} + +/* Parse an operand that is machine-specific. + We just return without modifying the expression if we have nothing + to do. */ + +/* ARGSUSED */ +void + md_operand (expressionP) +expressionS *expressionP; +{ +} + +/* Round up a section size to the appropriate boundary. */ +long + md_section_align (segment, size) +segT segment; +long size; +{ + return size; /* Byte alignment is fine */ +} + +/* Exactly what point is a PC-relative offset relative TO? + On the vax, they're relative to the address of the offset, plus + its size. (??? Is this right? FIXME-SOON) */ +long + md_pcrel_from (fixP) +fixS *fixP; +{ + return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; +} + +/* end of tc-vax.c */ diff --git a/gnu/usr.bin/as/config/tc-vax.h b/gnu/usr.bin/as/config/tc-vax.h new file mode 100644 index 000000000000..d3972e10a0e0 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-vax.h @@ -0,0 +1,25 @@ +/* + * This file is tc-vax.h. + */ + +#define TC_VAX 1 + +#define NO_LISTING + + /* use this to compare against gas-1.38 */ +#ifdef OLD_GAS +#define REVERSE_SORT_RELOCS +#endif + +#define tc_aout_pre_write_hook(x) {;} /* not used */ +#define tc_crawl_symbol_chain(a) {;} /* not used */ +#define tc_headers_hook(a) {;} /* not used */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of tc-vax.h */ diff --git a/gnu/usr.bin/as/config/te-dpx2.h b/gnu/usr.bin/as/config/te-dpx2.h new file mode 100644 index 000000000000..5f358a2bfd29 --- /dev/null +++ b/gnu/usr.bin/as/config/te-dpx2.h @@ -0,0 +1,8 @@ +/* Machine specific defines for the dpx2 machine */ +#define dpx2 +#define TC_M68K + +/* The magic number is not the usual MC68MAGIC. */ +#define FILE_HEADER_MAGIC MC68KBCSMAGIC + +/* end of te-dpx2.h */ diff --git a/gnu/usr.bin/as/config/te-generic.h b/gnu/usr.bin/as/config/te-generic.h new file mode 100644 index 000000000000..8bf93bf4ad39 --- /dev/null +++ b/gnu/usr.bin/as/config/te-generic.h @@ -0,0 +1,25 @@ +/* + * This file is te-generic.h and is intended to be a template for + * target environment specific header files. + * + * It is my intent that this file will evolve into a file suitable for config, + * compile, and copying as an aid for testing and porting. xoxorich. + */ +/* + * $Id: te-generic.h,v 1.1 1993/11/03 00:55:03 paul Exp $ + */ + + +#define TE_GENERIC 1 + +/* these define interfaces */ +#include "obj-format.h" + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of te-generic.h */ diff --git a/gnu/usr.bin/as/config/te-hpux.h b/gnu/usr.bin/as/config/te-hpux.h new file mode 100644 index 000000000000..5458df69862b --- /dev/null +++ b/gnu/usr.bin/as/config/te-hpux.h @@ -0,0 +1,99 @@ +/* Special version of <a.out.h> for use under hp-ux. + Copyright (C) 1988, 1992 Free Software Foundation, Inc. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR 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 file; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define TE_HPUX + +#define HP9000S200_ID (0x20C) +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (HP9000S200_ID) + + /* hpux has "special" headers. */ +#define H_GET_HEADER_SIZE(h) (64) + +#include "obj-format.h" + +/* This stuff is from an old a.out.hpux.h. It isn't used anymore, + (see obj-aout.c, obj_header_append) but I'm including it here for + context. xoxorich. */ + +#if comment + +/* The `exec' structure and overall layout must be close to HP's when + we are running on an HP system, otherwise we will not be able to + execute the resulting file. */ + +/* Allow this file to be included twice. */ +#ifndef __GNU_EXEC_MACROS__ + +struct exec +{ + unsigned short a_machtype; /* machine type */ + unsigned short a_info; /* magic number */ + unsigned long a_spare1; + unsigned long a_spare2; + unsigned long a_text; /* length of text, in bytes */ + unsigned long a_data; /* length of data, in bytes */ + unsigned long a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned long a_trsize; /* length of relocation info for text, in bytes */ + unsigned long a_drsize; /* length of relocation info for data, in bytes */ + unsigned long a_spare3; /* HP = pascal interface size */ + unsigned long a_spare4; /* HP = symbol table size */ + unsigned long a_spare5; /* HP = debug name table size */ + unsigned long a_entry; /* start address */ + unsigned long a_spare6; /* HP = source line table size */ + unsigned long a_spare7; /* HP = value table size */ + unsigned long a_syms; /* length of symbol table data in file, in bytes */ + unsigned long a_spare8; +}; + +/* Tell a.out.gnu.h not to define `struct exec'. */ +#define __STRUCT_EXEC_OVERRIDE__ + +#include "a.out.gnu.h" + +#undef N_MAGIC +#undef N_MACHTYPE +#undef N_FLAGS +#undef N_SET_INFO +#undef N_SET_MAGIC +#undef N_SET_MACHTYPE +#undef N_SET_FLAGS + +#define N_MAGIC(exec) ((exec) . a_magic) +#define N_MACHTYPE(exec) ((exec) . a_machtype) +#define N_SET_MAGIC(exec, magic) (((exec) . a_magic) = (magic)) +#define N_SET_MACHTYPE(exec, machtype) (((exec) . a_machtype) = (machtype)) + +#undef N_BADMAG +#define N_BADMAG(x) ((_N_BADMAG (x)) || (_N_BADMACH (x))) + +#define _N_BADMACH(x) \ +(((N_MACHTYPE (x)) != HP9000S200_ID) && \ + ((N_MACHTYPE (x)) != HP98x6_ID)) + +#define HP98x6_ID 0x20A +#define HP9000S200_ID 0x20C + +#undef _N_HDROFF +#define _N_HDROFF(x) (SEGMENT_SIZE - (sizeof (struct exec))) + +#define SEGMENT_SIZE 0x1000 + +#endif /* __GNU_EXEC_MACROS__ */ + +#endif /* comment */ + +/* end of te-hpux.h */ diff --git a/gnu/usr.bin/as/config/te-i386aix.h b/gnu/usr.bin/as/config/te-i386aix.h new file mode 100644 index 000000000000..dcadbc379e80 --- /dev/null +++ b/gnu/usr.bin/as/config/te-i386aix.h @@ -0,0 +1,19 @@ +/* + * This file is te-i386aix.h and is built from pieces of code from Minh Tran-Le + * <TRANLE@INTELLICORP.COM> by rich@cygnus.com. + */ + +#define TE_I386AIX 1 + +#include "obj-format.h" + +#define KEEP_RELOC_INFO + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 79 + * End: + */ + +/* end of te-i386aix.h */ diff --git a/gnu/usr.bin/as/config/te-ic960.h b/gnu/usr.bin/as/config/te-ic960.h new file mode 100644 index 000000000000..4858c7deebe2 --- /dev/null +++ b/gnu/usr.bin/as/config/te-ic960.h @@ -0,0 +1,46 @@ +/* This file is twe-ic960.h + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * This file is te-ic960.h and is intended to define ic960 environment + * specific differences. + */ + +#define TE_IC960 1 + +/* intel uses host byte order for headers */ +#ifdef CROSS_COMPILE +#undef CROSS_COMPILE +#endif /* CROSS_COMPILE */ + +#define OBJ_COFF_OMIT_OPTIONAL_HEADER +#define LOCAL_LABEL(name) ( (name[0] == 'L') \ + || (name[0] == '.' \ + && (name[1] == 'C' || name[1] == 'I' || name[1] == '.'))) +#include "obj-format.h" + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of te-ic960.h */ diff --git a/gnu/usr.bin/as/config/te-sco386.h b/gnu/usr.bin/as/config/te-sco386.h new file mode 100644 index 000000000000..da8de1da36c6 --- /dev/null +++ b/gnu/usr.bin/as/config/te-sco386.h @@ -0,0 +1,7 @@ +/* Machine specific defines for the SCO Unix V.3.2 ODT */ +#define scounix + +/* Return true if s (a non null string pointer), points to a local variable name. */ +#define LOCAL_LABEL(n) ((n)[0] == '.' && (n)[1] == 'L') + +/* end of te-sco386.h */ diff --git a/gnu/usr.bin/as/config/te-sequent.h b/gnu/usr.bin/as/config/te-sequent.h new file mode 100644 index 000000000000..fbf9d9ac8ebe --- /dev/null +++ b/gnu/usr.bin/as/config/te-sequent.h @@ -0,0 +1,32 @@ +/* + * This file is te-sequent.h and is intended to set up emulation with + * sequent's development tools. + * + */ + +#define TE_SEQUENT 1 + + /* sequent has a "special" header. */ +#define H_GET_HEADER_SIZE(h) (128) + +#ifdef TC_I386 + /* zmagic is 0x22eb */ +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (0x12eb) +#endif /* TC_I386 */ + +#ifdef TC_NS32K + /* zmagic is 0x10ea */ +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (0x00ea) +#endif /* TC_NS32K */ + +/* these define interfaces */ +#include "obj-format.h" + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of te-sequent.h */ diff --git a/gnu/usr.bin/as/config/te-sun3.h b/gnu/usr.bin/as/config/te-sun3.h new file mode 100644 index 000000000000..e559f283a9f5 --- /dev/null +++ b/gnu/usr.bin/as/config/te-sun3.h @@ -0,0 +1,49 @@ +/* te-sun3.h -- Sun-3 target environment declarations. + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 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. */ + + +/* Could also be : + #define S_LOCAL_NAME(s) (S_GET_NAME(s)[0] == '.' && + S_GET_NAME(s)[1] == 'L' || + S_GET_NAME(s)[1] == '.') + */ + +/* This variable contains the value to write out at the beginning of + the a.out file. The 2<<16 means that this is a 68020 file instead + of an old-style 68000 file */ + +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (2<<16|OMAGIC) /* Magic byte for file header */ + +#include "obj-format.h" + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of te-sun3.h */ diff --git a/gnu/usr.bin/as/config/te-sysv32.h b/gnu/usr.bin/as/config/te-sysv32.h new file mode 100644 index 000000000000..99702fb57c60 --- /dev/null +++ b/gnu/usr.bin/as/config/te-sysv32.h @@ -0,0 +1,4 @@ +/* Remove leading underscore from the gcc generated symbol names */ +#define STRIP_UNDERSCORE + +/* end of te-sysv32.h */ diff --git a/gnu/usr.bin/as/config/vax-inst.h b/gnu/usr.bin/as/config/vax-inst.h new file mode 100644 index 000000000000..1c1019142217 --- /dev/null +++ b/gnu/usr.bin/as/config/vax-inst.h @@ -0,0 +1,77 @@ +/* vax-inst.h - GNU - Part of vax.c + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * This is part of vax-ins-parse.c & friends. + * We want to parse a vax instruction text into a tree defined here. + */ + +#define VIT_MAX_OPERANDS (6) /* maximum number of operands in one */ +/* single vax instruction */ + +struct vop /* vax instruction operand */ +{ + short int vop_ndx; /* -1, or index register. eg 7=[R7] */ + short int vop_reg; /* -1, or register number. eg @I^#=0xF */ + /* Helps distinguish "abs" from "abs(PC)". */ + short int vop_mode; /* addressing mode 4 bits. eg I^#=0x9 */ + char vop_short; /* operand displacement length as written */ + /* ' '=none, "bilsw"=B^I^L^S^W^. */ + char vop_access; /* 'b'branch ' 'no-instruction 'amrvw'norm */ + char vop_width; /* Operand width, one of "bdfghloqw" */ + char *vop_warn; /* warning message of this operand, if any */ + char *vop_error; /* say if operand is inappropriate */ + char *vop_expr_begin; /* Unparsed expression, 1st char ... */ + char *vop_expr_end; /* ... last char. */ + unsigned char vop_nbytes; /* number of bytes in datum */ +}; + + +typedef long vax_opcodeT; /* For initialising array of opcodes */ +/* Some synthetic opcodes > 16 bits! */ + +#define VIT_OPCODE_SYNTHETIC 0x80000000 /* Not real hardware instruction. */ +#define VIT_OPCODE_SPECIAL 0x40000000 /* Not normal branch optimising. */ +/* Never set without ..._SYNTHETIC */ + +#define VAX_WIDTH_UNCONDITIONAL_JUMP '-' /* These are encoded into */ +#define VAX_WIDTH_CONDITIONAL_JUMP '?' /* vop_width when vop_access == 'b' */ +#define VAX_WIDTH_WORD_JUMP '!' /* and VIT_OPCODE_SYNTHETIC set. */ +#define VAX_WIDTH_BYTE_JUMP ':' /* */ + +#define VAX_JMP (0x17) /* Useful for branch optimising. Jump instr*/ +#define VAX_PC_RELATIVE_MODE (0xef) /* Use it after VAX_JMP */ +#define VAX_ABSOLUTE_MODE (0x9F) /* Use as @#... */ +#define VAX_BRB (0x11) /* Canonical branch. */ +#define VAX_BRW (0x31) /* Another canonical branch */ +#define VAX_WIDEN_WORD (0x20) /* Add this to byte branch to get word br. */ +#define VAX_WIDEN_LONG (0x6) /* Add this to byte branch to get long jmp.*/ +/* Needs VAX_PC_RELATIVE_MODE byte after it*/ + +struct vit /* vax instruction tree */ +{ + /* vit_opcode is char[] for portability. */ + char vit_opcode[ sizeof (vax_opcodeT) ]; + unsigned char vit_opcode_nbytes; /* How long is _opcode? (chars) */ + unsigned char vit_operands;/* */ + struct vop vit_operand[VIT_MAX_OPERANDS]; /* operands */ + char * vit_error; /* "" or error text */ +}; + +/* end of vax-inst.h */ diff --git a/gnu/usr.bin/as/configdos.bat b/gnu/usr.bin/as/configdos.bat new file mode 100644 index 000000000000..18331cd3da25 --- /dev/null +++ b/gnu/usr.bin/as/configdos.bat @@ -0,0 +1,14 @@ +@echo off +echo Configuring GAS for H8/300 + +copy config\ho-go32.h host.h +copy config\tc-h8300.c targ-cpu.c +copy config\tc-h8300.h targ-cpu.h +copy config\te-generic.h targ-env.h +copy config\objcoff-bfd.h obj-format.h +copy config\objcoff-bfd.c obj-format.c +copy config\atof-ieee.c atof-targ.c + +copy Makefile.dos Makefile + + diff --git a/gnu/usr.bin/as/configure.in b/gnu/usr.bin/as/configure.in new file mode 100755 index 000000000000..52f4b29f43ba --- /dev/null +++ b/gnu/usr.bin/as/configure.in @@ -0,0 +1,204 @@ +# This file is configure.in +# +# Copyright (C) 1987-1992 Free Software Foundation, Inc. +# +# This file is part of GAS, the GNU Assembler. +# +# GAS is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# GAS is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GAS; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +# + +# This file is a shell script that supplies the information necessary +# to tailor a template configure script into the configure script +# appropriate for this directory. For more information, check any +# existing configure script. + +srctrigger=as.c +srcname="gas" +need_bfd= +configdirs=doc + +# per-host: + +gas_host=generic + +case "${host_cpu}" in +a29k | rs6000 | vax) + case "${host_os}" in + vms*) gas_host=vms ;; + *) gas_host=${host_cpu} ;; + esac + ;; +mips) + case "${host_os}" in + ultrix) gas_host=decstation ;; + esac + ;; +i386) + case "${host_os}" in + aix*) gas_host=i386aix ;; + sysv4*) + gas_host=i386 + host_makefile_frag=config/ho-i386v4 + ;; + esac + ;; +*) + case "${host_os}" in + ansi | ultrix | hpux | sysv*) gas_host=${host_os} ;; + *) + case "${host_vendor}" in + sun) + case "${host_cpu}" in + m68k) gas_host=sun3 ;; + i386) gas_host=sun386 ;; + sparc) gas_host=sun4 ;; + esac + ;; + esac + ;; + esac + ;; +esac + +# per-target: + +# assign cpu type +environment=generic + +cpu_type=${target_cpu} + +# assign object format +case ${target_os} in +aix*) + case "${target_cpu}" in + i386) obj_format=coff + target_cpu=i386aix + environment=i386aix + ;; + esac + ;; + +bout*) obj_format=bout ;; +nindy*) obj_format=bout ;; +bsd* | sunos*) + obj_format=aout + case "${target_cpu}" in + m68k) environment=sun3 ;; + i386 | ns32k) + case "${target_vendor}" in + sequent) environment=${target_vendor} ;; + esac + esac + ;; + +ebmon-old) + obj_format=coff + need_bfd="$(unsubdir)/../bfd$(subdir)/libbfd.a" + target_cpu=ebmon29k + ;; + +ebmon) + obj_format=coffbfd + need_bfd="$(unsubdir)/../bfd$(subdir)/libbfd.a" + target_cpu=ebmon29k + ;; + +generic) obj_format=generic ;; + +hms) + obj_format=coffbfd + need_bfd="$(unsubdir)/../bfd$(subdir)/libbfd.a" + ;; + +hpux) + obj_format=aout + environment=hpux + ;; + +sysv32) + obj_format=coff + environment=sysv32 + ;; + +vms) + obj_format=vms + ;; + +coff* | sysv*) + obj_format=coff + + case ${target_vendor} in + bull) environment=dpx2 ;; + sco) environment=sco386 ;; + sun) environment=sun3 ;; + *) + esac + ;; +vxworks) + case ${target_cpu} in + i960) obj_format=bout ;; + *) obj_format=aout ;; + esac + ;; +*) + case ${target_vendor} in + aout) obj_format=aout ;; + bout) obj_format=bout ;; + coff) + obj_format=coff + case ${target_cpu} in + i960) environment=ic960 ;; + esac + ;; + sequent) + obj_format=aout + environment=sequent + ;; + *) obj_format=aout ;; + esac + ;; + +esac + +# assign floating point type +case ${target_cpu} in +ns32k) atof=ns32k ;; +tahoe) atof=tahoe ;; +vax) atof=vax ;; +*) atof=ieee ;; +esac + +# and target makefile frag + +target_makefile_frag=config/mt-${target_cpu} + +files="config/ho-${gas_host}.h config/tc-${cpu_type}.c \ + config/tc-${cpu_type}.h config/te-${environment}.h \ + config/obj-${obj_format}.h config/obj-${obj_format}.c \ + config/atof-${atof}.c" + +links="host.h targ-cpu.c targ-cpu.h targ-env.h obj-format.h obj-format.c atof-targ.c" + +# post-target: + +if [ ${target_alias} != ${host_alias} ] ; then + echo INTERNAL_CFLAGS=-DCROSS_COMPILE > Makefile.tem + cat Makefile >> Makefile.tem + mv Makefile.tem Makefile +else + true +fi + +# end of gas/configure.in diff --git a/gnu/usr.bin/as/debug.c b/gnu/usr.bin/as/debug.c new file mode 100644 index 000000000000..4b685334140e --- /dev/null +++ b/gnu/usr.bin/as/debug.c @@ -0,0 +1,104 @@ +/* This file is debug.c + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Routines for debug use only. */ + +#ifndef lint +static char rcsid[] = "$Id: debug.c,v 1.1 1993/11/03 00:51:26 paul Exp $"; +#endif + +#include "as.h" +#include "subsegs.h" + +dmp_frags() +{ + frchainS *chp; + char *p; + + for ( chp=frchain_root; chp; chp = chp->frch_next ){ + switch ( chp->frch_seg ){ + case SEG_DATA: + p ="Data"; + break; + case SEG_TEXT: + p ="Text"; + break; + default: + p ="???"; + break; + } + printf("\nSEGMENT %s %d\n", p, chp->frch_subseg); + dmp_frag( chp->frch_root,"\t"); + } +} + +dmp_frag( fp, indent ) + struct frag *fp; + char *indent; +{ + for ( ; fp; fp = fp->fr_next ){ + printf("%sFRAGMENT @ 0x%x\n", indent, fp); + switch( fp->fr_type ){ + case rs_align: + printf("%srs_align(%d)\n",indent, fp->fr_offset); + break; + case rs_fill: + printf("%srs_fill(%d)\n",indent, fp->fr_offset); + printf("%s", indent); + var_chars( fp, fp->fr_var + fp->fr_fix ); + printf("%s\t repeated %d times,", + indent, fp->fr_offset); + printf(" fixed length if # chars == 0)\n"); + break; + case rs_org: + printf("%srs_org(%d+sym @0x%x)\n",indent, + fp->fr_offset, fp->fr_symbol); + printf("%sfill with ",indent); + var_chars( fp, 1 ); + printf("\n"); + break; + case rs_machine_dependent: + printf("%smachine_dep\n",indent); + break; + default: + printf("%sunknown type\n",indent); + break; + } + printf("%saddr=%d(0x%x)\n",indent,fp->fr_address,fp->fr_address); + printf("%sfr_fix=%d\n",indent,fp->fr_fix); + printf("%sfr_var=%d\n",indent,fp->fr_var); + printf("%sfr_offset=%d\n",indent,fp->fr_offset); + printf("%schars @ 0x%x\n",indent,fp->fr_literal); + printf("\n"); + } +} + +var_chars( fp, n ) + struct frag *fp; + int n; +{ + unsigned char *p; + + for ( p=(unsigned char*)fp->fr_literal; n; n-- , p++ ){ + printf("%02x ", *p ); + } +} + +/* end of debug.c */ diff --git a/gnu/usr.bin/as/doc/Makefile b/gnu/usr.bin/as/doc/Makefile new file mode 100644 index 000000000000..f2c319f382a5 --- /dev/null +++ b/gnu/usr.bin/as/doc/Makefile @@ -0,0 +1,187 @@ +# This file was generated automatically by configure. Do not edit. +host_alias = i386 +host_cpu = i386 +host_vendor = unknown +host_os = scosysv322 +target_alias = i386 +target_cpu = i386 +target_vendor = unknown +target_os = scosysv322 +target_makefile_frag = +host_makefile_frag = +site_makefile_frag = +links = +VPATH = . +ALL=all.internal +# Makefile for GNU Assembler documentation +# - see pretex.m4 for discussion of preprocessor definitions +# Copyright (C) 1987-1992 Free Software Foundation, Inc. + +#This file is part of GNU GAS. + +#GNU GAS is free software; you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation; either version 2, or (at your option) +#any later version. + +#GNU GAS is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with GNU GAS; see the file COPYING. If not, write to +#the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# The targets for external use include: +# all, doc, proto, install, uninstall, includes, TAGS, +# clean, cleanconfig, realclean, stage1, stage2, stage3, stage4. + +# Variables that exist for you to override. +# See below for how to change them for certain systems. + +srcdir = . + +prefix = /usr/local + +bindir = $(prefix)/bin +datadir = $(prefix)/lib +libdir = $(prefix)/lib +mandir = $(datadir)/man +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = $(datadir)/info +includedir = $(prefix)/include +docdir = $(datadir)/doc + +SHELL = /bin/sh + +INSTALL = install -c +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = $(INSTALL) + +AR = ar +AR_FLAGS = qv +BISON = bison +MAKEINFO = makeinfo +RANLIB = ranlib + +# What version of the manual you want (see *.m4); "all" includes everything +CONFIG=all + +# Sun/Berkeley m4 doesn't have all the things we need; use GNU or sV +M4=gm4 +#M4=/usr/5bin/m4 + +# Directory for gas source +srcdir = . + +# Where to find texinfo.tex to format docn with TeX +TEXIDIR = $(srcdir)/../texinfo/fsf + +#### host, target, and site specific Makefile frags come in here. +## + +all: +clean: +install: + $(INSTALL_DATA) $(srcdir)/as.1 $(man1dir)/as.1 + +info: as.info + +as.info: as-${CONFIG}.texinfo + makeinfo -o as.info as-${CONFIG}.texinfo + +install-info: as.info + [ -d $(infodir) ] || mkdir $(infodir) + for i in as.info* ; do \ + $(INSTALL_DATA) $$i $(infodir)/$$i ; \ + done + +as.dvi: as-${CONFIG}.texinfo + TEXINPUTS=${TEXIDIR}:.:$$TEXINPUTS tex as-${CONFIG}.texinfo + texindex as-${CONFIG}.?? + TEXINPUTS=${TEXIDIR}:.:$$TEXINPUTS tex as-${CONFIG}.texinfo + mv as-${CONFIG}.dvi as.dvi + rm as-${CONFIG}.?? as-${CONFIG}.??? + +# ROFF doc targets as.ms, as.mm, as.me +# (we don't use a variable because we don't trust all makes to handle +# a var in the target name right). +# roff output (-ms) +as.ms: as-${CONFIG}.texinfo + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e 's/{.*,,/{/' \ + as-${CONFIG}.texinfo | \ + texi2roff -ms >as.ms + +# roff output (-mm) +as.mm: as-${CONFIG}.texinfo + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e 's/{.*,,/{/' \ + -e '/@noindent/d' \ + as-${CONFIG}.texinfo | \ + texi2roff -mm | \ + sed -e 's/---/\\(em/g' \ + >as.mm + +# roff output (-me) +as.me: as-${CONFIG}.texinfo + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e 's/{.*,,/{/' \ + as-${CONFIG}.texinfo | \ + texi2roff -me >as.me + + + +as-all.texinfo: as.texinfo pretex.m4 none.m4 all.m4 + ${M4} $(srcdir)/pretex.m4 $(srcdir)/none.m4 $(srcdir)/all.m4 $(srcdir)/as.texinfo >as-all.texinfo + +as-a29k.texinfo: as.texinfo pretex.m4 none.m4 a29k.m4 + ${M4} pretex.m4 none.m4 a29k.m4 as.texinfo >as-a29k.texinfo + +as-a29k-coff.texinfo: as.texinfo pretex.m4 none.m4 a29k-coff.m4 + ${M4} pretex.m4 none.m4 a29k-coff.m4 as.texinfo >as-a29k-coff.texinfo + +as-gen.texinfo: as.texinfo pretex.m4 none.m4 gen.m4 + ${M4} pretex.m4 none.m4 gen.m4 as.texinfo >as-gen.texinfo + +as-h8.texinfo: as.texinfo pretex.m4 none.m4 h8.m4 + ${M4} pretex.m4 none.m4 h8.m4 as.texinfo >as-h8.texinfo + +as-i80386.texinfo: as.texinfo pretex.m4 none.m4 i80386.m4 + ${M4} pretex.m4 none.m4 i80386.m4 as.texinfo >as-i80386.texinfo + +as-i960.texinfo: as.texinfo pretex.m4 none.m4 i960.m4 + ${M4} pretex.m4 none.m4 i960.m4 as.texinfo >as-i960.texinfo + +as-m680x0.texinfo: as.texinfo pretex.m4 none.m4 m680x0.m4 + ${M4} pretex.m4 none.m4 m680x0.m4 as.texinfo >as-m680x0.texinfo + +as-sparc.texinfo: as.texinfo pretex.m4 none.m4 sparc.m4 + ${M4} pretex.m4 none.m4 sparc.m4 as.texinfo >as-sparc.texinfo + +as-vax.texinfo: as.texinfo pretex.m4 none.m4 vax.m4 + ${M4} pretex.m4 none.m4 vax.m4 as.texinfo >as-vax.texinfo + +as-vintage.texinfo: as.texinfo pretex.m4 none.m4 vintage.m4 + ${M4} pretex.m4 none.m4 vintage.m4 as.texinfo >as-vintage.texinfo + +clean-info: + rm -f as-${CONFIG}.* as.dvi as.info* + +force: + +Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag) + $(SHELL) ./config.status + diff --git a/gnu/usr.bin/as/doc/Makefile.in b/gnu/usr.bin/as/doc/Makefile.in new file mode 100644 index 000000000000..fdae0b28f40d --- /dev/null +++ b/gnu/usr.bin/as/doc/Makefile.in @@ -0,0 +1,172 @@ +# Makefile for GNU Assembler documentation +# - see pretex.m4 for discussion of preprocessor definitions +# Copyright (C) 1987-1992 Free Software Foundation, Inc. + +#This file is part of GNU GAS. + +#GNU GAS is free software; you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation; either version 2, or (at your option) +#any later version. + +#GNU GAS is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with GNU GAS; see the file COPYING. If not, write to +#the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# The targets for external use include: +# all, doc, proto, install, uninstall, includes, TAGS, +# clean, cleanconfig, realclean, stage1, stage2, stage3, stage4. + +# Variables that exist for you to override. +# See below for how to change them for certain systems. + +srcdir = . + +prefix = /usr/local + +bindir = $(prefix)/bin +datadir = $(prefix)/lib +libdir = $(prefix)/lib +mandir = $(datadir)/man +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = $(datadir)/info +includedir = $(prefix)/include +docdir = $(datadir)/doc + +SHELL = /bin/sh + +INSTALL = install -c +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = $(INSTALL) + +AR = ar +AR_FLAGS = qv +BISON = bison +MAKEINFO = makeinfo +RANLIB = ranlib + +# What version of the manual you want (see *.m4); "all" includes everything +CONFIG=all + +# Sun/Berkeley m4 doesn't have all the things we need; use GNU or sV +M4=gm4 +#M4=/usr/5bin/m4 + +# Directory for gas source +srcdir=.. + +# Where to find texinfo.tex to format docn with TeX +TEXIDIR = $(srcdir)/../texinfo/fsf + +#### host, target, and site specific Makefile frags come in here. +## + +all: +clean: +install: + $(INSTALL_DATA) $(srcdir)/as.1 $(man1dir)/as.1 + +info: as.info + +as.info: as-${CONFIG}.texinfo + makeinfo -o as.info as-${CONFIG}.texinfo + +install-info: as.info + [ -d $(infodir) ] || mkdir $(infodir) + for i in as.info* ; do \ + $(INSTALL_DATA) $$i $(infodir)/$$i ; \ + done + +as.dvi: as-${CONFIG}.texinfo + TEXINPUTS=${TEXIDIR}:.:$$TEXINPUTS tex as-${CONFIG}.texinfo + texindex as-${CONFIG}.?? + TEXINPUTS=${TEXIDIR}:.:$$TEXINPUTS tex as-${CONFIG}.texinfo + mv as-${CONFIG}.dvi as.dvi + rm as-${CONFIG}.?? as-${CONFIG}.??? + +# ROFF doc targets as.ms, as.mm, as.me +# (we don't use a variable because we don't trust all makes to handle +# a var in the target name right). +# roff output (-ms) +as.ms: as-${CONFIG}.texinfo + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e 's/{.*,,/{/' \ + as-${CONFIG}.texinfo | \ + texi2roff -ms >as.ms + +# roff output (-mm) +as.mm: as-${CONFIG}.texinfo + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e 's/{.*,,/{/' \ + -e '/@noindent/d' \ + as-${CONFIG}.texinfo | \ + texi2roff -mm | \ + sed -e 's/---/\\(em/g' \ + >as.mm + +# roff output (-me) +as.me: as-${CONFIG}.texinfo + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e 's/{.*,,/{/' \ + as-${CONFIG}.texinfo | \ + texi2roff -me >as.me + + + +as-all.texinfo: as.texinfo pretex.m4 none.m4 all.m4 + ${M4} $(srcdir)/pretex.m4 $(srcdir)/none.m4 $(srcdir)/all.m4 $(srcdir)/as.texinfo >as-all.texinfo + +as-a29k.texinfo: as.texinfo pretex.m4 none.m4 a29k.m4 + ${M4} pretex.m4 none.m4 a29k.m4 as.texinfo >as-a29k.texinfo + +as-a29k-coff.texinfo: as.texinfo pretex.m4 none.m4 a29k-coff.m4 + ${M4} pretex.m4 none.m4 a29k-coff.m4 as.texinfo >as-a29k-coff.texinfo + +as-gen.texinfo: as.texinfo pretex.m4 none.m4 gen.m4 + ${M4} pretex.m4 none.m4 gen.m4 as.texinfo >as-gen.texinfo + +as-h8.texinfo: as.texinfo pretex.m4 none.m4 h8.m4 + ${M4} pretex.m4 none.m4 h8.m4 as.texinfo >as-h8.texinfo + +as-i80386.texinfo: as.texinfo pretex.m4 none.m4 i80386.m4 + ${M4} pretex.m4 none.m4 i80386.m4 as.texinfo >as-i80386.texinfo + +as-i960.texinfo: as.texinfo pretex.m4 none.m4 i960.m4 + ${M4} pretex.m4 none.m4 i960.m4 as.texinfo >as-i960.texinfo + +as-m680x0.texinfo: as.texinfo pretex.m4 none.m4 m680x0.m4 + ${M4} pretex.m4 none.m4 m680x0.m4 as.texinfo >as-m680x0.texinfo + +as-sparc.texinfo: as.texinfo pretex.m4 none.m4 sparc.m4 + ${M4} pretex.m4 none.m4 sparc.m4 as.texinfo >as-sparc.texinfo + +as-vax.texinfo: as.texinfo pretex.m4 none.m4 vax.m4 + ${M4} pretex.m4 none.m4 vax.m4 as.texinfo >as-vax.texinfo + +as-vintage.texinfo: as.texinfo pretex.m4 none.m4 vintage.m4 + ${M4} pretex.m4 none.m4 vintage.m4 as.texinfo >as-vintage.texinfo + +clean-info: + rm -f as-${CONFIG}.* as.dvi as.info* + +force: + +Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag) + $(SHELL) ./config.status + diff --git a/gnu/usr.bin/as/doc/a29k-coff.m4 b/gnu/usr.bin/as/doc/a29k-coff.m4 new file mode 100644 index 000000000000..c3b04e1e1346 --- /dev/null +++ b/gnu/usr.bin/as/doc/a29k-coff.m4 @@ -0,0 +1,14 @@ +_divert__(-1) +_define__(<_A29K__>,<1>) +_define__(<_GENERIC__>,<0>) +_define__(<_HOST__>,<AMD 29K>) +_define__(<_MACH_DEP__>,<AMD29K-Dependent>) +_define__(<_AOUT__>,<0>) +_define__(<_BOUT__>,<0>) +_define__(<_COFF__>,<1>) +_define__(<_ELF__>,<0>) +_define__(<_DIFFTABKLUG__>,0) NO difference-table kluge +_define__(<_IEEEFLOAT__>,1) IEEE floating point +_define__(<_W32__>,1) 32-bit words +_define__(<_W16__>,0) +_divert__<> diff --git a/gnu/usr.bin/as/doc/a29k.m4 b/gnu/usr.bin/as/doc/a29k.m4 new file mode 100644 index 000000000000..95643875774e --- /dev/null +++ b/gnu/usr.bin/as/doc/a29k.m4 @@ -0,0 +1,9 @@ +_divert__(-1) +_define__(<_A29K__>,<1>) +_define__(<_HOST__>,<AMD 29K>) +_define__(<_MACH_DEP__>,<AMD29K-Dependent>) +_define__(<_DIFFTABKLUG__>,0) NO difference-table kluge +_define__(<_IEEEFLOAT__>,1) IEEE floating point +_define__(<_W32__>,1) 32-bit words +_define__(<_W16__>,0) +_divert__<> diff --git a/gnu/usr.bin/as/doc/all.m4 b/gnu/usr.bin/as/doc/all.m4 new file mode 100644 index 000000000000..bcde65a1454c --- /dev/null +++ b/gnu/usr.bin/as/doc/all.m4 @@ -0,0 +1,20 @@ +_divert__(-1) +<$Id: all.m4,v 1.1 1993/11/03 00:55:21 paul Exp $> +_define__(<_ALL_ARCH__>,<1>) +_define__(<_GENERIC__>,<1>) In case none.m4 changes its mind abt default + +_define__(<_AOUT__>,<1>) +_define__(<_BOUT__>,<1>) +_define__(<_COFF__>,<1>) +_define__(<_ELF__>,<1>) + +_define__(<_A29K__>,<1>) +_define__(<_H8__>,<1>) +_define__(<_I80386__>,<1>) +_define__(<_I960__>,<1>) +_define__(<_M680X0__>,<1>) +_define__(<_SPARC__>,<1>) +_define__(<_VAX__>,<1>) +_define__(<_VXWORKS__>,<1>) + +_divert__<> diff --git a/gnu/usr.bin/as/doc/as.texinfo b/gnu/usr.bin/as/doc/as.texinfo new file mode 100644 index 000000000000..cc978f69515e --- /dev/null +++ b/gnu/usr.bin/as/doc/as.texinfo @@ -0,0 +1,6730 @@ +_dnl__ -*-Texinfo-*- +_dnl__ Copyright (c) 1991 1992 Free Software Foundation, Inc. +_dnl__ $Id: as.texinfo,v 1.1 1993/11/03 00:55:23 paul Exp $ +\input texinfo @c -*-Texinfo-*- +@c Copyright (c) 1991 1992 Free Software Foundation, Inc. +@c %**start of header +@setfilename _AS__.info +_if__(_GENERIC__) +@settitle Using _AS__ +_fi__(_GENERIC__) +_if__(!_GENERIC__) +@settitle Using _AS__ (_HOST__) +_fi__(!_GENERIC__) +@setchapternewpage odd +@c @smallbook +@c @cropmarks +@c %**end of header + +@finalout +@syncodeindex ky cp + +_if__(0) + +NOTE: this manual is marked up for preprocessing with a collection +of m4 macros called "pretex.m4". + +THIS IS THE FULL SOURCE. The full source needs to be run through m4 +before either tex- or info- formatting: for example, + m4 pretex.m4 none.m4 m680x0.m4 as.texinfo >as-680x0.texinfo +will produce (assuming your path finds either GNU or SysV m4; Berkeley +won't do) a file, configured for the M680x0 version of GAS, suitable for +formatting. See the text in "pretex.m4" for a fuller explanation (and +the macro definitions). + +_fi__(0) +@c +@ifinfo +This file documents the GNU Assembler "_AS__". + +Copyright (C) 1991 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +section entitled ``GNU General Public License'' is included exactly as +in the original, and provided that the entire resulting derived work is +distributed under the terms of a permission notice identical to this +one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that the section entitled ``GNU General Public License'' may be +included in a translation approved by the Free Software Foundation +instead of in the original English. +@end ifinfo + +@titlepage +@title Using _AS__ +@subtitle The GNU Assembler +_if__(!_GENERIC__) +@subtitle for the _HOST__ family +_fi__(!_GENERIC__) +@sp 1 +@subtitle January 1992 +@sp 1 +@sp 13 +The Free Software Foundation Inc. thanks The Nice Computer +Company of Australia for loaning Dean Elsner to write the +first (Vax) version of @code{as} for Project GNU. +The proprietors, management and staff of TNCCA thank FSF for +distracting the boss while they got some work +done. +@sp 3 +@author Dean Elsner, Jay Fenlason & friends +@c edited by: pesch@cygnus.com +@page +@tex +\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$ +\xdef\manvers{\$Revision: 1.1 $} % For use in headers, footers too +{\parskip=0pt +\hfill \manvers\par +\hfill \TeX{}info \texinfoversion\par +} +%"boxit" macro for figures: +%Modified from Knuth's ``boxit'' macro from TeXbook (answer to exercise 21.3) +\gdef\boxit#1#2{\vbox{\hrule\hbox{\vrule\kern3pt + \vbox{\parindent=0pt\parskip=0pt\hsize=#1\kern3pt\strut\hfil +#2\hfil\strut\kern3pt}\kern3pt\vrule}\hrule}}%box with visible outline +\gdef\ibox#1#2{\hbox to #1{#2\hfil}\kern8pt}% invisible box +@end tex + +Edited by Roland Pesch for Cygnus Support. + +@vskip 0pt plus 1filll +Copyright @copyright{} 1991 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +section entitled ``GNU General Public License'' is included exactly as +in the original, and provided that the entire resulting derived work is +distributed under the terms of a permission notice identical to this +one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that the section entitled ``GNU General Public License'' may be +included in a translation approved by the Free Software Foundation +instead of in the original English. +@end titlepage +@page +@node Top, Overview, (dir), (dir) +@ifinfo +This file is a user guide to the GNU assembler @code{_AS__}. +_if__(!_GENERIC__) +This version of the file describes @code{_AS__} configured to generate +code for _HOST__ architectures. +_fi__(!_GENERIC__) +@end ifinfo +@menu +* Overview:: Overview +* Invoking:: Command-Line Options +* Syntax:: Syntax +* Sections:: Sections and Relocation +* Symbols:: Symbols +* Expressions:: Expressions +* Pseudo Ops:: Assembler Directives +* _MACH_DEP__:: Machine Dependent Features +* Copying:: GNU GENERAL PUBLIC LICENSE +* Index:: Index +@end menu + +@node Overview, Invoking, Top, Top +@chapter Overview +@iftex +This manual is a user guide to the GNU assembler @code{_AS__}. +_if__(!_GENERIC__) +This version of the manual describes @code{_AS__} configured to generate +code for _HOST__ architectures. +_fi__(!_GENERIC__) +@end iftex + +@cindex invocation summary +@cindex option summary +@cindex summary of options +Here is a brief summary of how to invoke @code{_AS__}. For details, +@pxref{Invoking,,Comand-Line Options}. + +@c We don't use deffn and friends for the following because they seem +@c to be limited to one line for the header. +@smallexample + _AS__ [ -a | -al | -as ] [ -D ] [ -f ] + [ -I @var{path} ] [ -k ] [ -L ] + [ -o @var{objfile} ] [ -R ] [ -v ] [ -w ] +_if__(_A29K__) +@c am29k has no machine-dependent assembler options +_fi__(_A29K__) +_if__(_H8__) +@c h8/300 has no machine-dependent assembler options +_fi__(_H8__) +_if__(_I960__) +@c see md_parse_option in i960.c + [ -ACA | -ACA_A | -ACB | -ACC | -AKA | -AKB | -AKC | -AMC ] + [ -b ] [ -norelax ] +_fi__(_I960__) +_if__(_M680X0__) + [ -l ] [ -mc68000 | -mc68010 | -mc68020 ] +_fi__(_M680X0__) + [ -- | @var{files} @dots{} ] +@end smallexample + +@table @code +@item -a | -al | -as +Turn on assembly listings; @samp{-al}, listing only, @samp{-as}, symbols +only, @samp{-a}, everything. + +@item -D +This option is accepted only for script compatibility with calls to +other assemblers; it has no effect on @code{_AS__}. + +@item -f +``fast''---skip preprocessing (assume source is compiler output) + +@item -I @var{path} +Add @var{path} to the search list for @code{.include} directives + +@item -k +_if__((!_GENERIC__) && !_DIFFTABKLUG__) +This option is accepted but has no effect on the _HOST__ family. +_fi__((!_GENERIC__) && !_DIFFTABKLUG__) +_if__(_GENERIC__ || _DIFFTABKLUG__) +Issue warnings when difference tables altered for long displacements. +_fi__(_GENERIC__ || _DIFFTABKLUG__) + +@item -L +Keep (in symbol table) local symbols, starting with @samp{L} + +@item -o @var{objfile} +Name the object-file output from @code{_AS__} + +@item -R +Fold data section into text section + +@item -v +Announce @code{as} version + +@item -W +Suppress warning messages + +_if__(_I960__) +@item -ACA | -ACA_A | -ACB | -ACC | -AKA | -AKB | -AKC | -AMC +_if__(_GENERIC__) +(When configured for Intel 960). +_fi__(_GENERIC__) +Specify which variant of the 960 architecture is the target. + +@item -b +_if__(_GENERIC__) +(When configured for Intel 960). +_fi__(_GENERIC__) +Add code to collect statistics about branches taken. + +@item -norelax +_if__(_GENERIC__) +(When configured for Intel 960). +_fi__(_GENERIC__) +Do not alter compare-and-branch instructions for long displacements; +error if necessary. +_fi__(_I960__) + +_if__(_M680X0__) +@item -l +_if__(_GENERIC__) +(When configured for Motorola 68000). +_fi__(_GENERIC__) +Shorten references to undefined symbols, to one word instead of two + +@item -mc68000 | -mc68010 | -mc68020 +_if__(_GENERIC__) +(When configured for Motorola 68000). +_fi__(_GENERIC__) +Specify what processor in the 68000 family is the target (default 68020) +_fi__(_M680X0__) + +@item -- | @var{files} @dots{} +Standard input, or source files to assemble +@end table + +@menu +* Manual:: Structure of this Manual +* GNU Assembler:: _AS__, the GNU Assembler +* Object Formats:: Object File Formats +* Command Line:: Command Line +* Input Files:: Input Files +* Object:: Output (Object) File +* Errors:: Error and Warning Messages +@end menu + +@node Manual, GNU Assembler, Overview, Overview +@section Structure of this Manual + +@cindex manual, structure and purpose +This manual is intended to describe what you need to know to use +@sc{gnu} @code{_AS__}. We cover the syntax expected in source files, including +notation for symbols, constants, and expressions; the directives that +@code{_AS__} understands; and of course how to invoke @code{_AS__}. + +_if__(!_GENERIC__) +We also cover special features in the _HOST__ +configuration of @code{_AS__}, including assembler directives. +_fi__(!_GENERIC__) +_if__(_GENERIC__) +This manual also describes some of the machine-dependent features of +various flavors of the assembler. +_fi__(_GENERIC__) +_if__(_INTERNALS__) +This manual also describes how the assembler works internally, and +provides some information that may be useful to people attempting to +port the assembler to another machine. +_fi__(_INTERNALS__) +@refill + +@cindex machine instructions (not covered) +On the other hand, this manual is @emph{not} intended as an introduction +to programming in assembly language---let alone programming in general! +In a similar vein, we make no attempt to introduce the machine +architecture; we do @emph{not} describe the instruction set, standard +mnemonics, registers or addressing modes that are standard to a +particular architecture. +_if__(_GENERIC__) +You may want to consult the manufacturer's +machine architecture manual for this information. +_fi__(_GENERIC__) +_if__(_H8__&&!_GENERIC__) +For information on the H8/300 machine instruction set, see @cite{H8/300 +Series Programming Manual} (Hitachi ADE--602--025). +_fi__(_H8__&&!_GENERIC__) + + +@c I think this is premature---pesch@cygnus.com, 17jan1991 +@ignore +Throughout this manual, we assume that you are running @dfn{GNU}, +the portable operating system from the @dfn{Free Software +Foundation, Inc.}. This restricts our attention to certain kinds of +computer (in particular, the kinds of computers that GNU can run on); +once this assumption is granted examples and definitions need less +qualification. + +@code{_AS__} is part of a team of programs that turn a high-level +human-readable series of instructions into a low-level +computer-readable series of instructions. Different versions of +@code{_AS__} are used for different kinds of computer. +@end ignore + +@c There used to be a section "Terminology" here, which defined +@c "contents", "byte", "word", and "long". Defining "word" to any +@c particular size is confusing when the .word directive may generate 16 +@c bits on one machine and 32 bits on another; in general, for the user +@c version of this manual, none of these terms seem essential to define. +@c They were used very little even in the former draft of the manual; +@c this draft makes an effort to avoid them (except in names of +@c directives). + +@node GNU Assembler, Object Formats, Manual, Overview +@section _AS__, the GNU Assembler + +GNU @code{as} is really a family of assemblers. +_if__(!_GENERIC__) +This manual describes @code{_AS__}, a member of that family which is +configured for the _HOST__ architectures. +_fi__(!_GENERIC__) +If you use (or have used) the GNU assembler on one architecture, you +should find a fairly similar environment when you use it on another +architecture. Each version has much in common with the others, +including object file formats, most assembler directives (often called +@dfn{pseudo-ops)} and assembler syntax.@refill + +_if__(_GENERIC__||!_H8__) +@cindex purpose of @sc{gnu} @code{_AS__} +@code{_AS__} is primarily intended to assemble the output of the GNU C +compiler @code{_GCC__} for use by the linker @code{_LD__}. Nevertheless, +we've tried to make @code{_AS__} assemble correctly everything that the native +assembler would. +_fi__(_GENERIC__||!_H8__) +_if__(_VAX__) +Any exceptions are documented explicitly (@pxref{_MACH_DEP__}). +_fi__(_VAX__) +_if__(_GENERIC__||_M680X0__) +This doesn't mean @code{_AS__} always uses the same syntax as another +assembler for the same architecture; for example, we know of several +incompatible versions of 680x0 assembly language syntax. +_fi__(_GENERIC__||_M680X0__) + +Unlike older assemblers, @code{_AS__} is designed to assemble a source +program in one pass of the source file. This has a subtle impact on the +@kbd{.org} directive (@pxref{Org,,@code{.org}}). + +@node Object Formats, Command Line, GNU Assembler, Overview +@section Object File Formats + +@cindex object file format +The GNU assembler can be configured to produce several alternative +object file formats. For the most part, this does not affect how you +write assembly language programs; but directives for debugging symbols +are typically different in different file formats. @xref{Symbol +Attributes,,Symbol Attributes}. +_if__(!_GENERIC__) +_if__(!(_I960__||_A29K__)) +_if__(_AOUT__ && (!_COFF__) && (!_ELF__)) +On the _HOST__, @code{_AS__} is configured to produce @code{a.out} format object +files.@refill +_fi__(_AOUT__ && (!_COFF__) && (!_ELF__)) +_if__((!_AOUT__) && _COFF__ && (!_ELF__)) +On the _HOST__, @code{_AS__} is configured to produce COFF format object +files.@refill +_fi__((!_AOUT__) && _COFF__ && (!_ELF__)) +_fi__(!(_I960__||_A29K__)) +_if__(_A29K__) +On the _HOST__, @code{_AS__} can be configured to produce either +@code{a.out} or COFF format object files. +_fi__(_A29K__) +_if__(_I960__) +On the _HOST__, @code{_AS__} can be configured to produce either @code{b.out} or COFF +format object files. +_fi__(_I960__) +_fi__(!_GENERIC__) + +@node Command Line, Input Files, Object Formats, Overview +@section Command Line + +@cindex command line conventions +After the program name @code{_AS__}, the command line may contain +options and file names. Options may appear in any order, and may be +before, after, or between file names. The order of file names is +significant. + +@cindex standard input, as input file +@kindex -- +@file{--} (two hyphens) by itself names the standard input file +explicitly, as one of the files for @code{_AS__} to assemble. + +@cindex options, command line +Except for @samp{--} any command line argument that begins with a +hyphen (@samp{-}) is an option. Each option changes the behavior of +@code{_AS__}. No option changes the way another option works. An +option is a @samp{-} followed by one or more letters; the case of +the letter is important. All options are optional. + +Some options expect exactly one file name to follow them. The file +name may either immediately follow the option's letter (compatible +with older assemblers) or it may be the next command argument (GNU +standard). These two command lines are equivalent: + +@smallexample +_AS__ -o my-object-file.o mumble.s +_AS__ -omy-object-file.o mumble.s +@end smallexample + +@node Input Files, Object, Command Line, Overview +@section Input Files + +@cindex input +@cindex source program +@cindex files, input +We use the phrase @dfn{source program}, abbreviated @dfn{source}, to +describe the program input to one run of @code{_AS__}. The program may +be in one or more files; how the source is partitioned into files +doesn't change the meaning of the source. + +@c I added "con" prefix to "catenation" just to prove I can overcome my +@c APL training... pesch@cygnus.com +The source program is a concatenation of the text in all the files, in the +order specified. + +Each time you run @code{_AS__} it assembles exactly one source +program. The source program is made up of one or more files. +(The standard input is also a file.) + +You give @code{_AS__} a command line that has zero or more input file +names. The input files are read (from left file name to right). A +command line argument (in any position) that has no special meaning +is taken to be an input file name. + +If you give @code{_AS__} no file names it attempts to read one input file +from the @code{_AS__} standard input, which is normally your terminal. You +may have to type @key{ctl-D} to tell @code{_AS__} there is no more program +to assemble. + +Use @samp{--} if you need to explicitly name the standard input file +in your command line. + +If the source is empty, @code{_AS__} will produce a small, empty object +file. + +@subheading Filenames and Line-numbers + +@cindex input file linenumbers +@cindex line numbers, in input files +There are two ways of locating a line in the input file (or files) and +either may be used in reporting error messages. One way refers to a line +number in a physical file; the other refers to a line number in a +``logical'' file. @xref{Errors, ,Error and Warning Messages}. + +@dfn{Physical files} are those files named in the command line given +to @code{_AS__}. + +@dfn{Logical files} are simply names declared explicitly by assembler +directives; they bear no relation to physical files. Logical file names +help error messages reflect the original source file, when @code{_AS__} +source is itself synthesized from other files. +@xref{App-File,,@code{.app-file}}. + +@node Object, Errors, Input Files, Overview +@section Output (Object) File + +@cindex object file +@cindex output file +@kindex a.out +@kindex .o +Every time you run @code{_AS__} it produces an output file, which is +your assembly language program translated into numbers. This file +is the object file, named @code{a.out} unless you tell @code{_AS__} to +give it another name by using the @code{-o} option. Conventionally, +object file names end with @file{.o}. The default name of +@file{a.out} is used for historical reasons: older assemblers were +capable of assembling self-contained programs directly into a +runnable program. +@c This may still work, but hasn't been tested. + +@cindex linker +@kindex ld +The object file is meant for input to the linker @code{_LD__}. It contains +assembled program code, information to help @code{_LD__} integrate +the assembled program into a runnable file, and (optionally) symbolic +information for the debugger. + +@c link above to some info file(s) like the description of a.out. +@c don't forget to describe GNU info as well as Unix lossage. + +@node Errors, , Object, Overview +@section Error and Warning Messages + +@cindex error messsages +@cindex warning messages +@cindex messages from @code{_AS__} +@code{_AS__} may write warnings and error messages to the standard error +file (usually your terminal). This should not happen when a compiler +runs @code{_AS__} automatically. Warnings report an assumption made so +that @code{_AS__} could keep assembling a flawed program; errors report a +grave problem that stops the assembly. + +@cindex format of warning messages +Warning messages have the format + +@smallexample +file_name:@b{NNN}:Warning Message Text +@end smallexample + +@noindent +@cindex line numbers, in warnings/errors +(where @b{NNN} is a line number). If a logical file name has +been given (@pxref{App-File,,@code{.app-file}}) it is used for the filename, otherwise the +name of the current input file is used. If a logical line number was +given +_if__(!_A29K__) +(@pxref{Line,,@code{.line}}) +_fi__(!_A29K__) +_if__(_A29K__) +(@pxref{Ln,,@code{.ln}}) +_fi__(_A29K__) +then it is used to calculate the number printed, +otherwise the actual line in the current source file is printed. The +message text is intended to be self explanatory (in the grand Unix +tradition). @refill + +@cindex format of error messages +Error messages have the format +@smallexample +file_name:@b{NNN}:FATAL:Error Message Text +@end smallexample +The file name and line number are derived as for warning +messages. The actual message text may be rather less explanatory +because many of them aren't supposed to happen. + +@node Invoking, Syntax, Overview, Top +@chapter Command-Line Options + +@cindex options, all versions of @code{_AS__} +This chapter describes command-line options available in @emph{all} +versions of the GNU assembler; @pxref{_MACH_DEP__}, for options specific +_if__(!_GENERIC__) +to the _HOST__. +_fi__(!_GENERIC__) +_if__(_GENERIC__) +to particular machine architectures. +_fi__(_GENERIC__) + +@section Enable Listings: @code{-a}, @code{-al}, @code{-as} + +@kindex -a +@kindex -al +@kindex -as +@cindex listings, enabling +@cindex assembly listings, enabling +These options enable listing output from the assembler. @samp{-a} by +itself requests all listing output; @samp{-al} requests only the +output-program listing, and @samp{-as} requests only a symbol table +listing. + +Once you have specified one of these options, you can further control +listing output and its appearance using the directives @code{.list}, +@code{.nolist}, @code{.psize}, @code{.eject}, @code{.title}, and +@code{.sbttl}. + +If you do not request listing output with one of the @samp{-a} options, the +listing-control directives have no effect. + +@section @code{-D} + +@kindex -D +This option has no effect whatsoever, but it is accepted to make it more +likely that scripts written for other assemblers will also work with +@code{_AS__}. + +@section Work Faster: @code{-f} + +@kindex -f +@cindex trusted compiler +@cindex faster processing (@code{-f}) +@samp{-f} should only be used when assembling programs written by a +(trusted) compiler. @samp{-f} stops the assembler from pre-processing +the input file(s) before assembling them. @xref{Pre-processing, +,Pre-processing}. + +@quotation +@emph{Warning:} if the files actually need to be pre-processed (if they +contain comments, for example), @code{_AS__} will not work correctly if +@samp{-f} is used. +@end quotation + +@section @code{.include} search path: @code{-I} @var{path} + +@kindex -I @var{path} +@cindex paths for @code{.include} +@cindex search path for @code{.include} +@cindex @code{include} directive search path +Use this option to add a @var{path} to the list of directories +@code{_AS__} will search for files specified in @code{.include} +directives (@pxref{Include,,@code{.include}}). You may use @code{-I} as +many times as necessary to include a variety of paths. The current +working directory is always searched first; after that, @code{_AS__} +searches any @samp{-I} directories in the same order as they were +specified (left to right) on the command line. + +@section Difference Tables: @code{-k} + +@kindex -k +_if__((!_GENERIC__) && (!_DIFFTABKLUG__)) +On the _HOST__ family, this option is allowed, but has no effect. It is +permitted for compatibility with the GNU assembler on other platforms, +where it can be used to warn when the assembler alters the machine code +generated for @samp{.word} directives in difference tables. The _HOST__ +family does not have the addressing limitations that sometimes lead to this +alteration on other platforms. +_fi__((!_GENERIC__) && (!_DIFFTABKLUG__)) + +_if__(_GENERIC__ || _DIFFTABKLUG__ ) +@cindex difference tables, warning +@cindex warning for altered difference tables +@code{_AS__} sometimes alters the code emitted for directives of the form +@samp{.word @var{sym1}-@var{sym2}}; @pxref{Word,,@code{.word}}. +You can use the @samp{-k} option if you want a warning issued when this +is done. +_fi__(_GENERIC__ || _DIFFTABKLUG__ ) + +@section Include Local Labels: @code{-L} + +@kindex -L +@cindex local labels, retaining in output +Labels beginning with @samp{L} (upper case only) are called @dfn{local +labels}. @xref{Symbol Names}. Normally you don't see such labels when +debugging, because they are intended for the use of programs (like +compilers) that compose assembler programs, not for your notice. +Normally both @code{_AS__} and @code{_LD__} discard such labels, so you don't +normally debug with them. + +This option tells @code{_AS__} to retain those @samp{L@dots{}} symbols +in the object file. Usually if you do this you also tell the linker +@code{_LD__} to preserve symbols whose names begin with @samp{L}. + +@section Name the Object File: @code{-o} + +@kindex -o +@cindex naming object file +@cindex object file name +There is always one object file output when you run @code{_AS__}. By +default it has the name @file{a.out}. You use this option (which +takes exactly one filename) to give the object file a different name. + +Whatever the object file is called, @code{_AS__} will overwrite any +existing file of the same name. + +@section Join Data and Text Sections: @code{-R} + +@kindex -R +@cindex data and text sections, joining +@cindex text and data sections, joining +@cindex joining text and data sections +@cindex merging text and data sections +@code{-R} tells @code{_AS__} to write the object file as if all +data-section data lives in the text section. This is only done at +the very last moment: your binary data are the same, but data +section parts are relocated differently. The data section part of +your object file is zero bytes long because all it bytes are +appended to the text section. (@xref{Sections,,Sections and Relocation}.) + +When you specify @code{-R} it would be possible to generate shorter +address displacements (because we don't have to cross between text and +data section). We refrain from doing this simply for compatibility with +older versions of @code{_AS__}. In future, @code{-R} may work this way. + +_if__(_COFF__) +When @code{_AS__} is configured for COFF output, +this option is only useful if you use sections named @samp{.text} and +@samp{.data}. +_fi__(_COFF__) + +@section Announce Version: @code{-v} + +@kindex -v +@kindex -version +@cindex @code{_AS__} version +@cindex version of @code{_AS__} +You can find out what version of as is running by including the +option @samp{-v} (which you can also spell as @samp{-version}) on the +command line. + +@section Suppress Warnings: @code{-W} + +@kindex -W +@cindex suppressing warnings +@cindex warnings, suppressing +@code{_AS__} should never give a warning or error message when +assembling compiler output. But programs written by people often +cause @code{_AS__} to give a warning that a particular assumption was +made. All such warnings are directed to the standard error file. +If you use this option, no warnings are issued. This option only +affects the warning messages: it does not change any particular of how +@code{_AS__} assembles your file. Errors, which stop the assembly, are +still reported. + +@node Syntax, Sections, Invoking, Top +@chapter Syntax + +@cindex machine-independent syntax +@cindex syntax, machine-independent +This chapter describes the machine-independent syntax allowed in a +source file. @code{_AS__} syntax is similar to what many other assemblers +use; it is inspired in BSD 4.2 +_if__(!_VAX__) +assembler. @refill +_fi__(!_VAX__) +_if__(_VAX__) +assembler, except that @code{_AS__} does not assemble Vax bit-fields. +_fi__(_VAX__) + +@menu +* Pre-processing:: Pre-processing +* Whitespace:: Whitespace +* Comments:: Comments +* Symbol Intro:: Symbols +* Statements:: Statements +* Constants:: Constants +@end menu + +@node Pre-processing, Whitespace, Syntax, Syntax +@section Pre-Processing + +@cindex preprocessing +The pre-processor: +@itemize @bullet +@cindex whitespace, removed by preprocessor +@item +adjusts and removes extra whitespace. It leaves one space or tab before +the keywords on a line, and turns any other whitespace on the line into +a single space. + +@cindex comments, removed by preprocessor +@item +removes all comments, replacing them with a single space, or an +appropriate number of newlines. + +@cindex constants, converted by preprocessor +@item +converts character constants into the appropriate numeric values. +@end itemize + +Excess whitespace, comments, and character constants +cannot be used in the portions of the input text that are not +pre-processed. + +@cindex turning preprocessing on and off +@cindex preprocessing, turning on and off +@kindex #NO_APP +@kindex #APP +If the first line of an input file is @code{#NO_APP} or the @samp{-f} +option is given, the input file will not be pre-processed. Within such +an input file, parts of the file can be pre-processed by putting a line +that says @code{#APP} before the text that should be pre-processed, and +putting a line that says @code{#NO_APP} after them. This feature is +mainly intend to support @code{asm} statements in compilers whose output +normally does not need to be pre-processed. + +@node Whitespace, Comments, Pre-processing, Syntax +@section Whitespace + +@cindex whitespace +@dfn{Whitespace} is one or more blanks or tabs, in any order. +Whitespace is used to separate symbols, and to make programs neater for +people to read. Unless within character constants +(@pxref{Characters,,Character Constants}), any whitespace means the same +as exactly one space. + +@node Comments, Symbol Intro, Whitespace, Syntax +@section Comments + +@cindex comments +There are two ways of rendering comments to @code{_AS__}. In both +cases the comment is equivalent to one space. + +Anything from @samp{/*} through the next @samp{*/} is a comment. +This means you may not nest these comments. + +@smallexample +/* + The only way to include a newline ('\n') in a comment + is to use this sort of comment. +*/ + +/* This sort of comment does not nest. */ +@end smallexample + +@cindex line comment character +Anything from the @dfn{line comment} character to the next newline +is considered a comment and is ignored. The line comment character is +_if__(_VAX__) +@samp{#} on the Vax; +_fi__(_VAX__) +_if__(_I960__) +@samp{#} on the i960; +_fi__(_I960__) +_if__(_M680X0__) +@samp{|} on the 680x0; +_fi__(_M680X0__) +_if__(_A29K__) +@samp{;} for the AMD 29K family; +_fi__(_A29K__) +_if__(_H8__) +@samp{;} for the _HOST__ family; +_fi__(_H8__) +@pxref{_MACH_DEP__}. @refill +@c FIXME: fill in SPARC line comment char + +_if__(_GENERIC__) +On some machines there are two different line comment characters. One +will only begin a comment if it is the first non-whitespace character on +a line, while the other will always begin a comment. +_fi__(_GENERIC__) + +@kindex # +@cindex lines starting with @code{#} +@cindex logical line numbers +To be compatible with past assemblers, a special interpretation is +given to lines that begin with @samp{#}. Following the @samp{#} an +absolute expression (@pxref{Expressions}) is expected: this will be +the logical line number of the @b{next} line. Then a string +(@xref{Strings}.) is allowed: if present it is a new logical file +name. The rest of the line, if any, should be whitespace. + +If the first non-whitespace characters on the line are not numeric, +the line is ignored. (Just like a comment.) +@smallexample + # This is an ordinary comment. +# 42-6 "new_file_name" # New logical file name + # This is logical line # 36. +@end smallexample +This feature is deprecated, and may disappear from future versions +of @code{_AS__}. + +@node Symbol Intro, Statements, Comments, Syntax +@section Symbols + +@cindex symbols +@cindex characters used in symbols +A @dfn{symbol} is one or more characters chosen from the set of all +letters (both upper and lower case), digits and +_if__(!_H8__) +the three characters @samp{_.$} +_fi__(!_H8__) +_if__(_H8__) +the two characters @samp{_.} +_if__(_GENERIC__) +On most machines, you can also use @code{$} in symbol names; exceptions +are noted in @ref{_MACH_DEP__}. +_fi__(_GENERIC__) +_fi__(_H8__) +No symbol may begin with a digit. Case is significant. +There is no length limit: all characters are significant. Symbols are +delimited by characters not in that set, or by the beginning of a file +(since the source program must end with a newline, the end of a file is +not a possible symbol delimiter). @xref{Symbols}. +@cindex length of symbols + +@node Statements, Constants, Symbol Intro, Syntax +@section Statements + +@cindex statements, structure of +@cindex line separator character +@cindex statement separator character +_if__(!_GENERIC__) +_if__(!(_A29K__||_H8__)) +A @dfn{statement} ends at a newline character (@samp{\n}) or at a +semicolon (@samp{;}). The newline or semicolon is considered part of +the preceding statement. Newlines and semicolons within character +constants are an exception: they don't end statements. +_fi__(!(_A29K__||_H8__)) +_if__(_A29K__) +A @dfn{statement} ends at a newline character (@samp{\n}) or an ``at'' +sign (@samp{@@}). The newline or at sign is considered part of the +preceding statement. Newlines and at signs within character constants +are an exception: they don't end statements. +_fi__(_A29K__) +_if__(_H8__) +A @dfn{statement} ends at a newline character (@samp{\n}) or a dollar +sign (@samp{$}). The newline or dollar sign is considered part of the +preceding statement. Newlines and dollar signs within character constants +are an exception: they don't end statements. +_fi__(_H8__) +_fi__(!_GENERIC__) +_if__(_GENERIC__) +A @dfn{statement} ends at a newline character (@samp{\n}) or line +separator character. (The line separator is usually @samp{;}, unless +this conflicts with the comment character; @pxref{_MACH_DEP__}.) The +newline or separator character is considered part of the preceding +statement. Newlines and separators within character constants are an +exception: they don't end statements. +_fi__(_GENERIC__) + +@cindex newline, required at file end +@cindex EOF, newline must precede +It is an error to end any statement with end-of-file: the last +character of any input file should be a newline.@refill + +@cindex continuing statements +@cindex multi-line statements +@cindex statement on multiple lines +You may write a statement on more than one line if you put a +backslash (@kbd{\}) immediately in front of any newlines within the +statement. When @code{_AS__} reads a backslashed newline both +characters are ignored. You can even put backslashed newlines in +the middle of symbol names without changing the meaning of your +source program. + +An empty statement is allowed, and may include whitespace. It is ignored. + +@cindex instructions and directives +@cindex directives and instructions +@c "key symbol" is not used elsewhere in the document; seems pedantic to +@c @defn{} it in that case, as was done previously... pesch@cygnus.com, +@c 13feb91. +A statement begins with zero or more labels, optionally followed by a +key symbol which determines what kind of statement it is. The key +symbol determines the syntax of the rest of the statement. If the +symbol begins with a dot @samp{.} then the statement is an assembler +directive: typically valid for any computer. If the symbol begins with +a letter the statement is an assembly language @dfn{instruction}: it +will assemble into a machine language instruction. +_if__(_GENERIC__) +Different versions of @code{_AS__} for different computers will +recognize different instructions. In fact, the same symbol may +represent a different instruction in a different computer's assembly +language.@refill +_fi__(_GENERIC__) + +@cindex @code{:} (label) +@cindex label (@code{:}) +A label is a symbol immediately followed by a colon (@code{:}). +Whitespace before a label or after a colon is permitted, but you may not +have whitespace between a label's symbol and its colon. @xref{Labels}. + +@smallexample +label: .directive followed by something +another_label: # This is an empty statement. + instruction operand_1, operand_2, @dots{} +@end smallexample + +@node Constants, , Statements, Syntax +@section Constants + +@cindex constants +A constant is a number, written so that its value is known by +inspection, without knowing any context. Like this: +@smallexample +.byte 74, 0112, 092, 0x4A, 0X4a, 'J, '\J # All the same value. +.ascii "Ring the bell\7" # A string constant. +.octa 0x123456789abcdef0123456789ABCDEF0 # A bignum. +.float 0f-314159265358979323846264338327\ +95028841971.693993751E-40 # - pi, a flonum. +@end smallexample + +@menu +* Characters:: Character Constants +* Numbers:: Number Constants +@end menu + +@node Characters, Numbers, Constants, Constants +@subsection Character Constants + +@cindex character constants +@cindex constants, character +There are two kinds of character constants. A @dfn{character} stands +for one character in one byte and its value may be used in +numeric expressions. String constants (properly called string +@emph{literals}) are potentially many bytes and their values may not be +used in arithmetic expressions. + +@menu +* Strings:: Strings +* Chars:: Characters +@end menu + +@node Strings, Chars, Characters, Characters +@subsubsection Strings + +@cindex string constants +@cindex constants, string +A @dfn{string} is written between double-quotes. It may contain +double-quotes or null characters. The way to get special characters +into a string is to @dfn{escape} these characters: precede them with +a backslash @samp{\} character. For example @samp{\\} represents +one backslash: the first @code{\} is an escape which tells +@code{_AS__} to interpret the second character literally as a backslash +(which prevents @code{_AS__} from recognizing the second @code{\} as an +escape character). The complete list of escapes follows. + +@cindex escape codes, character +@cindex character escape codes +@table @kbd +@c @item \a +@c Mnemonic for ACKnowledge; for ASCII this is octal code 007. +@c +@item \b +@cindex @code{\b} (backspace character) +@cindex backspace (@code{\b}) +Mnemonic for backspace; for ASCII this is octal code 010. + +@c @item \e +@c Mnemonic for EOText; for ASCII this is octal code 004. +@c +@item \f +@cindex @code{\f} (formfeed character) +@cindex formfeed (@code{\f}) +Mnemonic for FormFeed; for ASCII this is octal code 014. + +@item \n +@cindex @code{\n} (newline character) +@cindex newline (@code{\n}) +Mnemonic for newline; for ASCII this is octal code 012. + +@c @item \p +@c Mnemonic for prefix; for ASCII this is octal code 033, usually known as @code{escape}. +@c +@item \r +@cindex @code{\r} (carriage return character) +@cindex carriage return (@code{\r}) +Mnemonic for carriage-Return; for ASCII this is octal code 015. + +@c @item \s +@c Mnemonic for space; for ASCII this is octal code 040. Included for compliance with +@c other assemblers. +@c +@item \t +@cindex @code{\t} (tab) +@cindex tab (@code{\t}) +Mnemonic for horizontal Tab; for ASCII this is octal code 011. + +@c @item \v +@c Mnemonic for Vertical tab; for ASCII this is octal code 013. +@c @item \x @var{digit} @var{digit} @var{digit} +@c A hexadecimal character code. The numeric code is 3 hexadecimal digits. +@c +@item \ @var{digit} @var{digit} @var{digit} +@cindex @code{\@var{ddd}} (octal character code) +@cindex octal character code (@code{\@var{ddd}}) +An octal character code. The numeric code is 3 octal digits. +For compatibility with other Unix systems, 8 and 9 are accepted as digits: +for example, @code{\008} has the value 010, and @code{\009} the value 011. + +@item \\ +@cindex @code{\\} (@samp{\} character) +@cindex backslash (@code{\\}) +Represents one @samp{\} character. + +@c @item \' +@c Represents one @samp{'} (accent acute) character. +@c This is needed in single character literals +@c (@xref{Characters,,Character Constants}.) to represent +@c a @samp{'}. +@c +@item \" +@cindex @code{\"} (doublequote character) +@cindex doublequote (@code{\"}) +Represents one @samp{"} character. Needed in strings to represent +this character, because an unescaped @samp{"} would end the string. + +@item \ @var{anything-else} +Any other character when escaped by @kbd{\} will give a warning, but +assemble as if the @samp{\} was not present. The idea is that if +you used an escape sequence you clearly didn't want the literal +interpretation of the following character. However @code{_AS__} has no +other interpretation, so @code{_AS__} knows it is giving you the wrong +code and warns you of the fact. +@end table + +Which characters are escapable, and what those escapes represent, +varies widely among assemblers. The current set is what we think +the BSD 4.2 assembler recognizes, and is a subset of what most C +compilers recognize. If you are in doubt, don't use an escape +sequence. + +@node Chars, , Strings, Characters +@subsubsection Characters + +@cindex single character constant +@cindex character, single +@cindex constant, single character +A single character may be written as a single quote immediately +followed by that character. The same escapes apply to characters as +to strings. So if you want to write the character backslash, you +must write @kbd{'\\} where the first @code{\} escapes the second +@code{\}. As you can see, the quote is an acute accent, not a +grave accent. A newline +_if__(!_GENERIC__) +_if__(!(_A29K__||_H8__)) +(or semicolon @samp{;}) +_fi__(!(_A29K__||_H8__)) +_if__(_A29K__) +(or at sign @samp{@@}) +_fi__(_A29K__) +_if__(_H8__) +(or dollar sign @samp{$}) +_fi__(_H8__) +_fi__(!_GENERIC__) +immediately following an acute accent is taken as a literal character +and does not count as the end of a statement. The value of a character +constant in a numeric expression is the machine's byte-wide code for +that character. @code{_AS__} assumes your character code is ASCII: +@kbd{'A} means 65, @kbd{'B} means 66, and so on. @refill + +@node Numbers, , Characters, Constants +@subsection Number Constants + +@cindex constants, number +@cindex number constants +@code{_AS__} distinguishes three kinds of numbers according to how they +are stored in the target machine. @emph{Integers} are numbers that +would fit into an @code{int} in the C language. @emph{Bignums} are +integers, but they are stored in more than 32 bits. @emph{Flonums} +are floating point numbers, described below. + +@menu +* Integers:: Integers +* Bignums:: Bignums +* Flonums:: Flonums +_if__(_I960__&&!_GENERIC__) +* Bit Fields:: Bit Fields +_fi__(_I960__&&!_GENERIC__) +@end menu + +@node Integers, Bignums, Numbers, Numbers +@subsubsection Integers +@cindex integers +@cindex constants, integer + +@cindex binary integers +@cindex integers, binary +A binary integer is @samp{0b} or @samp{0B} followed by zero or more of +the binary digits @samp{01}. + +@cindex octal integers +@cindex integers, octal +An octal integer is @samp{0} followed by zero or more of the octal +digits (@samp{01234567}). + +@cindex decimal integers +@cindex integers, decimal +A decimal integer starts with a non-zero digit followed by zero or +more digits (@samp{0123456789}). + +@cindex hexadecimal integers +@cindex integers, hexadecimal +A hexadecimal integer is @samp{0x} or @samp{0X} followed by one or +more hexadecimal digits chosen from @samp{0123456789abcdefABCDEF}. + +Integers have the usual values. To denote a negative integer, use +the prefix operator @samp{-} discussed under expressions +(@pxref{Prefix Ops,,Prefix Operators}). + +@node Bignums, Flonums, Integers, Numbers +@subsubsection Bignums + +@cindex bignums +@cindex constants, bignum +A @dfn{bignum} has the same syntax and semantics as an integer +except that the number (or its negative) takes more than 32 bits to +represent in binary. The distinction is made because in some places +integers are permitted while bignums are not. + +_if__(_I960__&&!_GENERIC__) +@node Flonums, Bit Fields, Bignums, Numbers +_fi__(_I960__&&!_GENERIC__) +_if__(_GENERIC__||!_I960__) +@node Flonums, , Bignums, Numbers +_fi__(_GENERIC__||!_I960__) +@subsubsection Flonums +@cindex flonums +@cindex floating point numbers +@cindex constants, floating point + +@cindex precision, floating point +A @dfn{flonum} represents a floating point number. The translation is +indirect: a decimal floating point number from the text is converted by +@code{_AS__} to a generic binary floating point number of more than +sufficient precision. This generic floating point number is converted +to a particular computer's floating point format (or formats) by a +portion of @code{_AS__} specialized to that computer. + +A flonum is written by writing (in order) +@itemize @bullet +@item +The digit @samp{0}. +@item +A letter, to tell @code{_AS__} the rest of the number is a flonum. +_if__(_GENERIC__) +@kbd{e} is recommended. Case is not important. +@ignore +@c FIXME: verify if flonum syntax really this vague for most cases + (Any otherwise illegal letter +will work here, but that might be changed. Vax BSD 4.2 assembler seems +to allow any of @samp{defghDEFGH}.) +@end ignore +_fi__(_GENERIC__) +_if__(_A29K__||_H8__) +_if__(_GENERIC__) +On the AMD 29K and H8/300 architectures, the letter must be: +_fi__(_GENERIC__) +One of the letters @samp{DFPRSX} (in upper or lower case). +_fi__(_A29K__||_H8__) +_if__(_I960__) +_if__(_GENERIC__) +On the Intel 960 architecture, the letter must be: +_fi__(_GENERIC__) +One of the letters @samp{DFT} (in upper or lower case). +_fi__(_I960__) +@item +An optional sign: either @samp{+} or @samp{-}. +@item +An optional @dfn{integer part}: zero or more decimal digits. +@item +An optional @dfn{fractional part}: @samp{.} followed by zero +or more decimal digits. +@item +An optional exponent, consisting of: +@itemize @bullet +@item +An @samp{E} or @samp{e}. +@c I can't find a config where "EXP_CHARS" is other than 'eE', but in +@c principle this can perfectly well be different on different targets. +@item +Optional sign: either @samp{+} or @samp{-}. +@item +One or more decimal digits. +@end itemize +@end itemize + +At least one of the integer part or the fractional part must be +present. The floating point number has the usual base-10 value. + +@code{_AS__} does all processing using integers. Flonums are computed +independently of any floating point hardware in the computer running +@code{_AS__}. + +_if__(_I960__&&!_GENERIC__) +@c Bit fields are written as a general facility but are also controlled +@c by a conditional-compilation flag---which is as of now (21mar91) +@c turned on only by the i960 config of GAS. +@node Bit Fields, , Flonums, Numbers +@subsubsection Bit Fields + +@cindex bit fields +@cindex constants, bit field +You can also define numeric constants as @dfn{bit fields}. +specify two numbers separated by a colon--- +@example +@var{mask}:@var{value} +@end example +@noindent +the first will act as a mask; @code{_AS__} will bitwise-and it with the +second value. + +The resulting number is then packed +_if__(_GENERIC__) +@c this conditional paren in case bit fields turned on elsewhere than 960 +(in host-dependent byte order) +_fi__(_GENERIC__) +into a field whose width depends on which assembler directive has the +bit-field as its argument. Overflow (a result from the bitwise and +requiring more binary digits to represent) is not an error; instead, +more constants are generated, of the specified width, beginning with the +least significant digits.@refill + +The directives @code{.byte}, @code{.hword}, @code{.int}, @code{.long}, +@code{.short}, and @code{.word} accept bit-field arguments. +_fi__(_I960__&&!_GENERIC__) + +@node Sections, Symbols, Syntax, Top +@chapter Sections and Relocation +@cindex sections +@cindex relocation + +@menu +* Secs Background:: Background +* _LD__ Sections:: _LD__ Sections +* _AS__ Sections:: _AS__ Internal Sections +* Sub-Sections:: Sub-Sections +* bss:: bss Section +@end menu + +@node Secs Background, _LD__ Sections, Sections, Sections +@section Background + +Roughly, a section is a range of addresses, with no gaps; all data +``in'' those addresses is treated the same for some particular purpose. +For example there may be a ``read only'' section. + +@cindex linker, and assembler +@cindex assembler, and linker +The linker @code{_LD__} reads many object files (partial programs) and +combines their contents to form a runnable program. When @code{_AS__} +emits an object file, the partial program is assumed to start at address +0. @code{_LD__} will assign the final addresses the partial program +occupies, so that different partial programs don't overlap. This is +actually an over-simplification, but it will suffice to explain how +@code{_AS__} uses sections. + +@code{_LD__} moves blocks of bytes of your program to their run-time +addresses. These blocks slide to their run-time addresses as rigid +units; their length does not change and neither does the order of bytes +within them. Such a rigid unit is called a @emph{section}. Assigning +run-time addresses to sections is called @dfn{relocation}. It includes +the task of adjusting mentions of object-file addresses so they refer to +the proper run-time addresses. +_if__(_H8__) +For the H8/300, @code{_AS__} pads sections if needed to ensure they end +on a word (sixteen bit) boundary. +_fi__(_H8__) + +@cindex standard @code{_AS__} sections +An object file written by @code{_AS__} has at least three sections, any +of which may be empty. These are named @dfn{text}, @dfn{data} and +@dfn{bss} sections. + +_if__(_COFF__) +_if__(_GENERIC__) +When it generates COFF output, +_fi__(_GENERIC__) +@code{_AS__} can also generate whatever other named sections you specify +using the @samp{.section} directive (@pxref{Section,,@code{.section}}). +If you don't use any directives that place output in the @samp{.text} +or @samp{.data} sections, these sections will still exist, but will be empty. +_fi__(_COFF__) + +Within the object file, the text section starts at address @code{0}, the +data section follows, and the bss section follows the data section. + +To let @code{_LD__} know which data will change when the sections are +relocated, and how to change that data, @code{_AS__} also writes to the +object file details of the relocation needed. To perform relocation +@code{_LD__} must know, each time an address in the object +file is mentioned: +@itemize @bullet +@item +Where in the object file is the beginning of this reference to +an address? +@item +How long (in bytes) is this reference? +@item +Which section does the address refer to? What is the numeric value of +@display +(@var{address}) @minus{} (@var{start-address of section})? +@end display +@item +Is the reference to an address ``Program-Counter relative''? +@end itemize + +@cindex addresses, format of +@cindex section-relative addressing +In fact, every address @code{_AS__} ever uses is expressed as +@display +(@var{section}) + (@var{offset into section}) +@end display +@noindent +Further, every expression @code{_AS__} computes is of this section-relative +nature. @dfn{Absolute expression} means an expression with section +``absolute'' (@pxref{_LD__ Sections}). A @dfn{pass1 expression} means +an expression with section ``pass1'' (@pxref{_AS__ Sections,,_AS__ +Internal Sections}). In this manual we use the notation @{@var{secname} +@var{N}@} to mean ``offset @var{N} into section @var{secname}''. + +Apart from text, data and bss sections you need to know about the +@dfn{absolute} section. When @code{_LD__} mixes partial programs, +addresses in the absolute section remain unchanged. For example, address +@code{@{absolute 0@}} is ``relocated'' to run-time address 0 by @code{_LD__}. +Although two partial programs' data sections will not overlap addresses +after linking, @emph{by definition} their absolute sections will overlap. +Address @code{@{absolute@ 239@}} in one partial program will always be the same +address when the program is running as address @code{@{absolute@ 239@}} in any +other partial program. + +The idea of sections is extended to the @dfn{undefined} section. Any +address whose section is unknown at assembly time is by definition +rendered @{undefined @var{U}@}---where @var{U} will be filled in later. +Since numbers are always defined, the only way to generate an undefined +address is to mention an undefined symbol. A reference to a named +common block would be such a symbol: its value is unknown at assembly +time so it has section @emph{undefined}. + +By analogy the word @emph{section} is used to describe groups of sections in +the linked program. @code{_LD__} puts all partial programs' text +sections in contiguous addresses in the linked program. It is +customary to refer to the @emph{text section} of a program, meaning all +the addresses of all partial program's text sections. Likewise for +data and bss sections. + +Some sections are manipulated by @code{_LD__}; others are invented for +use of @code{_AS__} and have no meaning except during assembly. + +@node _LD__ Sections, _AS__ Sections, Secs Background, Sections +@section _LD__ Sections +@code{_LD__} deals with just four kinds of sections, summarized below. + +@table @strong + +_if__(_GENERIC__||_COFF__) +@cindex named sections +@cindex sections, named +@item named sections +_fi__(_GENERIC__||_COFF__) +_if__(_AOUT__||_BOUT__) +@cindex text section +@cindex data section +@item text section +@itemx data section +_fi__(_AOUT__||_BOUT__) +These sections hold your program. @code{_AS__} and @code{_LD__} treat them as +separate but equal sections. Anything you can say of one section is +true another. +_if__(_AOUT__||_BOUT__) +When the program is running, however, it is +customary for the text section to be unalterable. The +text section is often shared among processes: it will contain +instructions, constants and the like. The data section of a running +program is usually alterable: for example, C variables would be stored +in the data section. +_fi__(_AOUT__||_BOUT__) + +@cindex bss section +@item bss section +This section contains zeroed bytes when your program begins running. It +is used to hold unitialized variables or common storage. The length of +each partial program's bss section is important, but because it starts +out containing zeroed bytes there is no need to store explicit zero +bytes in the object file. The bss section was invented to eliminate +those explicit zeros from object files. + +@cindex absolute section +@item absolute section +Address 0 of this section is always ``relocated'' to runtime address 0. +This is useful if you want to refer to an address that @code{_LD__} must +not change when relocating. In this sense we speak of absolute +addresses being ``unrelocatable'': they don't change during relocation. + +@cindex undefined section +@item undefined section +This ``section'' is a catch-all for address references to objects not in +the preceding sections. +@c FIXME: ref to some other doc on obj-file formats could go here. +@end table + +@cindex relocation example +An idealized example of three relocatable sections follows. +_if__(_COFF__) +The example uses the traditional section names @samp{.text} and @samp{.data}. +_fi__(_COFF__) +Memory addresses are on the horizontal axis. + +@c TEXI2ROFF-KILL +@ifinfo +@c END TEXI2ROFF-KILL +@smallexample + +-----+----+--+ +partial program # 1: |ttttt|dddd|00| + +-----+----+--+ + + text data bss + seg. seg. seg. + + +---+---+---+ +partial program # 2: |TTT|DDD|000| + +---+---+---+ + + +--+---+-----+--+----+---+-----+~~ +linked program: | |TTT|ttttt| |dddd|DDD|00000| + +--+---+-----+--+----+---+-----+~~ + + addresses: 0 @dots{} +@end smallexample +@c TEXI2ROFF-KILL +@end ifinfo +@c FIXME make sure no page breaks inside figure!! +@tex + +\line{\it Partial program \#1: \hfil} +\line{\ibox{2.5cm}{\tt text}\ibox{2cm}{\tt data}\ibox{1cm}{\tt bss}\hfil} +\line{\boxit{2.5cm}{\tt ttttt}\boxit{2cm}{\tt dddd}\boxit{1cm}{\tt 00}\hfil} + +\line{\it Partial program \#2: \hfil} +\line{\ibox{1cm}{\tt text}\ibox{1.5cm}{\tt data}\ibox{1cm}{\tt bss}\hfil} +\line{\boxit{1cm}{\tt TTT}\boxit{1.5cm}{\tt DDDD}\boxit{1cm}{\tt 000}\hfil} + +\line{\it linked program: \hfil} +\line{\ibox{.5cm}{}\ibox{1cm}{\tt text}\ibox{2.5cm}{}\ibox{.75cm}{}\ibox{2cm}{\tt data}\ibox{1.5cm}{}\ibox{2cm}{\tt bss}\hfil} +\line{\boxit{.5cm}{}\boxit{1cm}{\tt TTT}\boxit{2.5cm}{\tt +ttttt}\boxit{.75cm}{}\boxit{2cm}{\tt dddd}\boxit{1.5cm}{\tt +DDDD}\boxit{2cm}{\tt 00000}\ \dots\hfil} + +\line{\it addresses: \hfil} +\line{0\dots\hfil} + +@end tex +@c END TEXI2ROFF-KILL + +@node _AS__ Sections, Sub-Sections, _LD__ Sections, Sections +@section _AS__ Internal Sections + +@cindex internal @code{_AS__} sections +@cindex sections in messages, internal +These sections are meant only for the internal use of @code{_AS__}. They +have no meaning at run-time. You don't really need to know about these +sections for most purposes; but they can be mentioned in @code{_AS__} +warning messages, so it might be helpful to have an idea of their +meanings to @code{_AS__}. These sections are used to permit the +value of every expression in your assembly language program to be a +section-relative address. + +@table @b +@item absent +@cindex absent (internal section) +An expression was expected and none was found. + +@item ASSEMBLER-INTERNAL-LOGIC-ERROR! +@cindex assembler internal logic error +An internal assembler logic error has been found. This means there is a +bug in the assembler. + +@item bignum/flonum +@cindex bignum/flonum (internal section) +If a number can't be written as a C @code{int} constant (a bignum or a +flonum, but not an integer), it is recorded as belonging to this +``section''. @code{_AS__} has to remember that a flonum or a bignum +does not fit into 32 bits, and cannot be an argument (@pxref{Arguments}) +in an expression: this is done by making a flonum or bignum be in a +separate internal section. This is purely for internal @code{_AS__} +convenience; bignum/flonum section behaves similarly to absolute +section. + +@item pass1 section +@cindex pass1 (internal section) +The expression was impossible to evaluate in the first pass. The +assembler will attempt a second pass (second reading of the source) to +evaluate the expression. Your expression mentioned an undefined symbol +in a way that defies the one-pass (section + offset in section) assembly +process. No compiler need emit such an expression. + +@quotation +@emph{Warning:} the second pass is currently not implemented. @code{_AS__} +will abort with an error message if one is required. +@end quotation + +@item difference section +@cindex difference (internal section) +As an assist to the C compiler, expressions of the forms +@display + (@var{undefined symbol}) @minus{} (@var{expression}) + @var{something} @minus{} (@var{undefined symbol}) + (@var{undefined symbol}) @minus{} (@var{undefined symbol}) +@end display + +are permitted, and belong to the difference section. @code{_AS__} +re-evaluates such expressions after the source file has been read and +the symbol table built. If by that time there are no undefined symbols +in the expression then the expression assumes a new section. The +intention is to permit statements like +@samp{.word label - base_of_table} +to be assembled in one pass where both @code{label} and +@code{base_of_table} are undefined. This is useful for compiling C and +Algol switch statements, Pascal case statements, FORTRAN computed goto +statements and the like. +@c FIXME item debug +@c FIXME item transfer[t] vector preload +@c FIXME item transfer[t] vector postload +@c FIXME item register +@end table + +@node Sub-Sections, bss, _AS__ Sections, Sections +@section Sub-Sections + +@cindex numbered subsections +@cindex grouping data +_if__(_AOUT__||_BOUT__) +Assembled bytes +_if__(_COFF__) +conventionally +_fi__(_COFF__) +fall into two sections: text and data. +_fi__(_AOUT__||_BOUT__) +You may have separate groups of +_if__(_COFF__||_GENERIC__) +data in named sections +_fi__(_COFF__||_GENERIC__) +_if__((_AOUT__||_BOUT__)&&!_GENERIC__) +text or data +_fi__((_AOUT__||_BOUT__)&&!_GENERIC__) +that you want to end up near to each other in the object +file, even though they are not contiguous in the assembler source. +@code{_AS__} allows you to use @dfn{subsections} for this purpose. +Within each section, there can be numbered subsections with +values from 0 to 8192. Objects assembled into the same subsection will +be grouped with other objects in the same subsection when they are all +put into the object file. For example, a compiler might want to store +constants in the text section, but might not want to have them +interspersed with the program being assembled. In this case, the +compiler could issue a @samp{.text 0} before each section of code being +output, and a @samp{.text 1} before each group of constants being output. + +Subsections are optional. If you don't use subsections, everything +will be stored in subsection number zero. + +_if__(_GENERIC__) +Each subsection is zero-padded up to a multiple of four bytes. +(Subsections may be padded a different amount on different flavors +of @code{_AS__}.) +_fi__(_GENERIC__) +_if__(!_GENERIC__) +_if__(_H8__) +On the H8/300 platform, each subsection is zero-padded to a word +boundary (two bytes). +_fi__(_H8__) +_if__(_I960__) +@c FIXME section padding (alignment)? +@c Rich Pixley says padding here depends on target obj code format; that +@c doesn't seem particularly useful to say without further elaboration, +@c so for now I say nothing about it. If this is a generic BFD issue, +@c these paragraphs might need to vanish from this manual, and be +@c discussed in BFD chapter of binutils (or some such). +_fi__(_I960__) +_if__(_A29K__) +On the AMD 29K family, no particular padding is added to section or +subsection sizes; _AS__ forces no alignment on this platform. +_fi__(_A29K__) +_fi__(!_GENERIC__) + +Subsections appear in your object file in numeric order, lowest numbered +to highest. (All this to be compatible with other people's assemblers.) +The object file contains no representation of subsections; @code{_LD__} and +other programs that manipulate object files will see no trace of them. +They just see all your text subsections as a text section, and all your +data subsections as a data section. + +To specify which subsection you want subsequent statements assembled +into, use a numeric argument to specify it, in a @samp{.text +@var{expression}} or a @samp{.data @var{expression}} statement. +_if__(_COFF__) +_if__(_GENERIC__) +When generating COFF output, you +_fi__(_GENERIC__) +_if__(!_GENERIC__) +You +_fi__(!_GENERIC__) +can also use an extra subsection +argument with arbitrary named sections: @samp{.section @var{name}, +@var{expression}}. +_fi__(_COFF__) +@var{Expression} should be an absolute expression. +(@xref{Expressions}.) If you just say @samp{.text} then @samp{.text 0} +is assumed. Likewise @samp{.data} means @samp{.data 0}. Assembly +begins in @code{text 0}. For instance: +@smallexample +.text 0 # The default subsection is text 0 anyway. +.ascii "This lives in the first text subsection. *" +.text 1 +.ascii "But this lives in the second text subsection." +.data 0 +.ascii "This lives in the data section," +.ascii "in the first data subsection." +.text 0 +.ascii "This lives in the first text section," +.ascii "immediately following the asterisk (*)." +@end smallexample + +Each section has a @dfn{location counter} incremented by one for every +byte assembled into that section. Because subsections are merely a +convenience restricted to @code{_AS__} there is no concept of a subsection +location counter. There is no way to directly manipulate a location +counter---but the @code{.align} directive will change it, and any label +definition will capture its current value. The location counter of the +section that statements are being assembled into is said to be the +@dfn{active} location counter. + +@node bss, , Sub-Sections, Sections +@section bss Section + +@cindex bss section +@cindex common variable storage +The bss section is used for local common variable storage. +You may allocate address space in the bss section, but you may +not dictate data to load into it before your program executes. When +your program starts running, all the contents of the bss +section are zeroed bytes. + +Addresses in the bss section are allocated with special directives; you +may not assemble anything directly into the bss section. Hence there +are no bss subsections. @xref{Comm,,@code{.comm}}, +@pxref{Lcomm,,@code{.lcomm}}. + +@node Symbols, Expressions, Sections, Top +@chapter Symbols + +@cindex symbols +Symbols are a central concept: the programmer uses symbols to name +things, the linker uses symbols to link, and the debugger uses symbols +to debug. + +@quotation +@cindex debuggers, and symbol order +@emph{Warning:} @code{_AS__} does not place symbols in the object file in +the same order they were declared. This may break some debuggers. +@end quotation + +@menu +* Labels:: Labels +* Setting Symbols:: Giving Symbols Other Values +* Symbol Names:: Symbol Names +* Dot:: The Special Dot Symbol +* Symbol Attributes:: Symbol Attributes +@end menu + +@node Labels, Setting Symbols, Symbols, Symbols +@section Labels + +@cindex labels +A @dfn{label} is written as a symbol immediately followed by a colon +@samp{:}. The symbol then represents the current value of the +active location counter, and is, for example, a suitable instruction +operand. You are warned if you use the same symbol to represent two +different locations: the first definition overrides any other +definitions. + +@node Setting Symbols, Symbol Names, Labels, Symbols +@section Giving Symbols Other Values + +@cindex assigning values to symbols +@cindex symbol values, assigning +A symbol can be given an arbitrary value by writing a symbol, followed +by an equals sign @samp{=}, followed by an expression +(@pxref{Expressions}). This is equivalent to using the @code{.set} +directive. @xref{Set,,@code{.set}}. + +@node Symbol Names, Dot, Setting Symbols, Symbols +@section Symbol Names + +@cindex symbol names +@cindex names, symbol +Symbol names begin with a letter or with one of +_if__(!_H8__) +@samp{_.$} +_fi__(!_H8__) +_if__(_H8__) +@samp{_.} +_if__(_GENERIC__) +(On most machines, you can also use @code{$} in symbol names; exceptions +are noted in @ref{_MACH_DEP__}.) +_fi__(_GENERIC__) +_fi__(_H8__) +That character may be followed by any string of digits, letters, +_if__(!_H8__) +underscores and dollar signs. +_fi__(!_H8__) +_if__(_H8__) +_if__(_GENERIC__) +dollar signs (unless otherwise noted in @ref{_MACH_DEP__}), +_fi__(_GENERIC__) +and underscores. +_fi__(_H8__) +Case of letters is significant: +@code{foo} is a different symbol name than @code{Foo}. + +_if__(_A29K__) +For the AMD 29K family, @samp{?} is also allowed in the +body of a symbol name, though not at its beginning. +_fi__(_A29K__) + +Each symbol has exactly one name. Each name in an assembly language +program refers to exactly one symbol. You may use that symbol name any +number of times in a program. + +@subheading Local Symbol Names + +@cindex local symbol names +@cindex symbol names, local +@cindex temporary symbol names +@cindex symbol names, temporary +Local symbols help compilers and programmers use names temporarily. +There are ten local symbol names, which are re-used throughout the +program. You may refer to them using the names @samp{0} @samp{1} +@dots{} @samp{9}. To define a local symbol, write a label of the form +@samp{@b{N}:} (where @b{N} represents any digit). To refer to the most +recent previous definition of that symbol write @samp{@b{N}b}, using the +same digit as when you defined the label. To refer to the next +definition of a local label, write @samp{@b{N}f}---where @b{N} gives you +a choice of 10 forward references. The @samp{b} stands for +``backwards'' and the @samp{f} stands for ``forwards''. + +Local symbols are not emitted by the current GNU C compiler. + +There is no restriction on how you can use these labels, but +remember that at any point in the assembly you can refer to at most +10 prior local labels and to at most 10 forward local labels. + +Local symbol names are only a notation device. They are immediately +transformed into more conventional symbol names before the assembler +uses them. The symbol names stored in the symbol table, appearing in +error messages and optionally emitted to the object file have these +parts: + +@table @code +@item L +All local labels begin with @samp{L}. Normally both @code{_AS__} and +@code{_LD__} forget symbols that start with @samp{L}. These labels are +used for symbols you are never intended to see. If you give the +@samp{-L} option then @code{_AS__} will retain these symbols in the +object file. If you also instruct @code{_LD__} to retain these symbols, +you may use them in debugging. + +@item @var{digit} +If the label is written @samp{0:} then the digit is @samp{0}. +If the label is written @samp{1:} then the digit is @samp{1}. +And so on up through @samp{9:}. + +@item @ctrl{A} +This unusual character is included so you don't accidentally invent +a symbol of the same name. The character has ASCII value +@samp{\001}. + +@item @emph{ordinal number} +This is a serial number to keep the labels distinct. The first +@samp{0:} gets the number @samp{1}; The 15th @samp{0:} gets the +number @samp{15}; @emph{etc.}. Likewise for the other labels @samp{1:} +through @samp{9:}. +@end table + +For instance, the first @code{1:} is named @code{L1@ctrl{A}1}, the 44th +@code{3:} is named @code{L3@ctrl{A}44}. + +@node Dot, Symbol Attributes, Symbol Names, Symbols +@section The Special Dot Symbol + +@cindex dot (symbol) +@cindex @code{.} (symbol) +@cindex current address +@cindex location counter +The special symbol @samp{.} refers to the current address that +@code{_AS__} is assembling into. Thus, the expression @samp{melvin: +.long .} will cause @code{melvin} to contain its own address. +Assigning a value to @code{.} is treated the same as a @code{.org} +directive. Thus, the expression @samp{.=.+4} is the same as saying +_if__(!_A29K__) +@samp{.space 4}. +_fi__(!_A29K__) +_if__(_A29K__) +@samp{.block 4}. +_fi__(_A29K__) + +@node Symbol Attributes, , Dot, Symbols +@section Symbol Attributes + +@cindex symbol attributes +@cindex attributes, symbol +Every symbol has, as well as its name, the attributes ``Value'' and +``Type''. Depending on output format, symbols can also have auxiliary +attributes. +_if__(_INTERNALS__) +The detailed definitions are in _0__<a.out.h>_1__. +_fi__(_INTERNALS__) + +If you use a symbol without defining it, @code{_AS__} assumes zero for +all these attributes, and probably won't warn you. This makes the +symbol an externally defined symbol, which is generally what you +would want. + +@menu +* Symbol Value:: Value +* Symbol Type:: Type +_if__(_AOUT__||_BOUT__) +_if__(_GENERIC__||!_BOUT__) +* a.out Symbols:: Symbol Attributes: @code{a.out} +_fi__(_GENERIC__||!_BOUT__) +_if__(_BOUT__&&!_GENERIC__) +* a.out Symbols:: Symbol Attributes: @code{a.out}, @code{b.out} +_fi__(_BOUT__&&!_GENERIC__) +_fi__(_AOUT__||_BOUT__) +_if__(_COFF__) +* COFF Symbols:: Symbol Attributes for COFF +_fi__(_COFF__) +@end menu + +@node Symbol Value, Symbol Type, Symbol Attributes, Symbol Attributes +@subsection Value + +@cindex value of a symbol +@cindex symbol value +The value of a symbol is (usually) 32 bits. For a symbol which labels a +location in the text, data, bss or absolute sections the value is the +number of addresses from the start of that section to the label. +Naturally for text, data and bss sections the value of a symbol changes +as @code{_LD__} changes section base addresses during linking. Absolute +symbols' values do not change during linking: that is why they are +called absolute. + +The value of an undefined symbol is treated in a special way. If it is +0 then the symbol is not defined in this assembler source program, and +@code{_LD__} will try to determine its value from other programs it is +linked with. You make this kind of symbol simply by mentioning a symbol +name without defining it. A non-zero value represents a @code{.comm} +common declaration. The value is how much common storage to reserve, in +bytes (addresses). The symbol refers to the first address of the +allocated storage. + +_if__(!(_AOUT__||_BOUT__)) +@node Symbol Type, COFF Symbols, Symbol Value, Symbol Attributes +_fi__(!(_AOUT__||_BOUT__)) +_if__((_AOUT__||_BOUT__)) +@node Symbol Type, a.out Symbols, Symbol Value, Symbol Attributes +_fi__((_AOUT__||_BOUT__)) +@subsection Type + +@cindex type of a symbol +@cindex symbol type +The type attribute of a symbol contains relocation (section) +information, any flag settings indicating that a symbol is external, and +(optionally), other information for linkers and debuggers. The exact +format depends on the object-code output format in use. + +_if__(_AOUT__||_BOUT__) +_if__(_COFF__) +@node a.out Symbols, COFF Symbols, Symbol Type, Symbol Attributes +_fi__(_COFF__) +_if__(!_COFF__) +@node a.out Symbols, , Symbol Type, Symbol Attributes +_fi__(!_COFF__) +_if__(_BOUT__&&!_GENERIC__) +@subsection Symbol Attributes: @code{a.out}, @code{b.out} + +@cindex @code{b.out} symbol attributes +@cindex symbol attributes, @code{b.out} +These symbol attributes appear only when @code{_AS__} is configured for +one of the Berkeley-descended object output formats. +_fi__(_BOUT__&&!_GENERIC__) +_if__(_GENERIC__||!_BOUT__) +@subsection Symbol Attributes: @code{a.out} +_fi__(_GENERIC__||!_BOUT__) + +@cindex @code{a.out} symbol attributes +@cindex symbol attributes, @code{a.out} + +@menu +* Symbol Desc:: Descriptor +* Symbol Other:: Other +@end menu + +@node Symbol Desc, Symbol Other, a.out Symbols, a.out Symbols +@subsubsection Descriptor + +@cindex descriptor, of @code{a.out} symbol +This is an arbitrary 16-bit value. You may establish a symbol's +descriptor value by using a @code{.desc} statement +(@pxref{Desc,,@code{.desc}}). A descriptor value means nothing to +@code{_AS__}. + +@node Symbol Other, , Symbol Desc, a.out Symbols +@subsubsection Other + +@cindex other attribute, of @code{a.out} symbol +This is an arbitrary 8-bit value. It means nothing to @code{_AS__}. +_fi__(_AOUT__||_BOUT__) + +_if__(_COFF__) +_if__(!(_AOUT__||_BOUT__)) +@node COFF Symbols, , Symbol Type, Symbol Attributes +_fi__(!(_AOUT__||_BOUT__)) +_if__(_AOUT__||_BOUT__) +@node COFF Symbols, , a.out Symbols, Symbol Attributes +_fi__(_AOUT__||_BOUT__) +@subsection Symbol Attributes for COFF + +@cindex COFF symbol attributes +@cindex symbol attributes, COFF + +The COFF format supports a multitude of auxiliary symbol attributes; +like the primary symbol attributes, they are set between @code{.def} and +@code{.endef} directives. + +@subsubsection Primary Attributes + +@cindex primary attributes, COFF symbols +The symbol name is set with @code{.def}; the value and type, +respectively, with @code{.val} and @code{.type}. + +@subsubsection Auxiliary Attributes + +@cindex auxiliary attributes, COFF symbols +The @code{_AS__} directives @code{.dim}, @code{.line}, @code{.scl}, +@code{.size}, and @code{.tag} can generate auxiliary symbol table +information for COFF. +_fi__(_COFF__) + +@node Expressions, Pseudo Ops, Symbols, Top +@chapter Expressions + +@cindex expressions +@cindex addresses +@cindex numeric values +An @dfn{expression} specifies an address or numeric value. +Whitespace may precede and/or follow an expression. + +@menu +* Empty Exprs:: Empty Expressions +* Integer Exprs:: Integer Expressions +@end menu + +@node Empty Exprs, Integer Exprs, Expressions, Expressions +@section Empty Expressions + +@cindex empty expressions +@cindex expressions, empty +An empty expression has no value: it is just whitespace or null. +Wherever an absolute expression is required, you may omit the +expression and @code{_AS__} will assume a value of (absolute) 0. This +is compatible with other assemblers. + +@node Integer Exprs, , Empty Exprs, Expressions +@section Integer Expressions + +@cindex integer expressions +@cindex expressions, integer +An @dfn{integer expression} is one or more @emph{arguments} delimited +by @emph{operators}. + +@menu +* Arguments:: Arguments +* Operators:: Operators +* Prefix Ops:: Prefix Operators +* Infix Ops:: Infix Operators +@end menu + +@node Arguments, Operators, Integer Exprs, Integer Exprs +@subsection Arguments + +@cindex expression arguments +@cindex arguments in expressions +@cindex operands in expressions +@cindex arithmetic operands +@dfn{Arguments} are symbols, numbers or subexpressions. In other +contexts arguments are sometimes called ``arithmetic operands''. In +this manual, to avoid confusing them with the ``instruction operands'' of +the machine language, we use the term ``argument'' to refer to parts of +expressions only, reserving the word ``operand'' to refer only to machine +instruction operands. + +Symbols are evaluated to yield @{@var{section} @var{NNN}@} where +@var{section} is one of text, data, bss, absolute, +or undefined. @var{NNN} is a signed, 2's complement 32 bit +integer. + +Numbers are usually integers. + +A number can be a flonum or bignum. In this case, you are warned +that only the low order 32 bits are used, and @code{_AS__} pretends +these 32 bits are an integer. You may write integer-manipulating +instructions that act on exotic constants, compatible with other +assemblers. + +@cindex subexpressions +Subexpressions are a left parenthesis @samp{(} followed by an integer +expression, followed by a right parenthesis @samp{)}; or a prefix +operator followed by an argument. + +@node Operators, Prefix Ops, Arguments, Integer Exprs +@subsection Operators + +@cindex operators, in expressions +@cindex arithmetic functions +@cindex functions, in expressions +@dfn{Operators} are arithmetic functions, like @code{+} or @code{%}. Prefix +operators are followed by an argument. Infix operators appear +between their arguments. Operators may be preceded and/or followed by +whitespace. + +@node Prefix Ops, Infix Ops, Operators, Integer Exprs +@subsection Prefix Operator + +@cindex prefix operators +@code{_AS__} has the following @dfn{prefix operators}. They each take +one argument, which must be absolute. + +@c the tex/end tex stuff surrounding this small table is meant to make +@c it align, on the printed page, with the similar table in the next +@c section (which is inside an enumerate). +@tex +\global\advance\leftskip by \itemindent +@end tex + +@table @code +@item - +@dfn{Negation}. Two's complement negation. +@item ~ +@dfn{Complementation}. Bitwise not. +@end table + +@tex +\global\advance\leftskip by -\itemindent +@end tex + +@node Infix Ops, , Prefix Ops, Integer Exprs +@subsection Infix Operators + +@cindex infix operators +@cindex operators, permitted arguments +@dfn{Infix operators} take two arguments, one on either side. Operators +have precedence, but operations with equal precedence are performed left +to right. Apart from @code{+} or @code{-}, both arguments must be +absolute, and the result is absolute. + +@enumerate +@cindex operator precedence +@cindex precedence of operators + +@item +Highest Precedence + +@table @code +@item * +@dfn{Multiplication}. + +@item / +@dfn{Division}. Truncation is the same as the C operator @samp{/} + +@item % +@dfn{Remainder}. + +@item _0__<_1__ +@itemx _0__<<_1__ +@dfn{Shift Left}. Same as the C operator @samp{_0__<<_1__} + +@item _0__>_1__ +@itemx _0__>>_1__ +@dfn{Shift Right}. Same as the C operator @samp{_0__>>_1__} +@end table + +@item +Intermediate precedence + +@table @code +@item | + +@dfn{Bitwise Inclusive Or}. + +@item & +@dfn{Bitwise And}. + +@item ^ +@dfn{Bitwise Exclusive Or}. + +@item ! +@dfn{Bitwise Or Not}. +@end table + +@item +Lowest Precedence + +@table @code +@item + +@cindex addition, permitted arguments +@cindex plus, permitted arguments +@cindex arguments for addition +@dfn{Addition}. If either argument is absolute, the result +has the section of the other argument. +If either argument is pass1 or undefined, the result is pass1. +Otherwise @code{+} is illegal. + +@item - +@cindex subtraction, permitted arguments +@cindex minus, permitted arguments +@cindex arguments for subtraction +@dfn{Subtraction}. If the right argument is absolute, the +result has the section of the left argument. +If either argument is pass1 the result is pass1. +If either argument is undefined the result is difference section. +If both arguments are in the same section, the result is absolute---provided +that section is one of text, data or bss. +Otherwise subtraction is illegal. +@end table +@end enumerate + +The sense of the rule for addition is that it's only meaningful to add +the @emph{offsets} in an address; you can only have a defined section in +one of the two arguments. + +Similarly, you can't subtract quantities from two different sections. + +@node Pseudo Ops, _MACH_DEP__, Expressions, Top +@chapter Assembler Directives + +@cindex directives, machine independent +@cindex pseudo-ops, machine independent +@cindex machine independent directives +All assembler directives have names that begin with a period (@samp{.}). +The rest of the name is letters, usually in lower case. + +This chapter discusses directives present regardless of the target +machine configuration for the GNU assembler. +_if__(!_H8__) +@xref{_MACH_DEP__} for additional directives. +_fi__(!_H8__) + +@menu +* Abort:: @code{.abort} +_if__(_COFF__) +* coff-ABORT:: @code{.ABORT} +_fi__(_COFF__) +_if__(_BOUT__&&!_COFF__) +* bout-ABORT:: @code{.ABORT} +_fi__(_BOUT__&&!_COFF__) +* Align:: @code{.align @var{abs-expr} , @var{abs-expr}} +* App-File:: @code{.app-file @var{string}} +* Ascii:: @code{.ascii "@var{string}"}@dots{} +* Asciz:: @code{.asciz "@var{string}"}@dots{} +* Byte:: @code{.byte @var{expressions}} +* Comm:: @code{.comm @var{symbol} , @var{length} } +* Data:: @code{.data @var{subsection}} +_if__(_COFF__||_BOUT__) +* Def:: @code{.def @var{name}} +_fi__(_COFF__||_BOUT__) +_if__(_AOUT__||_BOUT__) +* Desc:: @code{.desc @var{symbol}, @var{abs-expression}} +_fi__(_AOUT__||_BOUT__) +_if__(_COFF__||_BOUT__) +* Dim:: @code{.dim} +_fi__(_COFF__||_BOUT__) +* Double:: @code{.double @var{flonums}} +* Eject:: @code{.eject} +* Else:: @code{.else} +_if__(_COFF__||_BOUT__) +* Endef:: @code{.endef} +_fi__(_COFF__||_BOUT__) +* Endif:: @code{.endif} +* Equ:: @code{.equ @var{symbol}, @var{expression}} +* Extern:: @code{.extern} +_if__(_GENERIC__||!_A29K__) +* File:: @code{.file @var{string}} +_fi__(_GENERIC__||!_A29K__) +* Fill:: @code{.fill @var{repeat} , @var{size} , @var{value}} +* Float:: @code{.float @var{flonums}} +* Global:: @code{.global @var{symbol}}, @code{.globl @var{symbol}} +* hword:: @code{.hword @var{expressions}} +* Ident:: @code{.ident} +* If:: @code{.if @var{absolute expression}} +* Include:: @code{.include "@var{file}"} +* Int:: @code{.int @var{expressions}} +* Lcomm:: @code{.lcomm @var{symbol} , @var{length}} +* Lflags:: @code{.lflags} +_if__(_GENERIC__||!_A29K__) +* Line:: @code{.line @var{line-number}} +_fi__(_GENERIC__||!_A29K__) +* Ln:: @code{.ln @var{line-number}} +* List:: @code{.list} +* Long:: @code{.long @var{expressions}} +* Lsym:: @code{.lsym @var{symbol}, @var{expression}} +* Nolist:: @code{.nolist} +* Octa:: @code{.octa @var{bignums}} +* Org:: @code{.org @var{new-lc} , @var{fill}} +* Psize:: @code{.psize @var{lines}, @var{columns}} +* Quad:: @code{.quad @var{bignums}} +* Sbttl:: @code{.sbttl "@var{subheading}"} +_if__(_COFF__||_BOUT__) +* Scl:: @code{.scl @var{class}} +_fi__(_COFF__||_BOUT__) +_if__(_COFF__) +* Section:: @code{.section @var{name}, @var{subsection}} +_fi__(_COFF__) +* Set:: @code{.set @var{symbol}, @var{expression}} +* Short:: @code{.short @var{expressions}} +* Single:: @code{.single @var{flonums}} +_if__(_COFF__||_BOUT__) +* Size:: @code{.size} +_fi__(_COFF__||_BOUT__) +* Space:: @code{.space @var{size} , @var{fill}} +_if__(_GENERIC__||!_H8__) +* Stab:: @code{.stabd, .stabn, .stabs} +_fi__(_GENERIC__||!_H8__) +_if__(_COFF__||_BOUT__) +* Tag:: @code{.tag @var{structname}} +_fi__(_COFF__||_BOUT__) +* Text:: @code{.text @var{subsection}} +* Title:: @code{.title "@var{heading}"} +_if__(_COFF__||_BOUT__) +* Type:: @code{.type @var{int}} +* Val:: @code{.val @var{addr}} +_fi__(_COFF__||_BOUT__) +* Word:: @code{.word @var{expressions}} +* Deprecated:: Deprecated Directives +@end menu + +_if__(_COFF__) +@node Abort, coff-ABORT, Pseudo Ops, Pseudo Ops +_fi__(_COFF__) +_if__((!_COFF__) && _BOUT__) +@node Abort, bout-ABORT, Pseudo Ops, Pseudo Ops +_fi__((!_COFF__) && _BOUT__) +_if__(! (_BOUT__ || _COFF__) ) +@node Abort, Align, Pseudo Ops, Pseudo Ops +_fi__(! (_BOUT__ || _COFF__) ) +@section @code{.abort} + +@cindex @code{abort} directive +@cindex stopping the assembly +This directive stops the assembly immediately. It is for +compatibility with other assemblers. The original idea was that the +assembly language source would be piped into the assembler. If the sender +of the source quit, it could use this directive tells @code{_AS__} to +quit also. One day @code{.abort} will not be supported. + +_if__(_COFF__) +@node coff-ABORT, Align, Abort, Pseudo Ops +@section @code{.ABORT} + +@cindex @code{ABORT} directive +When producing COFF output, @code{_AS__} accepts this directive as a +synonym for @samp{.abort}. +_fi__(_COFF__) + +_if__(_BOUT__) +_if__(!_COFF__) +@node bout-ABORT, Align, Abort, Pseudo Ops +@section @code{.ABORT} + +@cindex @code{ABORT} directive +_fi__(!_COFF__) + +When producing @code{b.out} output, @code{_AS__} accepts this directive, +but ignores it. +_fi__(_BOUT__) + +_if__( ! (_COFF__ || _BOUT__) ) +@node Align, App-File, Abort, Pseudo Ops +_fi__( ! (_COFF__ || _BOUT__) ) +_if__( _COFF__) +@node Align, App-File, coff-ABORT, Pseudo Ops +_fi__( _COFF__) +_if__( _BOUT__ && (! _COFF__)) +@node Align, App-File, bout-ABORT, Pseudo Ops +_fi__( _BOUT__ && (! _COFF__)) +@section @code{.align @var{abs-expr} , @var{abs-expr}} + +@cindex padding the location counter +@cindex advancing location counter +@cindex location counter, advancing +@cindex @code{align} directive +Pad the location counter (in the current subsection) to a particular +storage boundary. The first expression (which must be absolute) is the +number of low-order zero bits the location counter will have after +advancement. For example @samp{.align 3} will advance the location +counter until it a multiple of 8. If the location counter is already a +multiple of 8, no change is needed. + +The second expression (also absolute) gives the value to be stored in +the padding bytes. It (and the comma) may be omitted. If it is +omitted, the padding bytes are zero. + +@node App-File, Ascii, Align, Pseudo Ops +@section @code{.app-file @var{string}} + +@cindex logical file name +@cindex file name, logical +@cindex @code{app-file} directive +@code{.app-file} +_if__(!_A29K__) +(which may also be spelled @samp{.file}) +_fi__(!_A29K__) +tells @code{_AS__} that we are about to start a new +logical file. @var{string} is the new file name. In general, the +filename is recognized whether or not it is surrounded by quotes @samp{"}; +but if you wish to specify an empty file name is permitted, +you must give the quotes--@code{""}. This statement may go away in +future: it is only recognized to be compatible with old @code{_AS__} +programs.@refill + +@node Ascii, Asciz, App-File, Pseudo Ops +@section @code{.ascii "@var{string}"}@dots{} + +@cindex @code{ascii} directive +@cindex string literals +@code{.ascii} expects zero or more string literals (@pxref{Strings}) +separated by commas. It assembles each string (with no automatic +trailing zero byte) into consecutive addresses. + +@node Asciz, Byte, Ascii, Pseudo Ops +@section @code{.asciz "@var{string}"}@dots{} + +@cindex @code{asciz} directive +@cindex zero-terminated strings +@cindex null-terminated strings +@code{.asciz} is just like @code{.ascii}, but each string is followed by +a zero byte. The ``z'' in @samp{.asciz} stands for ``zero''. + +@node Byte, Comm, Asciz, Pseudo Ops +@section @code{.byte @var{expressions}} + +@cindex @code{byte} directive +@cindex integers, one byte +@code{.byte} expects zero or more expressions, separated by commas. +Each expression is assembled into the next byte. + +@node Comm, Data, Byte, Pseudo Ops +@section @code{.comm @var{symbol} , @var{length} } + +@cindex @code{comm} directive +@cindex symbol, common +@code{.comm} declares a named common area in the bss section. Normally +@code{_LD__} reserves memory addresses for it during linking, so no partial +program defines the location of the symbol. Use @code{.comm} to tell +@code{_LD__} that it must be at least @var{length} bytes long. @code{_LD__} +will allocate space for each @code{.comm} symbol that is at least as +long as the longest @code{.comm} request in any of the partial programs +linked. @var{length} is an absolute expression. + +_if__(_COFF__ || _BOUT__) +@node Data, Def, Comm, Pseudo Ops +_fi__(_COFF__ || _BOUT__) +_if__(!(_COFF__ || _BOUT__) && _AOUT__) +@node Data, Desc, Comm, Pseudo Ops +_fi__(!(_COFF__ || _BOUT__) && _AOUT__) +_if__(! (_COFF__ || _BOUT__ || _AOUT__) ) +@c Well, this *might* happen... +@node Data, Double, Comm, Pseudo Ops +_fi__(! (_COFF__ || _BOUT__ || _AOUT__) ) +@section @code{.data @var{subsection}} + +@cindex @code{data} directive +@code{.data} tells @code{_AS__} to assemble the following statements onto the +end of the data subsection numbered @var{subsection} (which is an +absolute expression). If @var{subsection} is omitted, it defaults +to zero. + +_if__(_COFF__ || _BOUT__) +_if__(_AOUT__ || _BOUT__) +@node Def, Desc, Data, Pseudo Ops +_fi__(_AOUT__ || _BOUT__) +_if__(!(_AOUT__ || _BOUT__)) +@node Def, Dim, Data, Pseudo Ops +_fi__(!(_AOUT__ || _BOUT__)) +@section @code{.def @var{name}} + +@cindex @code{def} directive +@cindex COFF symbols, debugging +@cindex debugging COFF symbols +Begin defining debugging information for a symbol @var{name}; the +definition extends until the @code{.endef} directive is encountered. +_if__(_BOUT__) + +This directive is only observed when @code{_AS__} is configured for COFF +format output; when producing @code{b.out}, @samp{.def} is recognized, +but ignored. +_fi__(_BOUT__) +_fi__(_COFF__ || _BOUT__) + +_if__(_AOUT__||_BOUT__) +_if__(_COFF__||_BOUT__) +@node Desc, Dim, Def, Pseudo Ops +_fi__(_COFF__||_BOUT__) +_if__(!(_COFF__||_BOUT__)) +@node Desc, Double, Data, Pseudo Ops +_fi__(!(_COFF__||_BOUT__)) +@section @code{.desc @var{symbol}, @var{abs-expression}} + +@cindex @code{desc} directive +@cindex COFF symbol descriptor +@cindex symbol descriptor, COFF +This directive sets the descriptor of the symbol (@pxref{Symbol Attributes}) +to the low 16 bits of an absolute expression. + +_if__(_COFF__) +The @samp{.desc} directive is not available when @code{_AS__} is +configured for COFF output; it is only for @code{a.out} or @code{b.out} +object format. For the sake of compatibility, @code{_AS__} will accept +it, but produce no output, when configured for COFF. +_fi__(_COFF__) +_fi__(_AOUT__||_BOUT__) + +_if__(_COFF__ || _BOUT__) +_if__(_AOUT__ || _BOUT__) +@node Dim, Double, Desc, Pseudo Ops +_fi__(_AOUT__ || _BOUT__) +_if__(!(_AOUT__ || _BOUT__)) +@node Dim, Double, Def, Pseudo Ops +_fi__(!(_AOUT__ || _BOUT__)) +@section @code{.dim} + +@cindex @code{dim} directive +@cindex COFF auxiliary symbol information +@cindex auxiliary symbol information, COFF +This directive is generated by compilers to include auxiliary debugging +information in the symbol table. It is only permitted inside +@code{.def}/@code{.endef} pairs. +_if__(_BOUT__) + +@samp{.dim} is only meaningful when generating COFF format output; when +@code{_AS__} is generating @code{b.out}, it accepts this directive but +ignores it. +_fi__(_BOUT__) +_fi__(_COFF__ || _BOUT__) + +_if__(_COFF__||_BOUT__) +@node Double, Eject, Dim, Pseudo Ops +_fi__(_COFF__||_BOUT__) +_if__(!(_COFF__||_BOUT__)) +@node Double, Eject, Desc, Pseudo Ops +_fi__(!(_COFF__||_BOUT__)) +@section @code{.double @var{flonums}} + +@cindex @code{double} directive +@cindex floating point numbers (double) +@code{.double} expects zero or more flonums, separated by commas. It +assembles floating point numbers. +_if__(_GENERIC__) +The exact kind of floating point numbers emitted depends on how +@code{_AS__} is configured. @xref{_MACH_DEP__}. +_fi__(_GENERIC__) +_if__((!_GENERIC__) && _IEEEFLOAT__) +On the _HOST__ family @samp{.double} emits 64-bit floating-point numbers +in @sc{ieee} format. +_fi__((!_GENERIC__) && _IEEEFLOAT__) + +@node Eject, Else, Double, Pseudo Ops +@section @code{.eject} + +@cindex @code{eject} directive +@cindex new page, in listings +@cindex page, in listings +@cindex listing control: new page +Force a page break at this point, when generating assembly listings. + +_if__(_COFF__||_BOUT__) +@node Else, Endef, Eject, Pseudo Ops +_fi__(_COFF__||_BOUT__) +_if__(!(_COFF__||_BOUT__)) +@node Else, Endif, Eject, Pseudo Ops +_fi__(!(_COFF__||_BOUT__)) +@section @code{.else} + +@cindex @code{else} directive +@code{.else} is part of the @code{_AS__} support for conditional +assembly; @pxref{If,,@code{.if}}. It marks the beginning of a section +of code to be assembled if the condition for the preceding @code{.if} +was false. + +_if__(0) +@node End, Endef, Else, Pseudo Ops +@section @code{.end} + +@cindex @code{end} directive +This doesn't do anything---but isn't an s_ignore, so I suspect it's +meant to do something eventually (which is why it isn't documented here +as "for compatibility with blah"). +_fi__(0) + +_if__(_COFF__||_BOUT__) +@node Endef, Endif, Else, Pseudo Ops +@section @code{.endef} + +@cindex @code{endef} directive +This directive flags the end of a symbol definition begun with +@code{.def}. +_if__(_BOUT__) + +@samp{.endef} is only meaningful when generating COFF format output; if +@code{_AS__} is configured to generate @code{b.out}, it accepts this +directive but ignores it. +_fi__(_BOUT__) +_fi__(_COFF__||_BOUT__) + +_if__(_COFF__||_BOUT__) +@node Endif, Equ, Endef, Pseudo Ops +_fi__(_COFF__||_BOUT__) +_if__(!(_COFF__||_BOUT__)) +@node Endif, Equ, Else, Pseudo Ops +_fi__(!(_COFF__||_BOUT__)) +@section @code{.endif} + +@cindex @code{endif} directive +@code{.endif} is part of the @code{_AS__} support for conditional assembly; +it marks the end of a block of code that is only assembled +conditionally. @xref{If,,@code{.if}}. + +@node Equ, Extern, Endif, Pseudo Ops +@section @code{.equ @var{symbol}, @var{expression}} + +@cindex @code{equ} directive +@cindex assigning values to symbols +@cindex symbols, assigning values to +This directive sets the value of @var{symbol} to @var{expression}. +It is synonymous with @samp{.set}; @pxref{Set,,@code{.set}}. + +_if__(_GENERIC__||!_A29K__) +@node Extern, File, Equ, Pseudo Ops +_fi__(_GENERIC__||!_A29K__) +_if__(_A29K__&&!_GENERIC__) +@node Extern, Fill, Equ, Pseudo Ops +_fi__(_A29K__&&!_GENERIC__) +@section @code{.extern} + +@cindex @code{extern} directive +@code{.extern} is accepted in the source program---for compatibility +with other assemblers---but it is ignored. @code{_AS__} treats +all undefined symbols as external. + +_if__(_GENERIC__||!_A29K__) +@node File, Fill, Extern, Pseudo Ops +@section @code{.file @var{string}} + +@cindex @code{file} directive +@cindex logical file name +@cindex file name, logical +@code{.file} (which may also be spelled @samp{.app-file}) tells +@code{_AS__} that we are about to start a new logical file. +@var{string} is the new file name. In general, the filename is +recognized whether or not it is surrounded by quotes @samp{"}; but if +you wish to specify an empty file name, you must give the +quotes--@code{""}. This statement may go away in future: it is only +recognized to be compatible with old @code{_AS__} programs. +_if__(_A29K__) +In some configurations of @code{_AS__}, @code{.file} has already been +removed to avoid conflicts with other assemblers. @xref{_MACH_DEP__}. +_fi__(_A29K__) +_fi__(_GENERIC__||!_A29K__) + +_if__(_GENERIC__||!_A29K__) +@node Fill, Float, File, Pseudo Ops +_fi__(_GENERIC__||!_A29K__) +_if__(_A29K__&&!_GENERIC__) +@node Fill, Float, Extern, Pseudo Ops +_fi__(_A29K__&&!_GENERIC__) +@section @code{.fill @var{repeat} , @var{size} , @var{value}} + +@cindex @code{fill} directive +@cindex writing patterns in memory +@cindex patterns, writing in memory +@var{result}, @var{size} and @var{value} are absolute expressions. +This emits @var{repeat} copies of @var{size} bytes. @var{Repeat} +may be zero or more. @var{Size} may be zero or more, but if it is +more than 8, then it is deemed to have the value 8, compatible with +other people's assemblers. The contents of each @var{repeat} bytes +is taken from an 8-byte number. The highest order 4 bytes are +zero. The lowest order 4 bytes are @var{value} rendered in the +byte-order of an integer on the computer @code{_AS__} is assembling for. +Each @var{size} bytes in a repetition is taken from the lowest order +@var{size} bytes of this number. Again, this bizarre behavior is +compatible with other people's assemblers. + +@var{size} and @var{value} are optional. +If the second comma and @var{value} are absent, @var{value} is +assumed zero. If the first comma and following tokens are absent, +@var{size} is assumed to be 1. + +@node Float, Global, Fill, Pseudo Ops +@section @code{.float @var{flonums}} + +@cindex floating point numbers (single) +@cindex @code{float} directive +This directive assembles zero or more flonums, separated by commas. It +has the same effect as @code{.single}. +_if__(_GENERIC__) +The exact kind of floating point numbers emitted depends on how +@code{_AS__} is configured. +@xref{_MACH_DEP__}. +_fi__(_GENERIC__) +_if__((!_GENERIC__) && _IEEEFLOAT__) +On the _HOST__ family, @code{.float} emits 32-bit floating point numbers +in @sc{ieee} format. +_fi__((!_GENERIC__) && _IEEEFLOAT__) + +@node Global, hword, Float, Pseudo Ops +@section @code{.global @var{symbol}}, @code{.globl @var{symbol}} + +@cindex @code{global} directive +@cindex symbol, making visible to linker +@code{.global} makes the symbol visible to @code{_LD__}. If you define +@var{symbol} in your partial program, its value is made available to +other partial programs that are linked with it. Otherwise, +@var{symbol} will take its attributes from a symbol of the same name +from another partial program it is linked with. + +Both spellings (@samp{.globl} and @samp{.global}) are accepted, for +compatibility with other assemblers. + +_if__(_AOUT__||_BOUT__||_COFF__) +@node hword, Ident, Global, Pseudo Ops +_fi__(_AOUT__||_BOUT__||_COFF__) +_if__(!(_AOUT__||_BOUT__||_COFF__)) +@node hword, If, Global, Pseudo Ops +_fi__(!(_AOUT__||_BOUT__||_COFF__)) +@section @code{.hword @var{expressions}} + +@cindex @code{hword} directive +@cindex integers, 16-bit +@cindex numbers, 16-bit +@cindex sixteen bit integers +This expects zero or more @var{expressions}, and emits +a 16 bit number for each. + +_if__(_GENERIC__) +This directive is a synonym for @samp{.short}; depending on the target +architecture, it may also be a synonym for @samp{.word}. +_fi__(_GENERIC__) +_if__( _W32__ && !_GENERIC__ ) +This directive is a synonym for @samp{.short}. +_fi__( _W32__ && !_GENERIC__ ) +_if__(_W16__ && !_GENERIC__ ) +This directive is a synonym for both @samp{.short} and @samp{.word}. +_fi__(_W16__ && !_GENERIC__ ) + +_if__(_AOUT__||_BOUT__||_COFF__) +@node Ident, If, hword, Pseudo Ops +@section @code{.ident} + +@cindex @code{ident} directive +This directive is used by some assemblers to place tags in object files. +@code{_AS__} simply accepts the directive for source-file +compatibility with such assemblers, but does not actually emit anything +for it. +_fi__(_AOUT__||_BOUT__||_COFF__) + +_if__(_AOUT__||_BOUT__||_COFF__) +@node If, Include, Ident, Pseudo Ops +_fi__(_AOUT__||_BOUT__||_COFF__) +_if__(!(_AOUT__||_BOUT__||_COFF__)) +@node If, Include, hword, Pseudo Ops +_fi__(!(_AOUT__||_BOUT__||_COFF__)) +@section @code{.if @var{absolute expression}} + +@cindex conditional assembly +@cindex @code{if} directive +@code{.if} marks the beginning of a section of code which is only +considered part of the source program being assembled if the argument +(which must be an @var{absolute expression}) is non-zero. The end of +the conditional section of code must be marked by @code{.endif} +(@pxref{Endif,,@code{.endif}}); optionally, you may include code for the +alternative condition, flagged by @code{.else} (@pxref{Else,,@code{.else}}. + +The following variants of @code{.if} are also supported: +@table @code +@item .ifdef @var{symbol} +@cindex @code{ifdef} directive +Assembles the following section of code if the specified @var{symbol} +has been defined. + +_if__(0) +@item .ifeqs +@cindex @code{ifeqs} directive +Not yet implemented. +_fi__(0) + +@item .ifndef @var{symbol} +@itemx ifnotdef @var{symbol} +@cindex @code{ifndef} directive +@cindex @code{ifnotdef} directive +Assembles the following section of code if the specified @var{symbol} +has not been defined. Both spelling variants are equivalent. + +_if__(0) +@item ifnes +Not yet implemented. +_fi__(0) +@end table + +@node Include, Int, If, Pseudo Ops +@section @code{.include "@var{file}"} + +@cindex @code{include} directive +@cindex supporting files, including +@cindex files, including +This directive provides a way to include supporting files at specified +points in your source program. The code from @var{file} is assembled as +if it followed the point of the @code{.include}; when the end of the +included file is reached, assembly of the original file continues. You +can control the search paths used with the @samp{-I} command-line option +(@pxref{Invoking,,Command-Line Options}). Quotation marks are required +around @var{file}. + +@node Int, Lcomm, Include, Pseudo Ops +@section @code{.int @var{expressions}} + +@cindex @code{int} directive +_if__(_GENERIC__||!_H8__) +@cindex integers, 32-bit +_fi__(_GENERIC__||!_H8__) +Expect zero or more @var{expressions}, of any section, separated by +commas. For each expression, emit a +_if__(_GENERIC__||!_H8__) +32-bit +_fi__(_GENERIC__||!_H8__) +_if__(_H8__&&!_GENERIC__) +16-bit +_fi__(_H8__&&!_GENERIC__) +number that will, at run +time, be the value of that expression. The byte order of the +expression depends on what kind of computer will run the program. + +@node Lcomm, Lflags, Int, Pseudo Ops +@section @code{.lcomm @var{symbol} , @var{length}} + +@cindex @code{lcomm} directive +@cindex local common symbols +@cindex symbols, local common +Reserve @var{length} (an absolute expression) bytes for a local common +denoted by @var{symbol}. The section and value of @var{symbol} are +those of the new local common. The addresses are allocated in the bss +section, so at run-time the bytes will start off zeroed. @var{Symbol} +is not declared global (@pxref{Global,,@code{.global}}), so is normally +not visible to @code{_LD__}. + +_if__(_GENERIC__||(!_A29K__)) +@node Lflags, Line, Lcomm, Pseudo Ops +_fi__(_GENERIC__||(!_A29K__)) +_if__((!_GENERIC__)&& _A29K__) +@node Lflags, Ln, Lcomm, Pseudo Ops +_fi__((!_GENERIC__)&& _A29K__) +@section @code{.lflags} + +@cindex @code{lflags} directive (ignored) +@code{_AS__} accepts this directive, for compatibility with other +assemblers, but ignores it. + +_if__(_GENERIC__ || !_A29K__) +@node Line, Ln, Lflags, Pseudo Ops +@section @code{.line @var{line-number}} + +@cindex @code{line} directive +_fi__(_GENERIC__ || (!_A29K__)) +_if__(_A29K__ && (!_GENERIC__)) +@node Ln, List, Lflags, Pseudo Ops +@section @code{.ln @var{line-number}} + +@cindex @code{ln} directive +_fi__(_A29K__ && (!_GENERIC__)) +@cindex logical line number +_if__(_AOUT__||_BOUT__) +Tell @code{_AS__} to change the logical line number. @var{line-number} must be +an absolute expression. The next line will have that logical line +number. So any other statements on the current line (after a statement +separator +_if__(_GENERIC__) +character) +_fi__(_GENERIC__) +_if__(!_GENERIC__) +_if__(! (_A29K__||_H8__) ) +character @code{;}) +_fi__(! (_A29K__||_H8__) ) +_if__(_A29K__) +character @samp{@@}) +_fi__(_A29K__) +_if__(_H8__) +character @samp{$}) +_fi__(_H8__) +_fi__(!_GENERIC__) +will be reported as on logical line number +@var{line-number} @minus{} 1. +One day this directive will be unsupported: it is used only +for compatibility with existing assembler programs. @refill + +_if__(_GENERIC__ && _A29K__) +@emph{Warning:} In the AMD29K configuration of _AS__, this command is +only available with the name @code{.ln}, rather than as either +@code{.line} or @code{.ln}. +_fi__(_GENERIC__ && _A29K__) +_fi__(_AOUT__||_BOUT__) +_if__(_COFF__) + +Even though this is a directive associated with the @code{a.out} or +@code{b.out} object-code formats, @code{_AS__} will still recognize it +when producing COFF output, and will treat @samp{.line} as though it +were the COFF @samp{.ln} @emph{if} it is found outside a +@code{.def}/@code{.endef} pair. + +Inside a @code{.def}, @samp{.line} is, instead, one of the directives +used by compilers to generate auxiliary symbol information for +debugging. +_fi__(_COFF__) + +_if__(_AOUT__&&(_GENERIC__||!_A29K__)) +@node Ln, List, Line, Pseudo Ops +@section @code{.ln @var{line-number}} + +@cindex @code{ln} directive +@samp{.ln} is a synonym for @samp{.line}. +_fi__(_AOUT__&&(_GENERIC__||!_A29K__)) +_if__(_COFF__&&!_AOUT__) +@node Ln, List, Line, Pseudo Ops +@section @code{.ln @var{line-number}} + +@cindex @code{ln} directive +Tell @code{_AS__} to change the logical line number. @var{line-number} +must be an absolute expression. The next line will have that logical +line number, so any other statements on the current line (after a +statement separator character @code{;}) will be reported as on logical +line number @var{line-number} @minus{} 1. +_if__(_BOUT__) + +This directive is accepted, but ignored, when @code{_AS__} is configured for +@code{b.out}; its effect is only associated with COFF output format. +_fi__(_BOUT__) +_fi__(_COFF__&&!_AOUT__) + +@node List, Long, Ln, Pseudo Ops +@section @code{.list} + +@cindex @code{list} directive +@cindex listing control, turning on +Control (in conjunction with the @code{.nolist} directive) whether or +not assembly listings are generated. These two directives maintain an +internal counter (which is zero initially). @code{.list} increments the +counter, and @code{.nolist} decrements it. Assembly listings are +generated whenever the counter is greater than zero. + +By default, listings are disabled. When you enable them (with the +@samp{-a} command line option; @pxref{Invoking,,Command-Line Options}), +the initial value of the listing counter is one. + +@node Long, Lsym, List, Pseudo Ops +@section @code{.long @var{expressions}} + +@cindex @code{long} directive +@code{.long} is the same as @samp{.int}, @pxref{Int,,@code{.int}}. + +@node Lsym, Nolist, Long, Pseudo Ops +@section @code{.lsym @var{symbol}, @var{expression}} + +@cindex @code{lsym} directive +@cindex symbol, not referenced in assembly +@code{.lsym} creates a new symbol named @var{symbol}, but does not put it in +the hash table, ensuring it cannot be referenced by name during the +rest of the assembly. This sets the attributes of the symbol to be +the same as the expression value: +@smallexample +@var{other} = @var{descriptor} = 0 +@var{type} = @r{(section of @var{expression})} +@var{value} = @var{expression} +@end smallexample +@noindent +The new symbol is not flagged as external. + +@node Nolist, Octa, Lsym, Pseudo Ops +@section @code{.nolist} + +@cindex @code{nolist} directive +@cindex listing control, turning off +Control (in conjunction with the @code{.list} directive) whether or +not assembly listings are generated. These two directives maintain an +internal counter (which is zero initially). @code{.list} increments the +counter, and @code{.nolist} decrements it. Assembly listings are +generated whenever the counter is greater than zero. + +@node Octa, Org, Nolist, Pseudo Ops +@section @code{.octa @var{bignums}} + +@c FIXME: double size emitted for "octa" on i960, others? Or warn? +@cindex @code{octa} directive +@cindex integer, 16-byte +@cindex sixteen byte integer +This directive expects zero or more bignums, separated by commas. For each +bignum, it emits a 16-byte integer. + +The term ``octa'' comes from contexts in which a ``word'' is two bytes; +hence @emph{octa}-word for 16 bytes. + +@node Org, Psize, Octa, Pseudo Ops +@section @code{.org @var{new-lc} , @var{fill}} + +@cindex @code{org} directive +@cindex location counter, advancing +@cindex advancing location counter +@cindex current address, advancing +@code{.org} will advance the location counter of the current section to +@var{new-lc}. @var{new-lc} is either an absolute expression or an +expression with the same section as the current subsection. That is, +you can't use @code{.org} to cross sections: if @var{new-lc} has the +wrong section, the @code{.org} directive is ignored. To be compatible +with former assemblers, if the section of @var{new-lc} is absolute, +@code{_AS__} will issue a warning, then pretend the section of @var{new-lc} +is the same as the current subsection. + +@code{.org} may only increase the location counter, or leave it +unchanged; you cannot use @code{.org} to move the location counter +backwards. + +@c double negative used below "not undefined" because this is a specific +@c reference to "undefined" (as SEG_UNKNOWN is called in this manual) +@c section. pesch@cygnus.com 18feb91 +Because @code{_AS__} tries to assemble programs in one pass @var{new-lc} +may not be undefined. If you really detest this restriction we eagerly await +a chance to share your improved assembler. + +Beware that the origin is relative to the start of the section, not +to the start of the subsection. This is compatible with other +people's assemblers. + +When the location counter (of the current subsection) is advanced, the +intervening bytes are filled with @var{fill} which should be an +absolute expression. If the comma and @var{fill} are omitted, +@var{fill} defaults to zero. + +@node Psize, Quad, Org, Pseudo Ops +@section @code{.psize @var{lines} , @var{columns}} + +@cindex @code{psize} directive +@cindex listing control: paper size +@cindex paper size, for listings +Use this directive to declare the number of lines---and, optionally, the +number of columns---to use for each page, when generating listings. + +If you don't use @code{.psize}, listings will use a default line-count +of 60. You may omit the comma and @var{columns} specification; the +default width is 200 columns. + +@code{_AS__} will generate formfeeds whenever the specified number of +lines is exceeded (or whenever you explicitly request one, using +@code{.eject}). + +If you specify @var{lines} as @code{0}, no formfeeds are generated save +those explicitly specified with @code{.eject}. + +@node Quad, Sbttl, Psize, Pseudo Ops +@section @code{.quad @var{bignums}} + +@cindex @code{quad} directive +@code{.quad} expects zero or more bignums, separated by commas. For +each bignum, it emits +_if__(_GENERIC__||(!_I960__)) +an 8-byte integer. If the bignum won't fit in 8 +bytes, it prints a warning message; and just takes the lowest order 8 +bytes of the bignum.@refill +@cindex eight-byte integer +@cindex integer, 8-byte + +The term ``quad'' comes from contexts in which a ``word'' is two bytes; +hence @emph{quad}-word for 8 bytes. +_fi__(_GENERIC__||(!_I960__)) +_if__(_I960__&&(!_GENERIC__)) +a 16-byte integer. If the bignum won't fit in 16 bytes, it prints a +warning message; and just takes the lowest order 16 bytes of the +bignum.@refill +@cindex sixteen-byte integer +@cindex integer, 16-byte +_fi__(_I960__&&(!_GENERIC__)) + +_if__(_COFF__||_BOUT__) +@node Sbttl, Scl, Quad, Pseudo Ops +_fi__(_COFF__||_BOUT__) +_if__(!(_COFF__||_BOUT__)) +@node Sbttl, Set, Quad, Pseudo Ops +_fi__(!(_COFF__||_BOUT__)) +@section @code{.sbttl "@var{subheading}"} + +@cindex @code{sbttl} directive +@cindex subtitles for listings +@cindex listing control: subtitle +Use @var{subheading} as the title (third line, immediately after the +title line) when generating assembly listings. + +This directive affects subsequent pages, as well as the current page if +it appears within ten lines of the top of a page. + +_if__(_COFF__||_BOUT__) +_if__(!_COFF__) +@node Scl, Set, Sbttl, Pseudo Ops +_fi__(!_COFF__) +_if__(_COFF__) +@node Scl, Section, Sbttl, Pseudo Ops +_fi__(_COFF__) +@section @code{.scl @var{class}} + +@cindex @code{scl} directive +@cindex symbol storage class (COFF) +@cindex COFF symbol storage class +Set the storage-class value for a symbol. This directive may only be +used inside a @code{.def}/@code{.endef} pair. Storage class may flag +whether a symbol is static or external, or it may record further +symbolic debugging information. +_if__(_BOUT__) + +The @samp{.scl} directive is primarily associated with COFF output; when +configured to generate @code{b.out} output format, @code{_AS__} will +accept this directive but ignore it. +_fi__(_BOUT__) +_fi__(_COFF__||_BOUT__) + +_if__(_COFF__) +@node Section, Set, Scl, Pseudo Ops +@section @code{.section @var{name}, @var{subsection}} + +@cindex @code{section} directive +@cindex named section (COFF) +@cindex COFF named section +Assemble the following code into end of subsection numbered +@var{subsection} in the COFF named section @var{name}. If you omit +@var{subsection}, @code{_AS__} uses subsection number zero. +@samp{.section .text} is equivalent to the @code{.text} directive; +@samp{.section .data} is equivalent to the @code{.data} directive. + +@node Set, Short, Section, Pseudo Ops +_fi__(_COFF__) +_if__(_BOUT__&&!_COFF__) +@node Set, Short, Scl, Pseudo Ops +_fi__(_BOUT__&&!_COFF__) +_if__(!(_COFF__||_BOUT__)) +@node Set, Short, Quad, Pseudo Ops +_fi__(!(_COFF__||_BOUT__)) +@section @code{.set @var{symbol}, @var{expression}} + +@cindex @code{set} directive +@cindex symbol value, setting +This directive sets the value of @var{symbol} to @var{expression}. This +will change @var{symbol}'s value and type to conform to +@var{expression}. If @var{symbol} was flagged as external, it remains +flagged. (@xref{Symbol Attributes}.) + +You may @code{.set} a symbol many times in the same assembly. +If the expression's section is unknowable during pass 1, a second +pass over the source program will be forced. The second pass is +currently not implemented. @code{_AS__} will abort with an error +message if one is required. + +If you @code{.set} a global symbol, the value stored in the object +file is the last value stored into it. + +@node Short, Single, Set, Pseudo Ops +@section @code{.short @var{expressions}} + +@cindex @code{short} directive +_if__(_GENERIC__ || _W16__) +@code{.short} is the same as @samp{.word}. @xref{Word,,@code{.word}}. +_if__(_W32__) +In some configurations, however, @code{.short} and @code{.word} generate +numbers of different lengths; @pxref{_MACH_DEP__}. +_fi__(_W32__) +_fi__(_GENERIC__|| _W16__) +_if__((!_GENERIC__) && _W32__) +This expects zero or more @var{expressions}, and emits +a 16 bit number for each. +_fi__((!_GENERIC__) && _W32__) +_if__(_COFF__||_BOUT__) +@node Single, Size, Short, Pseudo Ops +_fi__(_COFF__||_BOUT__) +_if__(!(_COFF__||_BOUT__)) +@node Single, Space, Short, Pseudo Ops +_fi__(!(_COFF__||_BOUT__)) +@section @code{.single @var{flonums}} + +@cindex @code{single} directive +@cindex floating point numbers (single) +This directive assembles zero or more flonums, separated by commas. It +has the same effect as @code{.float}. +_if__(_GENERIC__) +The exact kind of floating point numbers emitted depends on how +@code{_AS__} is configured. @xref{_MACH_DEP__}. +_fi__(_GENERIC__) +_if__((!_GENERIC__) && _IEEEFLOAT__) +On the _HOST__ family, @code{.single} emits 32-bit floating point +numbers in @sc{ieee} format. +_fi__((!_GENERIC__) && _IEEEFLOAT__) + +_if__(_COFF__||_BOUT__) +@node Size, Space, Single, Pseudo Ops +@section @code{.size} + +@cindex @code{size} directive +This directive is generated by compilers to include auxiliary debugging +information in the symbol table. It is only permitted inside +@code{.def}/@code{.endef} pairs. +_if__(_BOUT__) + +@samp{.size} is only meaningful when generating COFF format output; when +@code{_AS__} is generating @code{b.out}, it accepts this directive but +ignores it. +_fi__(_BOUT__) +_fi__(_COFF__||_BOUT__) + +_if__(_H8__&&!_GENERIC__) +@node Space, Tag, Size, Pseudo Ops +_fi__(_H8__&&!_GENERIC__) +_if__(_GENERIC__||!_H8__) +_if__(_COFF__||_BOUT__) +@node Space, Stab, Size, Pseudo Ops +_fi__(_COFF__||_BOUT__) +_if__(!(_COFF__||_BOUT__)) +@node Space, Stab, Single, Pseudo Ops +_fi__(!(_COFF__||_BOUT__)) +_fi__(_GENERIC__||!_H8__) +_if__(_GENERIC__ || !_A29K__) +@section @code{.space @var{size} , @var{fill}} + +@cindex @code{space} directive +@cindex filling memory +This directive emits @var{size} bytes, each of value @var{fill}. Both +@var{size} and @var{fill} are absolute expressions. If the comma +and @var{fill} are omitted, @var{fill} is assumed to be zero. +_fi__(_GENERIC__ || !_A29K__) + +_if__(_A29K__) +@section @code{.space} + +@cindex @code{space} directive +On the AMD 29K, this directive is ignored; it is accepted for +compatibility with other AMD 29K assemblers. + +@quotation +@emph{Warning:} In other versions of the GNU assembler, the directive +@code{.space} has the effect of @code{.block} @xref{_MACH_DEP__}. +@end quotation +_fi__(_A29K__) + +_if__(_GENERIC__||!_H8__) +_if__(_AOUT__||_BOUT__||_COFF__) +_if__(_COFF__||_BOUT__) +@node Stab, Tag, Space, Pseudo Ops +_fi__(_COFF__||_BOUT__) +_if__(!(_COFF__||_BOUT__)) +@node Stab, Text, Space, Pseudo Ops +_fi__(!(_COFF__||_BOUT__)) +@section @code{.stabd, .stabn, .stabs} + +@cindex symbolic debuggers, information for +@cindex @code{stab@var{x}} directives +There are three directives that begin @samp{.stab}. +All emit symbols (@pxref{Symbols}), for use by symbolic debuggers. +The symbols are not entered in the @code{_AS__} hash table: they +cannot be referenced elsewhere in the source file. +Up to five fields are required: +@table @var +@item string +This is the symbol's name. It may contain any character except @samp{\000}, +so is more general than ordinary symbol names. Some debuggers used to +code arbitrarily complex structures into symbol names using this field. +@item type +An absolute expression. The symbol's type is set to the low 8 +bits of this expression. +Any bit pattern is permitted, but @code{_LD__} and debuggers will choke on +silly bit patterns. +@item other +An absolute expression. +The symbol's ``other'' attribute is set to the low 8 bits of this expression. +@item desc +An absolute expression. +The symbol's descriptor is set to the low 16 bits of this expression. +@item value +An absolute expression which becomes the symbol's value. +@end table + +If a warning is detected while reading a @code{.stabd}, @code{.stabn}, +or @code{.stabs} statement, the symbol has probably already been created +and you will get a half-formed symbol in your object file. This is +compatible with earlier assemblers! + +@table @code +@cindex @code{stabd} directive +@item .stabd @var{type} , @var{other} , @var{desc} + +The ``name'' of the symbol generated is not even an empty string. +It is a null pointer, for compatibility. Older assemblers used a +null pointer so they didn't waste space in object files with empty +strings. + +The symbol's value is set to the location counter, +relocatably. When your program is linked, the value of this symbol +will be where the location counter was when the @code{.stabd} was +assembled. + +@item .stabn @var{type} , @var{other} , @var{desc} , @var{value} +@cindex @code{stabn} directive +The name of the symbol is set to the empty string @code{""}. + +@item .stabs @var{string} , @var{type} , @var{other} , @var{desc} , @var{value} +@cindex @code{stabs} directive +All five fields are specified. +@end table +_fi__(_AOUT__||_BOUT__||_COFF__) +_fi__(_GENERIC__||!_H8__) + +_if__(_COFF__||_BOUT__) +_if__(_GENERIC__||!_H8__) +@node Tag, Text, Stab, Pseudo Ops +_fi__(_GENERIC__||!_H8__) +_if__(_H8__&&!_GENERIC__) +@node Tag, Text, Space, Pseudo Ops +_fi__(_H8__&&!_GENERIC__) +@section @code{.tag @var{structname}} + +@cindex COFF structure debugging +@cindex structure debugging, COFF +@cindex @code{tag} directive +This directive is generated by compilers to include auxiliary debugging +information in the symbol table. It is only permitted inside +@code{.def}/@code{.endef} pairs. Tags are used to link structure +definitions in the symbol table with instances of those structures. +_if__(_BOUT__) + +@samp{.tag} is only used when generating COFF format output; when +@code{_AS__} is generating @code{b.out}, it accepts this directive but +ignores it. +_fi__(_BOUT__) +_fi__(_COFF__||_BOUT__) + +_if__(_COFF__||_BOUT__) +@node Text, Title, Tag, Pseudo Ops +_fi__(_COFF__||_BOUT__) +_if__(!(_COFF__||_BOUT__)) +@node Text, Title, Stab, Pseudo Ops +_fi__(!(_COFF__||_BOUT__)) +@section @code{.text @var{subsection}} + +@cindex @code{text} directive +Tells @code{_AS__} to assemble the following statements onto the end of +the text subsection numbered @var{subsection}, which is an absolute +expression. If @var{subsection} is omitted, subsection number zero +is used. + +_if__(_COFF__||_BOUT__) +@node Title, Type, Text, Pseudo Ops +_fi__(_COFF__||_BOUT__) +_if__(!(_COFF__||_BOUT__)) +@node Title, Word, Text, Pseudo Ops +_fi__(!(_COFF__||_BOUT__)) +@section @code{.title "@var{heading}"} + +@cindex @code{title} directive +@cindex listing control: title line +Use @var{heading} as the title (second line, immediately after the +source file name and pagenumber) when generating assembly listings. + +This directive affects subsequent pages, as well as the current page if +it appears within ten lines of the top of a page. + +_if__(_COFF__||_BOUT__) +@node Type, Val, Title, Pseudo Ops +@section @code{.type @var{int}} + +@cindex COFF symbol type +@cindex symbol type, COFF +@cindex @code{type} directive +This directive, permitted only within @code{.def}/@code{.endef} pairs, +records the integer @var{int} as the type attribute of a symbol table entry. +_if__(_BOUT__) + +@samp{.type} is associated only with COFF format output; when +@code{_AS__} is configured for @code{b.out} output, it accepts this +directive but ignores it. +_fi__(_BOUT__) +_fi__(_COFF__||_BOUT__) + +_if__(_COFF__||_BOUT__) +@node Val, Word, Type, Pseudo Ops +@section @code{.val @var{addr}} + +@cindex @code{val} directive +@cindex COFF value attribute +@cindex value attribute, COFF +This directive, permitted only within @code{.def}/@code{.endef} pairs, +records the address @var{addr} as the value attribute of a symbol table +entry. +_if__(_BOUT__) + +@samp{.val} is used only for COFF output; when @code{_AS__} is +configured for @code{b.out}, it accepts this directive but ignores it. +_fi__(_BOUT__) +_fi__(_COFF__||_BOUT__) + +_if__(_COFF__||_BOUT__) +@node Word, Deprecated, Val, Pseudo Ops +_fi__(_COFF__||_BOUT__) +_if__(!(_COFF__||_BOUT__)) +@node Word, Deprecated, Text, Pseudo Ops +_fi__(!(_COFF__||_BOUT__)) +@section @code{.word @var{expressions}} + +@cindex @code{word} directive +This directive expects zero or more @var{expressions}, of any section, +separated by commas. +_if__((!_GENERIC__) && _W32__) +For each expression, @code{_AS__} emits a 32-bit number. +_fi__((!_GENERIC__) && _W32__) +_if__((!_GENERIC__) && _W16__) +For each expression, @code{_AS__} emits a 16-bit number. +_fi__((!_GENERIC__) && _W16__) + +_if__(_GENERIC__) +The size of the number emitted, and its byte order, +depends on what kind of computer will run the program. +_fi__(_GENERIC__) + +@c on amd29k, i960, sparc the "special treatment to support compilers" doesn't +@c happen---32-bit addressability, period; no long/short jumps. +_if__(_GENERIC__ || _DIFFTABKLUG__) +@cindex difference tables altered +@cindex altered difference tables +@quotation +@emph{Warning: Special Treatment to support Compilers} +@end quotation + +_if__(_GENERIC__) +Machines with a 32-bit address space, but that do less than 32-bit +addressing, require the following special treatment. If the machine of +interest to you does 32-bit addressing (or doesn't require it; +@pxref{_MACH_DEP__}), you can ignore this issue. + +_fi__(_GENERIC__) +In order to assemble compiler output into something that will work, +@code{_AS__} will occasionlly do strange things to @samp{.word} directives. +Directives of the form @samp{.word sym1-sym2} are often emitted by +compilers as part of jump tables. Therefore, when @code{_AS__} assembles a +directive of the form @samp{.word sym1-sym2}, and the difference between +@code{sym1} and @code{sym2} does not fit in 16 bits, @code{_AS__} will +create a @dfn{secondary jump table}, immediately before the next label. +This secondary jump table will be preceded by a short-jump to the +first byte after the secondary table. This short-jump prevents the flow +of control from accidentally falling into the new table. Inside the +table will be a long-jump to @code{sym2}. The original @samp{.word} +will contain @code{sym1} minus the address of the long-jump to +@code{sym2}. + +If there were several occurrences of @samp{.word sym1-sym2} before the +secondary jump table, all of them will be adjusted. If there was a +@samp{.word sym3-sym4}, that also did not fit in sixteen bits, a +long-jump to @code{sym4} will be included in the secondary jump table, +and the @code{.word} directives will be adjusted to contain @code{sym3} +minus the address of the long-jump to @code{sym4}; and so on, for as many +entries in the original jump table as necessary. + +_if__(_INTERNALS__) +@emph{This feature may be disabled by compiling @code{_AS__} with the +@samp{-DWORKING_DOT_WORD} option.} This feature is likely to confuse +assembly language programmers. +_fi__(_INTERNALS__) +_fi__(_GENERIC__ || _DIFFTABKLUG__) + +@node Deprecated, , Word, Pseudo Ops +@section Deprecated Directives + +@cindex deprecated directives +@cindex obsolescent directives +One day these directives won't work. +They are included for compatibility with older assemblers. +@table @t +@item .abort +@item .app-file +@item .line +@end table + +@node _MACH_DEP__, Copying, Pseudo Ops, Top +_if__(_GENERIC__) +@chapter Machine Dependent Features + +@cindex machine dependencies +The machine instruction sets are (almost by definition) different on +each machine where @code{_AS__} runs. Floating point representations +vary as well, and @code{_AS__} often supports a few additional +directives or command-line options for compatibility with other +assemblers on a particular platform. Finally, some versions of +@code{_AS__} support special pseudo-instructions for branch +optimization. + +This chapter discusses most of these differences, though it does not +include details on any machine's instruction set. For details on that +subject, see the hardware manufacturer's manual. + +@menu +_if__(_VAX__) +* Vax-Dependent:: VAX Dependent Features +_fi__(_VAX__) +_if__(_A29K__) +* AMD29K-Dependent:: AMD 29K Dependent Features +_fi__(_A29K__) +_if__(_H8__) +* H8/300-Dependent:: AMD 29K Dependent Features +_fi__(_H8__) +_if__(_I960__) +* i960-Dependent:: Intel 80960 Dependent Features +_fi__(_I960__) +_if__(_M680X0__) +* M68K-Dependent:: M680x0 Dependent Features +_fi__(_M680X0__) +_if__(_SPARC__) +* Sparc-Dependent:: SPARC Dependent Features +_fi__(_SPARC__) +_if__(_I80386__) +* i386-Dependent:: 80386 Dependent Features +_fi__(_I80386__) +@end menu + +_fi__(_GENERIC__) +_if__(_VAX__) +_if__(_GENERIC__) +@node Vax-Dependent, AMD29K-Dependent, Machine Dependent, Machine Dependent +_fi__(_GENERIC__) +_CHAPSEC__(0+_GENERIC__) VAX Dependent Features + +@cindex VAX support +@menu +* Vax-Opts:: VAX Command-Line Options +* VAX-float:: VAX Floating Point +* VAX-directives:: Vax Machine Directives +* VAX-opcodes:: VAX Opcodes +* VAX-branch:: VAX Branch Improvement +* VAX-operands:: VAX Operands +* VAX-no:: Not Supported on VAX +@end menu + +@node Vax-Opts, VAX-float, Vax-Dependent, Vax-Dependent +_CHAPSEC__(1+_GENERIC__) VAX Command-Line Options + +@cindex command-line options ignored, VAX +@cindex VAX command-line options ignored +The Vax version of @code{_AS__} accepts any of the following options, +gives a warning message that the option was ignored and proceeds. +These options are for compatibility with scripts designed for other +people's assemblers. + +@table @asis +@item @kbd{-D} (Debug) +@itemx @kbd{-S} (Symbol Table) +@itemx @kbd{-T} (Token Trace) +@cindex @code{-D}, ignored on VAX +@cindex @code{-S}, ignored on VAX +@cindex @code{-T}, ignored on VAX +These are obsolete options used to debug old assemblers. + +@item @kbd{-d} (Displacement size for JUMPs) +@cindex @code{-d}, VAX option +This option expects a number following the @kbd{-d}. Like options +that expect filenames, the number may immediately follow the +@kbd{-d} (old standard) or constitute the whole of the command line +argument that follows @kbd{-d} (GNU standard). + +@item @kbd{-V} (Virtualize Interpass Temporary File) +@cindex @code{-V}, redundant on VAX +Some other assemblers use a temporary file. This option +commanded them to keep the information in active memory rather +than in a disk file. @code{_AS__} always does this, so this +option is redundant. + +@item @kbd{-J} (JUMPify Longer Branches) +@cindex @code{-J}, ignored on VAX +Many 32-bit computers permit a variety of branch instructions +to do the same job. Some of these instructions are short (and +fast) but have a limited range; others are long (and slow) but +can branch anywhere in virtual memory. Often there are 3 +flavors of branch: short, medium and long. Some other +assemblers would emit short and medium branches, unless told by +this option to emit short and long branches. + +@item @kbd{-t} (Temporary File Directory) +@cindex @code{-t}, ignored on VAX +Some other assemblers may use a temporary file, and this option +takes a filename being the directory to site the temporary +file. @code{_AS__} does not use a temporary disk file, so this +option makes no difference. @kbd{-t} needs exactly one +filename. +@end table + +@cindex VMS (VAX) options +@cindex options for VAX/VMS +@cindex VAX/VMS options +@cindex @code{-h} option, VAX/VMS +@cindex @code{-+} option, VAX/VMS +@cindex Vax-11 C compatibility +@cindex symbols with lowercase, VAX/VMS +@c FIXME! look into "I think" below, correct if needed, delete. +The Vax version of the assembler accepts two options when +compiled for VMS. They are @kbd{-h}, and @kbd{-+}. The +@kbd{-h} option prevents @code{_AS__} from modifying the +symbol-table entries for symbols that contain lowercase +characters (I think). The @kbd{-+} option causes @code{_AS__} to +print warning messages if the FILENAME part of the object file, +or any symbol name is larger than 31 characters. The @kbd{-+} +option also insertes some code following the @samp{_main} +symbol so that the object file will be compatible with Vax-11 +"C". + +@node VAX-float, VAX-directives, Vax-Opts, Vax-Dependent +_CHAPSEC__(1+_GENERIC__) VAX Floating Point + +@cindex VAX floating point +@cindex floating point, VAX +Conversion of flonums to floating point is correct, and +compatible with previous assemblers. Rounding is +towards zero if the remainder is exactly half the least significant bit. + +@code{D}, @code{F}, @code{G} and @code{H} floating point formats +are understood. + +Immediate floating literals (@emph{e.g.} @samp{S`$6.9}) +are rendered correctly. Again, rounding is towards zero in the +boundary case. + +@cindex @code{float} directive, VAX +@cindex @code{double} directive, VAX +The @code{.float} directive produces @code{f} format numbers. +The @code{.double} directive produces @code{d} format numbers. + +@node VAX-directives, VAX-opcodes, VAX-float, Vax-Dependent +_CHAPSEC__(1+_GENERIC__) Vax Machine Directives + +@cindex machine directives, VAX +@cindex VAX machine directives +The Vax version of the assembler supports four directives for +generating Vax floating point constants. They are described in the +table below. + +@cindex wide floating point directives, VAX +@table @code +@item .dfloat +@cindex @code{dfloat} directive, VAX +This expects zero or more flonums, separated by commas, and +assembles Vax @code{d} format 64-bit floating point constants. + +@item .ffloat +@cindex @code{ffloat} directive, VAX +This expects zero or more flonums, separated by commas, and +assembles Vax @code{f} format 32-bit floating point constants. + +@item .gfloat +@cindex @code{gfloat} directive, VAX +This expects zero or more flonums, separated by commas, and +assembles Vax @code{g} format 64-bit floating point constants. + +@item .hfloat +@cindex @code{hfloat} directive, VAX +This expects zero or more flonums, separated by commas, and +assembles Vax @code{h} format 128-bit floating point constants. + +@end table + +@node VAX-opcodes, VAX-branch, VAX-directives, Vax-Dependent +_CHAPSEC__(1+_GENERIC__) VAX Opcodes + +@cindex VAX opcode mnemonics +@cindex opcode mnemonics, VAX +@cindex mnemonics for opcodes, VAX +All DEC mnemonics are supported. Beware that @code{case@dots{}} +instructions have exactly 3 operands. The dispatch table that +follows the @code{case@dots{}} instruction should be made with +@code{.word} statements. This is compatible with all unix +assemblers we know of. + +@node VAX-branch, VAX-operands, VAX-opcodes, Vax-Dependent +_CHAPSEC__(1+_GENERIC__) VAX Branch Improvement + +@cindex VAX branch improvement +@cindex branch improvement, VAX +@cindex pseudo-ops for branch, VAX +Certain pseudo opcodes are permitted. They are for branch +instructions. They expand to the shortest branch instruction that +will reach the target. Generally these mnemonics are made by +substituting @samp{j} for @samp{b} at the start of a DEC mnemonic. +This feature is included both for compatibility and to help +compilers. If you don't need this feature, don't use these +opcodes. Here are the mnemonics, and the code they can expand into. + +@table @code +@item jbsb +@samp{Jsb} is already an instruction mnemonic, so we chose @samp{jbsb}. +@table @asis +@item (byte displacement) +@kbd{bsbb @dots{}} +@item (word displacement) +@kbd{bsbw @dots{}} +@item (long displacement) +@kbd{jsb @dots{}} +@end table +@item jbr +@itemx jr +Unconditional branch. +@table @asis +@item (byte displacement) +@kbd{brb @dots{}} +@item (word displacement) +@kbd{brw @dots{}} +@item (long displacement) +@kbd{jmp @dots{}} +@end table +@item j@var{COND} +@var{COND} may be any one of the conditional branches +@code{neq nequ eql eqlu gtr geq lss gtru lequ vc vs gequ cc lssu cs}. +@var{COND} may also be one of the bit tests +@code{bs bc bss bcs bsc bcc bssi bcci lbs lbc}. +@var{NOTCOND} is the opposite condition to @var{COND}. +@table @asis +@item (byte displacement) +@kbd{b@var{COND} @dots{}} +@item (word displacement) +@kbd{b@var{NOTCOND} foo ; brw @dots{} ; foo:} +@item (long displacement) +@kbd{b@var{NOTCOND} foo ; jmp @dots{} ; foo:} +@end table +@item jacb@var{X} +@var{X} may be one of @code{b d f g h l w}. +@table @asis +@item (word displacement) +@kbd{@var{OPCODE} @dots{}} +@item (long displacement) +@example +@var{OPCODE} @dots{}, foo ; +brb bar ; +foo: jmp @dots{} ; +bar: +@end example +@end table +@item jaob@var{YYY} +@var{YYY} may be one of @code{lss leq}. +@item jsob@var{ZZZ} +@var{ZZZ} may be one of @code{geq gtr}. +@table @asis +@item (byte displacement) +@kbd{@var{OPCODE} @dots{}} +@item (word displacement) +@example +@var{OPCODE} @dots{}, foo ; +brb bar ; +foo: brw @var{destination} ; +bar: +@end example +@item (long displacement) +@example +@var{OPCODE} @dots{}, foo ; +brb bar ; +foo: jmp @var{destination} ; +bar: +@end example +@end table +@item aobleq +@itemx aoblss +@itemx sobgeq +@itemx sobgtr +@table @asis +@item (byte displacement) +@kbd{@var{OPCODE} @dots{}} +@item (word displacement) +@example +@var{OPCODE} @dots{}, foo ; +brb bar ; +foo: brw @var{destination} ; +bar: +@end example +@item (long displacement) +@example +@var{OPCODE} @dots{}, foo ; +brb bar ; +foo: jmp @var{destination} ; +bar: +@end example +@end table +@end table + +@node VAX-operands, VAX-no, VAX-branch, Vax-Dependent +_CHAPSEC__(1+_GENERIC__) VAX Operands + +@cindex VAX operand notation +@cindex operand notation, VAX +@cindex immediate character, VAX +@cindex VAX immediate character +The immediate character is @samp{$} for Unix compatibility, not +@samp{#} as DEC writes it. + +@cindex indirect character, VAX +@cindex VAX indirect character +The indirect character is @samp{*} for Unix compatibility, not +@samp{@@} as DEC writes it. + +@cindex displacement sizing character, VAX +@cindex VAX displacement sizing character +The displacement sizing character is @samp{`} (an accent grave) for +Unix compatibility, not @samp{^} as DEC writes it. The letter +preceding @samp{`} may have either case. @samp{G} is not +understood, but all other letters (@code{b i l s w}) are understood. + +@cindex register names, VAX +@cindex VAX register names +Register names understood are @code{r0 r1 r2 @dots{} r15 ap fp sp +pc}. Any case of letters will do. + +For instance +@smallexample +tstb *w`$4(r5) +@end smallexample + +Any expression is permitted in an operand. Operands are comma +separated. + +@c There is some bug to do with recognizing expressions +@c in operands, but I forget what it is. It is +@c a syntax clash because () is used as an address mode +@c and to encapsulate sub-expressions. + +@node VAX-no, , VAX-operands, Vax-Dependent +_CHAPSEC__(1+_GENERIC__) Not Supported on VAX + +@cindex VAX bitfields not supported +@cindex bitfields, not supported on VAX +Vax bit fields can not be assembled with @code{_AS__}. Someone +can add the required code if they really need it. + +_fi__(_VAX__) +_if__(_A29K__) +_if__(_GENERIC__) +@node AMD29K-Dependent, H8/300-Dependent, Vax-Dependent, Machine Dependent +_fi__(_GENERIC__) +_CHAPSEC__(0+_GENERIC__) AMD 29K Dependent Features + +@cindex AMD 29K support +@cindex 29K support +@menu +* AMD29K Options:: Options +* AMD29K Syntax:: Syntax +* AMD29K Floating Point:: Floating Point +* AMD29K Directives:: AMD 29K Machine Directives +* AMD29K Opcodes:: Opcodes +@end menu + +@node AMD29K Options, AMD29K Syntax, AMD29K-Dependent, AMD29K-Dependent +_CHAPSEC__(1+_GENERIC__) Options +@cindex AMD 29K options (none) +@cindex options for AMD29K (none) +@code{_AS__} has no additional command-line options for the AMD +29K family. + +@node AMD29K Syntax, AMD29K Floating Point, AMD29K Options, AMD29K-Dependent +_CHAPSEC__(1+_GENERIC__) Syntax +@menu +* AMD29K-Chars:: Special Characters +* AMD29K-Regs:: Register Names +@end menu + +@node AMD29K-Chars, AMD29K-Regs, AMD29K Syntax, AMD29K Syntax +_CHAPSEC__(2+_GENERIC__) Special Characters + +@cindex line comment character, AMD 29K +@cindex AMD 29K line comment character +@samp{;} is the line comment character. + +@cindex line separator, AMD 29K +@cindex AMD 29K line separator +@cindex statement separator, AMD 29K +@cindex AMD 29K statement separator +@samp{@@} can be used instead of a newline to separate statements. + +@cindex identifiers, AMD 29K +@cindex AMD 29K identifiers +The character @samp{?} is permitted in identifiers (but may not begin +an identifier). + +@node AMD29K-Regs, , AMD29K-Chars, AMD29K Syntax +_CHAPSEC__(2+_GENERIC__) Register Names + +@cindex AMD 29K register names +@cindex register names, AMD 29K +General-purpose registers are represented by predefined symbols of the +form @samp{GR@var{nnn}} (for global registers) or @samp{LR@var{nnn}} +(for local registers), where @var{nnn} represents a number between +@code{0} and @code{127}, written with no leading zeros. The leading +letters may be in either upper or lower case; for example, @samp{gr13} +and @samp{LR7} are both valid register names. + +You may also refer to general-purpose registers by specifying the +register number as the result of an expression (prefixed with @samp{%%} +to flag the expression as a register number): +@smallexample +%%@var{expression} +@end smallexample +@noindent +---where @var{expression} must be an absolute expression evaluating to a +number between @code{0} and @code{255}. The range [0, 127] refers to +global registers, and the range [128, 255] to local registers. + +@cindex special purpose registers, AMD 29K +@cindex AMD 29K special purpose registers +@cindex protected registers, AMD 29K +@cindex AMD 29K protected registers +In addition, @code{_AS__} understands the following protected +special-purpose register names for the AMD 29K family: + +@smallexample + vab chd pc0 + ops chc pc1 + cps rbp pc2 + cfg tmc mmu + cha tmr lru +@end smallexample + +These unprotected special-purpose register names are also recognized: +@smallexample + ipc alu fpe + ipa bp inte + ipb fc fps + q cr exop +@end smallexample + +@node AMD29K Floating Point, AMD29K Directives, AMD29K Syntax, AMD29K-Dependent +_CHAPSEC__(1+_GENERIC__) Floating Point + +@cindex floating point, AMD 29K (@sc{ieee}) +@cindex AMD 29K floating point (@sc{ieee}) +The AMD 29K family uses @sc{ieee} floating-point numbers. + +@node AMD29K Directives, AMD29K Opcodes, AMD29K Floating Point, AMD29K-Dependent +_CHAPSEC__(1+_GENERIC__) AMD 29K Machine Directives + +@cindex machine directives, AMD 29K +@cindex AMD 29K machine directives +@table @code +@item .block @var{size} , @var{fill} +@cindex @code{block} directive, AMD 29K +This directive emits @var{size} bytes, each of value @var{fill}. Both +@var{size} and @var{fill} are absolute expressions. If the comma +and @var{fill} are omitted, @var{fill} is assumed to be zero. + +In other versions of the GNU assembler, this directive is called +@samp{.space}. +@end table + +@table @code +@item .cputype +@cindex @code{cputype} directive, AMD 29K +This directive is ignored; it is accepted for compatibility with other +AMD 29K assemblers. + +@item .file +@cindex @code{file} directive, AMD 29K +This directive is ignored; it is accepted for compatibility with other +AMD 29K assemblers. + +@quotation +@emph{Warning:} in other versions of the GNU assembler, @code{.file} is +used for the directive called @code{.app-file} in the AMD 29K support. +@end quotation + +@item .line +@cindex @code{line} directive, AMD 29K +This directive is ignored; it is accepted for compatibility with other +AMD 29K assemblers. + +@item .reg @var{symbol}, @var{expression} +@cindex @code{reg} directive, AMD 29K +@code{.reg} has the same effect as @code{.lsym}; @pxref{Lsym,,@code{.lsym}}. + +@item .sect +@cindex @code{sect} directive, AMD 29K +This directive is ignored; it is accepted for compatibility with other +AMD 29K assemblers. + +@item .use @var{section name} +@cindex @code{use} directive, AMD 29K +Establishes the section and subsection for the following code; +@var{section name} may be one of @code{.text}, @code{.data}, +@code{.data1}, or @code{.lit}. With one of the first three @var{section +name} options, @samp{.use} is equivalent to the machine directive +@var{section name}; the remaining case, @samp{.use .lit}, is the same as +@samp{.data 200}. +@end table + +@node AMD29K Opcodes, , AMD29K Directives, AMD29K-Dependent +_CHAPSEC__(1+_GENERIC__) Opcodes + +@cindex AMD 29K opcodes +@cindex opcodes for AMD 29K +@code{_AS__} implements all the standard AMD 29K opcodes. No +additional pseudo-instructions are needed on this family. + +For information on the 29K machine instruction set, see @cite{Am29000 +User's Manual}, Advanced Micro Devices, Inc. + +_fi__(_A29K__) +_if__(_H8__) +_if__(_GENERIC__) +@node H8/300-Dependent, i960-Dependent, AMD29K-Dependent, Machine Dependent +_fi__(_GENERIC__) +_CHAPSEC__(0+_GENERIC__) H8/300 Dependent Features + +@cindex H8/300 support +@menu +* H8/300 Options:: Options +* H8/300 Syntax:: Syntax +* H8/300 Floating Point:: Floating Point +* H8/300 Directives:: H8/300 Machine Directives +* H8/300 Opcodes:: Opcodes +@end menu + +@node H8/300 Options, H8/300 Syntax, H8/300-Dependent, H8/300-Dependent +_CHAPSEC__(1+_GENERIC__) Options + +@cindex H8/300 options (none) +@cindex options, H8/300 (none) +@code{_AS__} has no additional command-line options for the Hitachi +H8/300 family. + +@node H8/300 Syntax, H8/300 Floating Point, H8/300 Options, H8/300-Dependent +_CHAPSEC__(1+_GENERIC__) Syntax +@menu +* H8/300-Chars:: Special Characters +* H8/300-Regs:: Register Names +* H8/300-Addressing:: Addressing Modes +@end menu + +@node H8/300-Chars, H8/300-Regs, H8/300 Syntax, H8/300 Syntax +_CHAPSEC__(2+_GENERIC__) Special Characters + +@cindex line comment character, H8/300 +@cindex H8/300 line comment character +@samp{;} is the line comment character. + +@cindex line separator, H8/300 +@cindex statement separator, H8/300 +@cindex H8/300 line separator +@samp{$} can be used instead of a newline to separate statements. +Therefore @emph{you may not use @samp{$} in symbol names} on the H8/300. + +@node H8/300-Regs, H8/300-Addressing, H8/300-Chars, H8/300 Syntax +_CHAPSEC__(2+_GENERIC__) Register Names + +@cindex H8/300 registers +@cindex registers, H8/300 +You can use predefined symbols of the form @samp{r@var{n}h} and +@samp{r@var{n}l} to refer to the H8/300 registers as sixteen 8-bit +general-purpose registers. @var{n} is a digit from @samp{0} to +@samp{7}); for instance, both @samp{r0h} and @samp{r7l} are valid +register names. + +You can also use the eight predefined symbols @samp{r@var{n}} to refer +to the H8/300 registers as 16-bit registers (you must use this form for +addressing). + +The two control registers are called @code{pc} (program counter; a +16-bit register) and @code{ccr} (condition code register; an 8-bit +register). @code{r7} is used as the stack pointer, and can also be +called @code{sp}. + +@node H8/300-Addressing, , H8/300-Regs, H8/300 Syntax +_CHAPSEC__(2+_GENERIC__) Addressing Modes + +@cindex addressing modes, H8/300 +@cindex H8/300 addressing modes +_AS__ understands the following addressing modes for the H8/300: +@table @code +@item r@var{n} +Register direct + +@item @@r@var{n} +Register indirect + +@item @@(@var{d}, r@var{n}) +@itemx @@(@var{d}:16, r@var{n}) +Register indirect: 16-bit displacement @var{d} from register @var{n}. +(You may specify the @samp{:16} for clarity if you wish, but it is not +required and has no effect.) + +@item @@r@var{n}+ +Register indirect with post-increment + +@item @@-r@var{n} +Register indirect with pre-decrement + +@item @code{@@}@var{aa} +@itemx @code{@@}@var{aa}:8 +@itemx @code{@@}@var{aa}:16 +Absolute address @code{aa}. You may specify the @samp{:8} or @samp{:16} +for clarity, if you wish; but @code{_AS__} neither requires this nor +uses it---the address size required is taken from context. + +@item #@var{xx} +@itemx #@var{xx}:8 +@itemx #@var{xx}:16 +Immediate data @var{xx}. You may specify the @samp{:8} or @samp{:16} +for clarity, if you wish; but @code{_AS__} neither requires this nor +uses it---the data size required is taken from context. + +@item @code{@@}@code{@@}@var{aa} +@itemx @code{@@}@code{@@}@var{aa}:8 +Memory indirect. You may specify the @samp{:8} for clarity, if you +wish; but @code{_AS__} neither requires this nor uses it. +@end table + +@node H8/300 Floating Point, H8/300 Directives, H8/300 Syntax, H8/300-Dependent +_CHAPSEC__(1+_GENERIC__) Floating Point + +@cindex floating point, H8/300 (@sc{ieee}) +@cindex H8/300 floating point (@sc{ieee}) +The H8/300 family uses @sc{ieee} floating-point numbers. + +@node H8/300 Directives, H8/300 Opcodes, H8/300 Floating Point, H8/300-Dependent +_CHAPSEC__(1+_GENERIC__) H8/300 Machine Directives + +@cindex H8/300 machine directives (none) +@cindex machine directives, H8/300 (none) +@cindex @code{word} directive, H8/300 +@cindex @code{int} directive, H8/300 +@code{_AS__} has no machine-dependent directives for the H8/300. +However, on this platform the @samp{.int} and @samp{.word} directives +generate 16-bit numbers. + +@node H8/300 Opcodes, , H8/300 Directives, H8/300-Dependent +_CHAPSEC__(1+_GENERIC__) Opcodes + +@cindex H8/300 opcode summary +@cindex opcode summary, H8/300 +@cindex mnemonics, H8/300 +@cindex instruction summary, H8/300 +For detailed information on the H8/300 machine instruction set, see +@cite{H8/300 Series Programming Manual} (Hitachi ADE--602--025). + +@code{_AS__} implements all the standard H8/300 opcodes. No additional +pseudo-instructions are needed on this family. + +The following table summarizes the opcodes and their arguments: +@c kluge due to lack of group outside example +@page +@smallexample +@group + Rs @r{source register} + Rd @r{destination register} + imm @r{immediate data} + x:3 @r{a bit (as a number between 0 and 7)} + d:8 @r{eight bit displacement from @code{pc}} + d:16 @r{sixteen bit displacement from @code{Rs}} + +add.b Rs,Rd biand #x:3,Rd +add.b #imm:8,Rd biand #x:3,@@Rd +add.w Rs,Rd biand #x:3,@@aa:8 +adds #1,Rd bild #x:3,Rd +adds #2,Rd bild #x:3,@@Rd +addx #imm:8,Rd bild #x:3,@@aa:8 +addx Rs,Rd bior #x:3,Rd +and #imm:8,Rd bior #x:3,@@Rd +and Rs,Rd bior #x:3,@@aa:8 +andc #imm:8,ccr bist #x:3,Rd +band #x:3,Rd bist #x:3,@@Rd +band #x:3,@@Rd bist #x:3,@@aa:8 +bra d:8 bixor #x:3,Rd +bt d:8 bixor #x:3,@@Rd +brn d:8 bixor #x:3,@@aa:8 +bf d:8 bld #x:3,Rd +bhi d:8 bld #x:3,@@Rd +bls d:8 bld #x:3,@@aa:8 +bcc d:8 bnot #x:3,Rd +bhs d:8 bnot #x:3,@@Rd +bcs d:8 bnot #x:3,@@aa:8 +blo d:8 bnot Rs,Rd +bne d:8 bnot Rs,@@Rd +beq d:8 bnot Rs,@@aa:8 +bvc d:8 bor #x:3,Rd +bvs d:8 bor #x:3,@@Rd +bpl d:8 bor #x:3,@@aa:8 +bmi d:8 bset #x:3,@@Rd +bge d:8 bset #x:3,@@aa:8 +blt d:8 bset Rs,Rd +bgt d:8 bset Rs,@@Rd +ble d:8 bset Rs,@@aa:8 +bclr #x:3,Rd bsr d:8 +bclr #x:3,@@Rd bst #x:3,Rd +bclr #x:3,@@aa:8 bst #x:3,@@Rd +bclr Rs,Rd bst #x:3,@@aa:8 +bclr Rs,@@Rd btst #x:3,Rd +@end group +@group +btst #x:3,@@Rd mov.w @@(d:16, Rs),Rd +btst #x:3,@@aa:8 mov.w @@Rs+,Rd +btst Rs,Rd mov.w @@aa:16,Rd +btst Rs,@@Rd mov.w Rs,@@Rd +btst Rs,@@aa:8 mov.w Rs,@@(d:16, Rd) +bxor #x:3,Rd mov.w Rs,@@-Rd +bxor #x:3,@@Rd mov.w Rs,@@aa:16 +bxor #x:3,@@aa:8 movfpe @@aa:16,Rd +cmp.b #imm:8,Rd movtpe Rs,@@aa:16 +cmp.b Rs,Rd mulxu Rs,Rd +cmp.w Rs,Rd neg Rs +daa Rs nop +das Rs not Rs +dec Rs or #imm:8,Rd +divxu Rs,Rd or Rs,Rd +eepmov orc #imm:8,ccr +inc Rs pop Rs +jmp @@Rs push Rs +jmp @@aa:16 rotl Rs +jmp @@@@aa rotr Rs +jsr @@Rs rotxl Rs +jsr @@aa:16 rotxr Rs +jsr @@@@aa:8 rte +ldc #imm:8,ccr rts +ldc Rs,ccr shal Rs +mov.b Rs,Rd shar Rs +mov.b #imm:8,Rd shll Rs +mov.b @@Rs,Rd shlr Rs +mov.b @@(d:16, Rs),Rd sleep +mov.b @@Rs+,Rd stc ccr,Rd +mov.b @@aa:16,Rd sub.b Rs,Rd +mov.b @@aa:8,Rd sub.w Rs,Rd +mov.b Rs,@@Rd subs #1,Rd +mov.b Rs,@@(d:16, Rd) subs #2,Rd +mov.b Rs,@@-Rd subx #imm:8,Rd +mov.b Rs,@@aa:16 subx Rs,Rd +mov.b Rs,@@aa:8 xor #imm:8,Rd +mov.w Rs,Rd xor Rs,Rd +mov.w #imm:16,Rd xorc #imm:8,ccr +mov.w @@Rs,Rd +@end group +@end smallexample + +@cindex size suffixes, H8/300 +@cindex H8/300 size suffixes +Four H8/300 instructions (@code{add}, @code{cmp}, @code{mov}, +@code{sub}) are defined with variants using the suffixes @samp{.b} and +@samp{.w} to specify the size of a memory operand. @code{_AS__} +supports these suffixes, but does not require them; since one of the +operands is always a register, @code{_AS__} can deduce the correct size. + +For example, since @code{r0} refers to a 16-bit register, +@example +mov r0,@@foo +@exdent is equivalent to +mov.w r0,@@foo +@end example + +If you use the size suffixes, @code{_AS__} will issue a warning if +there's a mismatch between the suffix and the register size. + +_fi__(_H8__) +_if__(_I960__) +_if__(_GENERIC__) +@node i960-Dependent, M68K-Dependent, H8/300-Dependent, Machine Dependent +_fi__(_GENERIC__) +_CHAPSEC__(0+_GENERIC__) Intel 80960 Dependent Features + +@cindex i960 support +@menu +* Options-i960:: i960 Command-line Options +* Floating Point-i960:: Floating Point +* Directives-i960:: i960 Machine Directives +* Opcodes for i960:: i960 Opcodes +@end menu + +@c FIXME! Add Syntax sec with discussion of bitfields here, at least so +@c long as they're not turned on for other machines than 960. +@node Options-i960, Floating Point-i960, i960-Dependent, i960-Dependent + +_CHAPSEC__(1+_GENERIC__) i960 Command-line Options + +@cindex i960 options +@cindex options, i960 +@table @code + +@item -ACA | -ACA_A | -ACB | -ACC | -AKA | -AKB | -AKC | -AMC +@cindex i960 architecture options +@cindex architecture options, i960 +@cindex @code{-A} options, i960 +Select the 80960 architecture. Instructions or features not supported +by the selected architecture cause fatal errors. + +@samp{-ACA} is equivalent to @samp{-ACA_A}; @samp{-AKC} is equivalent to +@samp{-AMC}. Synonyms are provided for compatibility with other tools. + +If none of these options is specified, @code{_AS__} will generate code for any +instruction or feature that is supported by @emph{some} version of the +960 (even if this means mixing architectures!). In principle, +@code{_AS__} will attempt to deduce the minimal sufficient processor +type if none is specified; depending on the object code format, the +processor type may be recorded in the object file. If it is critical +that the @code{_AS__} output match a specific architecture, specify that +architecture explicitly. + +@item -b +@cindex @code{-b} option, i960 +@cindex branch recording, i960 +@cindex i960 branch recording +Add code to collect information about conditional branches taken, for +later optimization using branch prediction bits. (The conditional branch +instructions have branch prediction bits in the CA, CB, and CC +architectures.) If @var{BR} represents a conditional branch instruction, +the following represents the code generated by the assembler when +@samp{-b} is specified: + +@smallexample + call @var{increment routine} + .word 0 # pre-counter +Label: @var{BR} + call @var{increment routine} + .word 0 # post-counter +@end smallexample + +The counter following a branch records the number of times that branch +was @emph{not} taken; the differenc between the two counters is the +number of times the branch @emph{was} taken. + +@cindex @code{gbr960}, i960 postprocessor +@cindex branch statistics table, i960 +A table of every such @code{Label} is also generated, so that the +external postprocessor @code{gbr960} (supplied by Intel) can locate all +the counters. This table is always labelled @samp{__BRANCH_TABLE__}; +this is a local symbol to permit collecting statistics for many separate +object files. The table is word aligned, and begins with a two-word +header. The first word, initialized to 0, is used in maintaining linked +lists of branch tables. The second word is a count of the number of +entries in the table, which follow immediately: each is a word, pointing +to one of the labels illustrated above. + +@c TEXI2ROFF-KILL +@ifinfo +@c END TEXI2ROFF-KILL +@example + +------------+------------+------------+ ... +------------+ + | | | | | | + | *NEXT | COUNT: N | *BRLAB 1 | | *BRLAB N | + | | | | | | + +------------+------------+------------+ ... +------------+ + + __BRANCH_TABLE__ layout +@end example +@c TEXI2ROFF-KILL +@end ifinfo +@tex +\vskip 1pc +\line{\leftskip=0pt\hskip\tableindent +\boxit{2cm}{\tt *NEXT}\boxit{2cm}{\tt COUNT: \it N}\boxit{2cm}{\tt +*BRLAB 1}\ibox{1cm}{\quad\dots}\boxit{2cm}{\tt *BRLAB \it N}\hfil} +\centerline{\it {\tt \_\_BRANCH\_TABLE\_\_} layout} +@end tex +@c END TEXI2ROFF-KILL + +The first word of the header is used to locate multiple branch tables, +since each object file may contain one. Normally the links are +maintained with a call to an initialization routine, placed at the +beginning of each function in the file. The GNU C compiler will +generate these calls automatically when you give it a @samp{-b} option. +For further details, see the documentation of @samp{gbr960}. + +@item -norelax +@cindex @code{-norelax} option, i960 +Normally, Compare-and-Branch instructions with targets that require +displacements greater than 13 bits (or that have external targets) are +replaced with the corresponding compare (or @samp{chkbit}) and branch +instructions. You can use the @samp{-norelax} option to specify that +@code{_AS__} should generate errors instead, if the target displacement +is larger than 13 bits. + +This option does not affect the Compare-and-Jump instructions; the code +emitted for them is @emph{always} adjusted when necessary (depending on +displacement size), regardless of whether you use @samp{-norelax}. +@end table + +@node Floating Point-i960, Directives-i960, Options-i960, i960-Dependent +_CHAPSEC__(1+_GENERIC__) Floating Point + +@cindex floating point, i960 (@sc{ieee}) +@cindex i960 floating point (@sc{ieee}) +@code{_AS__} generates @sc{ieee} floating-point numbers for the directives +@samp{.float}, @samp{.double}, @samp{.extended}, and @samp{.single}. + +@node Directives-i960, Opcodes for i960, Floating Point-i960, i960-Dependent +_CHAPSEC__(1+_GENERIC__) i960 Machine Directives + +@cindex machine directives, i960 +@cindex i960 machine directives + +@table @code +@cindex @code{bss} directive, i960 +@item .bss @var{symbol}, @var{length}, @var{align} +Reserve @var{length} bytes in the bss section for a local @var{symbol}, +aligned to the power of two specified by @var{align}. @var{length} and +@var{align} must be positive absolute expressions. This directive +differs from @samp{.lcomm} only in that it permits you to specify +an alignment. @xref{Lcomm,,@code{.lcomm}}. +@end table + +@table @code +@item .extended @var{flonums} +@cindex @code{extended} directive, i960 +@code{.extended} expects zero or more flonums, separated by commas; for +each flonum, @samp{.extended} emits an @sc{ieee} extended-format (80-bit) +floating-point number. + +@item .leafproc @var{call-lab}, @var{bal-lab} +@cindex @code{leafproc} directive, i960 +You can use the @samp{.leafproc} directive in conjunction with the +optimized @code{callj} instruction to enable faster calls of leaf +procedures. If a procedure is known to call no other procedures, you +may define an entry point that skips procedure prolog code (and that does +not depend on system-supplied saved context), and declare it as the +@var{bal-lab} using @samp{.leafproc}. If the procedure also has an +entry point that goes through the normal prolog, you can specify that +entry point as @var{call-lab}. + +A @samp{.leafproc} declaration is meant for use in conjunction with the +optimized call instruction @samp{callj}; the directive records the data +needed later to choose between converting the @samp{callj} into a +@code{bal} or a @code{call}. + +@var{call-lab} is optional; if only one argument is present, or if the +two arguments are identical, the single argument is assumed to be the +@code{bal} entry point. + +@item .sysproc @var{name}, @var{index} +@cindex @code{sysproc} directive, i960 +The @samp{.sysproc} directive defines a name for a system procedure. +After you define it using @samp{.sysproc}, you can use @var{name} to +refer to the system procedure identified by @var{index} when calling +procedures with the optimized call instruction @samp{callj}. + +Both arguments are required; @var{index} must be between 0 and 31 +(inclusive). +@end table + +@node Opcodes for i960, , Directives-i960, i960-Dependent +_CHAPSEC__(1+_GENERIC__) i960 Opcodes + +@cindex opcodes, i960 +@cindex i960 opcodes +All Intel 960 machine instructions are supported; +@pxref{Options-i960,,i960 Command-line Options} for a discussion of +selecting the instruction subset for a particular 960 +architecture.@refill + +Some opcodes are processed beyond simply emitting a single corresponding +instruction: @samp{callj}, and Compare-and-Branch or Compare-and-Jump +instructions with target displacements larger than 13 bits. + +@menu +* callj-i960:: @code{callj} +* Compare-and-branch-i960:: Compare-and-Branch +@end menu + +@node callj-i960, Compare-and-branch-i960, Opcodes for i960, Opcodes for i960 +_CHAPSEC__(2+_GENERIC__) @code{callj} + +@cindex @code{callj}, i960 pseudo-opcode +@cindex i960 @code{callj} pseudo-opcode +You can write @code{callj} to have the assembler or the linker determine +the most appropriate form of subroutine call: @samp{call}, +@samp{bal}, or @samp{calls}. If the assembly source contains +enough information---a @samp{.leafproc} or @samp{.sysproc} directive +defining the operand---then @code{_AS__} will translate the +@code{callj}; if not, it will simply emit the @code{callj}, leaving it +for the linker to resolve. + +@node Compare-and-branch-i960, , callj-i960, Opcodes for i960 +_CHAPSEC__(2+_GENERIC__) Compare-and-Branch + +@cindex i960 compare and branch instructions +@cindex compare and branch instructions, i960 +The 960 architectures provide combined Compare-and-Branch instructions +that permit you to store the branch target in the lower 13 bits of the +instruction word itself. However, if you specify a branch target far +enough away that its address won't fit in 13 bits, the assembler can +either issue an error, or convert your Compare-and-Branch instruction +into separate instructions to do the compare and the branch. + +@cindex compare and jump expansions, i960 +@cindex i960 compare and jump expansions +Whether @code{_AS__} gives an error or expands the instruction depends +on two choices you can make: whether you use the @samp{-norelax} option, +and whether you use a ``Compare and Branch'' instruction or a ``Compare +and Jump'' instruction. The ``Jump'' instructions are @emph{always} +expanded if necessary; the ``Branch'' instructions are expanded when +necessary @emph{unless} you specify @code{-norelax}---in which case +@code{_AS__} gives an error instead. + +These are the Compare-and-Branch instructions, their ``Jump'' variants, +and the instruction pairs they may expand into: + +@c TEXI2ROFF-KILL +@ifinfo +@c END TEXI2ROFF-KILL +@example + Compare and + Branch Jump Expanded to + ------ ------ ------------ + bbc chkbit; bno + bbs chkbit; bo + cmpibe cmpije cmpi; be + cmpibg cmpijg cmpi; bg + cmpibge cmpijge cmpi; bge + cmpibl cmpijl cmpi; bl + cmpible cmpijle cmpi; ble + cmpibno cmpijno cmpi; bno + cmpibne cmpijne cmpi; bne + cmpibo cmpijo cmpi; bo + cmpobe cmpoje cmpo; be + cmpobg cmpojg cmpo; bg + cmpobge cmpojge cmpo; bge + cmpobl cmpojl cmpo; bl + cmpoble cmpojle cmpo; ble + cmpobne cmpojne cmpo; bne +@end example +@c TEXI2ROFF-KILL +@end ifinfo +@tex +\hskip\tableindent +\halign{\hfil {\tt #}\quad&\hfil {\tt #}\qquad&{\tt #}\hfil\cr +\omit{\hfil\it Compare and\hfil}\span\omit&\cr +{\it Branch}&{\it Jump}&{\it Expanded to}\cr + bbc& & chkbit; bno\cr + bbs& & chkbit; bo\cr + cmpibe& cmpije& cmpi; be\cr + cmpibg& cmpijg& cmpi; bg\cr + cmpibge& cmpijge& cmpi; bge\cr + cmpibl& cmpijl& cmpi; bl\cr + cmpible& cmpijle& cmpi; ble\cr + cmpibno& cmpijno& cmpi; bno\cr + cmpibne& cmpijne& cmpi; bne\cr + cmpibo& cmpijo& cmpi; bo\cr + cmpobe& cmpoje& cmpo; be\cr + cmpobg& cmpojg& cmpo; bg\cr + cmpobge& cmpojge& cmpo; bge\cr + cmpobl& cmpojl& cmpo; bl\cr + cmpoble& cmpojle& cmpo; ble\cr + cmpobne& cmpojne& cmpo; bne\cr} +@end tex +@c END TEXI2ROFF-KILL +_fi__(_I960__) + +_if__(_M680X0__) +_if__(_GENERIC__) +@c FIXME! node conds are only sufficient for m68k alone, all, and vintage +_if__(_I960__) +@node M68K-Dependent, Sparc-Dependent, i960-Dependent, Machine Dependent +_fi__(_I960__) +_if__(!_I960__) +@node M68K-Dependent, Sparc-Dependent, Machine Dependent, Machine Dependent +_fi__(!_I960__) +_fi__(_GENERIC__) +_CHAPSEC__(0+_GENERIC__) M680x0 Dependent Features + +@cindex M680x0 support +@menu +* M68K-Opts:: M680x0 Options +* M68K-Syntax:: Syntax +* M68K-Float:: Floating Point +* M68K-Directives:: 680x0 Machine Directives +* M68K-opcodes:: Opcodes +@end menu + +@node M68K-Opts, M68K-Syntax, M68K-Dependent, M68K-Dependent +_CHAPSEC__(1+_GENERIC__) M680x0 Options + +@cindex options, M680x0 +@cindex M680x0 options +The Motorola 680x0 version of @code{_AS__} has two machine dependent options. +One shortens undefined references from 32 to 16 bits, while the +other is used to tell @code{_AS__} what kind of machine it is +assembling for. + +@cindex @code{-l} option, M680x0 +You can use the @kbd{-l} option to shorten the size of references to +undefined symbols. If the @kbd{-l} option is not given, references to +undefined symbols will be a full long (32 bits) wide. (Since @code{_AS__} +cannot know where these symbols will end up, @code{_AS__} can only allocate +space for the linker to fill in later. Since @code{_AS__} doesn't know how +far away these symbols will be, it allocates as much space as it can.) +If this option is given, the references will only be one word wide (16 +bits). This may be useful if you want the object file to be as small as +possible, and you know that the relevant symbols will be less than 17 +bits away. + +@cindex @code{-m68000} and related options, M680x0 +@cindex architecture options, M680x0 +@cindex M680x0 architecture options +The 680x0 version of @code{_AS__} is most frequently used to assemble +programs for the Motorola MC68020 microprocessor. Occasionally it is +used to assemble programs for the mostly similar, but slightly different +MC68000 or MC68010 microprocessors. You can give @code{_AS__} the options +@samp{-m68000}, @samp{-mc68000}, @samp{-m68010}, @samp{-mc68010}, +@samp{-m68020}, and @samp{-mc68020} to tell it what processor is the +target. + +@node M68K-Syntax, M68K-Float, M68K-Opts, M68K-Dependent +_CHAPSEC__(1+_GENERIC__) Syntax + +@cindex M680x0 syntax +@cindex syntax, M680x0 +@cindex M680x0 size modifiers +@cindex size modifiers, M680x0 +The 680x0 version of @code{_AS__} uses syntax similar to the Sun assembler. +Size modifiers are appended directly to the end of the opcode without an +intervening period. For example, write @samp{movl} rather than +@samp{move.l}. + +_if__(_INTERNALS__) +If @code{_AS__} is compiled with SUN_ASM_SYNTAX defined, it will also allow +Sun-style local labels of the form @samp{1$} through @samp{$9}. +_fi__(_INTERNALS__) + +In the following table @dfn{apc} stands for any of the address +registers (@samp{a0} through @samp{a7}), nothing, (@samp{}), the +Program Counter (@samp{pc}), or the zero-address relative to the +program counter (@samp{zpc}). + +@cindex M680x0 addressing modes +@cindex addressing modes, M680x0 +The following addressing modes are understood: +@table @dfn +@item Immediate +@samp{#@var{digits}} + +@item Data Register +@samp{d0} through @samp{d7} + +@item Address Register +@samp{a0} through @samp{a7} + +@item Address Register Indirect +@samp{a0@@} through @samp{a7@@} + +@item Address Register Postincrement +@samp{a0@@+} through @samp{a7@@+} + +@item Address Register Predecrement +@samp{a0@@-} through @samp{a7@@-} + +@item Indirect Plus Offset +@samp{@var{apc}@@(@var{digits})} + +@item Index +@samp{@var{apc}@@(@var{digits},@var{register}:@var{size}:@var{scale})} + +or @samp{@var{apc}@@(@var{register}:@var{size}:@var{scale})} + +@item Postindex +@samp{@var{apc}@@(@var{digits})@@(@var{digits},@var{register}:@var{size}:@var{scale})} + +or @samp{@var{apc}@@(@var{digits})@@(@var{register}:@var{size}:@var{scale})} + +@item Preindex +@samp{@var{apc}@@(@var{digits},@var{register}:@var{size}:@var{scale})@@(@var{digits})} + +or @samp{@var{apc}@@(@var{register}:@var{size}:@var{scale})@@(@var{digits})} + +@item Memory Indirect +@samp{@var{apc}@@(@var{digits})@@(@var{digits})} + +@item Absolute +@samp{@var{symbol}}, or @samp{@var{digits}} +@ignore +@c pesch@cygnus.com: gnu, rich concur the following needs careful +@c research before documenting. + , or either of the above followed +by @samp{:b}, @samp{:w}, or @samp{:l}. +@end ignore +@end table + +@node M68K-Float, M68K-Directives, M68K-Syntax, M68K-Dependent +_CHAPSEC__(1+_GENERIC__) Floating Point + +@cindex floating point, M680x0 +@cindex M680x0 floating point +@c FIXME is this "not too well tested" crud STILL true? +The floating point code is not too well tested, and may have +subtle bugs in it. + +Packed decimal (P) format floating literals are not supported. +Feel free to add the code! + +The floating point formats generated by directives are these. + +@table @code +@item .float +@cindex @code{float} directive, M680x0 +@code{Single} precision floating point constants. + +@item .double +@cindex @code{double} directive, M680x0 +@code{Double} precision floating point constants. +@end table + +There is no directive to produce regions of memory holding +extended precision numbers, however they can be used as +immediate operands to floating-point instructions. Adding a +directive to create extended precision numbers would not be +hard, but it has not yet seemed necessary. + +@node M68K-Directives, M68K-opcodes, M68K-Float, M68K-Dependent +_CHAPSEC__(1+_GENERIC__) 680x0 Machine Directives + +@cindex M680x0 directives +@cindex directives, M680x0 +In order to be compatible with the Sun assembler the 680x0 assembler +understands the following directives. + +@table @code +@item .data1 +@cindex @code{data1} directive, M680x0 +This directive is identical to a @code{.data 1} directive. + +@item .data2 +@cindex @code{data2} directive, M680x0 +This directive is identical to a @code{.data 2} directive. + +@item .even +@cindex @code{even} directive, M680x0 +This directive is identical to a @code{.align 1} directive. +@c Is this true? does it work??? + +@item .skip +@cindex @code{skip} directive, M680x0 +This directive is identical to a @code{.space} directive. +@end table + +@node M68K-opcodes, , M68K-Directives, M68K-Dependent +_CHAPSEC__(1+_GENERIC__) Opcodes + +@cindex M680x0 opcodes +@cindex opcodes, M680x0 +@cindex instruction set, M680x0 +@c pesch@cygnus.com: I don't see any point in the following +@c paragraph. Bugs are bugs; how does saying this +@c help anyone? +@ignore +Danger: Several bugs have been found in the opcode table (and +fixed). More bugs may exist. Be careful when using obscure +instructions. +@end ignore + +@menu +* M68K-Branch:: Branch Improvement +* M68K-Chars:: Special Characters +@end menu + +@node M68K-Branch, M68K-Chars, M68K-opcodes, M68K-opcodes +_CHAPSEC__(2+_GENERIC__) Branch Improvement + +@cindex pseudo-opcodes, M680x0 +@cindex M680x0 pseudo-opcodes +@cindex branch improvement, M680x0 +@cindex M680x0 branch improvement +Certain pseudo opcodes are permitted for branch instructions. +They expand to the shortest branch instruction that will reach the +target. Generally these mnemonics are made by substituting @samp{j} for +@samp{b} at the start of a Motorola mnemonic. + +The following table summarizes the pseudo-operations. A @code{*} flags +cases that are more fully described after the table: + +@smallexample + Displacement + +--------------------------------------------------------- + | 68020 68000/10 +Pseudo-Op |BYTE WORD LONG LONG non-PC relative + +--------------------------------------------------------- + jbsr |bsrs bsr bsrl jsr jsr + jra |bras bra bral jmp jmp +* jXX |bXXs bXX bXXl bNXs;jmpl bNXs;jmp +* dbXX |dbXX dbXX dbXX; bra; jmpl +* fjXX |fbXXw fbXXw fbXXl fbNXw;jmp + +XX: condition +NX: negative of condition XX + +@end smallexample +@center @code{*}---see full description below + +@table @code +@item jbsr +@itemx jra +These are the simplest jump pseudo-operations; they always map to one +particular machine instruction, depending on the displacement to the +branch target. + +@item j@var{XX} +Here, @samp{j@var{XX}} stands for an entire family of pseudo-operations, +where @var{XX} is a conditional branch or condition-code test. The full +list of pseudo-ops in this family is: +@smallexample + jhi jls jcc jcs jne jeq jvc + jvs jpl jmi jge jlt jgt jle +@end smallexample + +For the cases of non-PC relative displacements and long displacements on +the 68000 or 68010, @code{_AS__} will issue a longer code fragment in terms of +@var{NX}, the opposite condition to @var{XX}: +@smallexample + j@var{XX} foo +@end smallexample +gives +@smallexample + b@var{NX}s oof + jmp foo + oof: +@end smallexample + +@item db@var{XX} +The full family of pseudo-operations covered here is +@smallexample + dbhi dbls dbcc dbcs dbne dbeq dbvc + dbvs dbpl dbmi dbge dblt dbgt dble + dbf dbra dbt +@end smallexample + +Other than for word and byte displacements, when the source reads +@samp{db@var{XX} foo}, @code{_AS__} will emit +@smallexample + db@var{XX} oo1 + bra oo2 + oo1:jmpl foo + oo2: +@end smallexample + +@item fj@var{XX} +This family includes +@smallexample + fjne fjeq fjge fjlt fjgt fjle fjf + fjt fjgl fjgle fjnge fjngl fjngle fjngt + fjnle fjnlt fjoge fjogl fjogt fjole fjolt + fjor fjseq fjsf fjsne fjst fjueq fjuge + fjugt fjule fjult fjun +@end smallexample + +For branch targets that are not PC relative, @code{_AS__} emits +@smallexample + fb@var{NX} oof + jmp foo + oof: +@end smallexample +when it encounters @samp{fj@var{XX} foo}. + +@end table + +@node M68K-Chars, , M68K-Branch, M68K-opcodes +_CHAPSEC__(2+_GENERIC__) Special Characters + +@cindex special characters, M680x0 +@cindex M680x0 immediate character +@cindex immediate character, M680x0 +@cindex M680x0 line comment character +@cindex line comment character, M680x0 +@cindex comments, M680x0 +The immediate character is @samp{#} for Sun compatibility. The +line-comment character is @samp{|}. If a @samp{#} appears at the +beginning of a line, it is treated as a comment unless it looks like +@samp{# line file}, in which case it is treated normally. + +_fi__(_M680X0__) +_if__(0) +@c pesch@cygnus.com: conditionalize on something other than 0 when filled in. +@section 32x32 +@section Options +The 32x32 version of @code{_AS__} accepts a @kbd{-m32032} option to +specify thiat it is compiling for a 32032 processor, or a +@kbd{-m32532} to specify that it is compiling for a 32532 option. +The default (if neither is specified) is chosen when the assembler +is compiled. + +@subsection Syntax +I don't know anything about the 32x32 syntax assembled by +@code{_AS__}. Someone who undersands the processor (I've never seen +one) and the possible syntaxes should write this section. + +@subsection Floating Point +The 32x32 uses @sc{ieee} floating point numbers, but @code{_AS__} will only +create single or double precision values. I don't know if the 32x32 +understands extended precision numbers. + +@subsection 32x32 Machine Directives +The 32x32 has no machine dependent directives. + +_fi__(0) +_if__(_SPARC__) +_if__(_GENERIC__) +_if__(_I80386__&&_M680X0__) +@node Sparc-Dependent, i386-Dependent, M68K-Dependent, Machine Dependent +_fi__(_I80386__&&_M680X0__) +_if__(_I80386__&&_I960__&&!_M680X0__) +@node Sparc-Dependent, i386-Dependent, i960-Dependent, Machine Dependent +_fi__(_I80386__&&_I960__&&!_M680X0__) +_if__(_I80386__&&_A29K__&&(!_I960__)&&!_M680X0__) +@node Sparc-Dependent, i386-Dependent, AMD29K-Dependent, Machine Dependent +_fi__(_I80386__&&_A29K__&&(!_I960__)&&!_M680X0__) +_if__(_I80386__&&_VAX__&&(!_A29K__)&&(!_I960__)&&!_M680X0__) +@node Sparc-Dependent, i386-Dependent, Vax-Dependent, Machine Dependent +_fi__(_I80386__&&_VAX__&&(!_A29K__)&&(!_I960__)&&!_M680X0__) +_if__(_I80386__&&(!_VAX__)&&(!_A29K__)&&(!_I960__)&&!_M680X0__) +@node Sparc-Dependent, i386-Dependent, Machine Dependent, Machine Dependent +_fi__(_I80386__&&(!_VAX__)&&(!_A29K__)&&(!_I960__)&&!_M680X0__) +_if__((!_I80386__)&&_M680X0__) +@node Sparc-Dependent, , M68K-Dependent, Machine Dependent +_fi__((!_I80386__)&&_M680X0__) +_if__((!_I80386__)&&_I960__&&!_M680X0__) +@node Sparc-Dependent, , i960-Dependent, Machine Dependent +_fi__((!_I80386__)&&_I960__&&!_M680X0__) +_if__((!_I80386__)&&_A29K__&&(!_I960__)&&!_M680X0__) +@node Sparc-Dependent, , AMD29K-Dependent, Machine Dependent +_fi__((!_I80386__)&&_A29K__&&(!_I960__)&&!_M680X0__) +_if__((!_I80386__)&&_VAX__&&(!_A29K__)&&(!_I960__)&&!_M680X0__) +@node Sparc-Dependent, , Vax-Dependent, Machine Dependent +_fi__((!_I80386__)&&_VAX__&&(!_A29K__)&&(!_I960__)&&!_M680X0__) +_if__((!_I80386__)&&(!_VAX__)&&(!_A29K__)&&(!_I960__)&&!_M680X0__) +@node Sparc-Dependent, , Machine Dependent, Machine Dependent +_fi__((!_I80386__)&&(!_VAX__)&&(!_A29K__)&&(!_I960__)&&!_M680X0__) +_fi__(_GENERIC__) +_CHAPSEC__(0+_GENERIC__) SPARC Dependent Features + +@cindex SPARC support +@menu +* Sparc-Opts:: Options +* Sparc-Float:: Floating Point +* Sparc-Directives:: Sparc Machine Directives +@end menu + +@node Sparc-Opts, Sparc-Float, Sparc-Dependent, Sparc-Dependent +_CHAPSEC__(1+_GENERIC__) Options + +@cindex options for SPARC (none) +@cindex SPARC options (none) +The Sparc has no machine dependent options. + +@ignore +@c FIXME: (sparc) Fill in "syntax" section! +@c subsection syntax +I don't know anything about Sparc syntax. Someone who does +will have to write this section. +@end ignore + +@node Sparc-Float, Sparc-Directives, Sparc-Opts, Sparc-Dependent +_CHAPSEC__(1+_GENERIC__) Floating Point + +@cindex floating point, SPARC (@sc{ieee}) +@cindex SPARC floating point (@sc{ieee}) +The Sparc uses @sc{ieee} floating-point numbers. + +@node Sparc-Directives, , Sparc-Float, Sparc-Dependent +_CHAPSEC__(1+_GENERIC__) Sparc Machine Directives + +@cindex SPARC machine directives +@cindex machine directives, SPARC +The Sparc version of @code{_AS__} supports the following additional +machine directives: + +@table @code +@item .common +@cindex @code{common} directive, SPARC +This must be followed by a symbol name, a positive number, and +@code{"bss"}. This behaves somewhat like @code{.comm}, but the +syntax is different. + +@item .half +@cindex @code{half} directive, SPARC +This is functionally identical to @code{.short}. + +@item .proc +@cindex @code{proc} directive, SPARC +This directive is ignored. Any text following it on the same +line is also ignored. + +@item .reserve +@cindex @code{reserve} directive, SPARC +This must be followed by a symbol name, a positive number, and +@code{"bss"}. This behaves somewhat like @code{.lcomm}, but the +syntax is different. + +@item .seg +@cindex @code{seg} directive, SPARC +This must be followed by @code{"text"}, @code{"data"}, or +@code{"data1"}. It behaves like @code{.text}, @code{.data}, or +@code{.data 1}. + +@item .skip +@cindex @code{skip} directive, SPARC +This is functionally identical to the @code{.space} directive. + +@item .word +@cindex @code{word} directive, SPARC +On the Sparc, the .word directive produces 32 bit values, +instead of the 16 bit values it produces on many other machines. +@end table + +_fi__(_SPARC__) +_if__(_I80386__) +_if__(_GENERIC__) +@c FIXME! Conditionalize for all combinations in this section +@node i386-Dependent, , Sparc-Dependent, Machine Dependent +_fi__(_GENERIC__) +_CHAPSEC__(0+_GENERIC__) 80386 Dependent Features + +@cindex i386 support +@cindex i80306 support +@menu +* i386-Options:: Options +* i386-Syntax:: AT&T Syntax versus Intel Syntax +* i386-Opcodes:: Opcode Naming +* i386-Regs:: Register Naming +* i386-prefixes:: Opcode Prefixes +* i386-Memory:: Memory References +* i386-jumps:: Handling of Jump Instructions +* i386-Float:: Floating Point +* i386-Notes:: Notes +@end menu + +@node i386-Options, i386-Syntax, i386-Dependent, i386-Dependent +_CHAPSEC__(1+_GENERIC__) Options + +@cindex options for i386 (none) +@cindex i386 options (none) +The 80386 has no machine dependent options. + +@node i386-Syntax, i386-Opcodes, i386-Options, i386-Dependent +_CHAPSEC__(1+_GENERIC__) AT&T Syntax versus Intel Syntax + +@cindex i386 syntax compatibility +@cindex syntax compatibility, i386 +In order to maintain compatibility with the output of @code{_GCC__}, +@code{_AS__} supports AT&T System V/386 assembler syntax. This is quite +different from Intel syntax. We mention these differences because +almost all 80386 documents used only Intel syntax. Notable differences +between the two syntaxes are: + +@itemize @bullet +@item +@cindex immediate operands, i386 +@cindex i386 immediate operands +@cindex register operands, i386 +@cindex i386 register operands +@cindex jump/call operands, i386 +@cindex i386 jump/call operands +@cindex operand delimiters, i386 +AT&T immediate operands are preceded by @samp{$}; Intel immediate +operands are undelimited (Intel @samp{push 4} is AT&T @samp{pushl $4}). +AT&T register operands are preceded by @samp{%}; Intel register operands +are undelimited. AT&T absolute (as opposed to PC relative) jump/call +operands are prefixed by @samp{*}; they are undelimited in Intel syntax. + +@item +@cindex i386 source, destination operands +@cindex source, destination operands; i386 +AT&T and Intel syntax use the opposite order for source and destination +operands. Intel @samp{add eax, 4} is @samp{addl $4, %eax}. The +@samp{source, dest} convention is maintained for compatibility with +previous Unix assemblers. + +@item +@cindex opcode suffixes, i386 +@cindex sizes operands, i386 +@cindex i386 size suffixes +In AT&T syntax the size of memory operands is determined from the last +character of the opcode name. Opcode suffixes of @samp{b}, @samp{w}, +and @samp{l} specify byte (8-bit), word (16-bit), and long (32-bit) +memory references. Intel syntax accomplishes this by prefixes memory +operands (@emph{not} the opcodes themselves) with @samp{byte ptr}, +@samp{word ptr}, and @samp{dword ptr}. Thus, Intel @samp{mov al, byte +ptr @var{foo}} is @samp{movb @var{foo}, %al} in AT&T syntax. + +@item +@cindex return instructions, i386 +@cindex i386 jump, call, return +Immediate form long jumps and calls are +@samp{lcall/ljmp $@var{section}, $@var{offset}} in AT&T syntax; the +Intel syntax is +@samp{call/jmp far @var{section}:@var{offset}}. Also, the far return +instruction +is @samp{lret $@var{stack-adjust}} in AT&T syntax; Intel syntax is +@samp{ret far @var{stack-adjust}}. + +@item +@cindex sections, i386 +@cindex i386 sections +The AT&T assembler does not provide support for multiple section +programs. Unix style systems expect all programs to be single sections. +@end itemize + +@node i386-Opcodes, i386-Regs, i386-Syntax, i386-Dependent +_CHAPSEC__(1+_GENERIC__) Opcode Naming + +@cindex i386 opcode naming +@cindex opcode naming, i386 +Opcode names are suffixed with one character modifiers which specify the +size of operands. The letters @samp{b}, @samp{w}, and @samp{l} specify +byte, word, and long operands. If no suffix is specified by an +instruction and it contains no memory operands then @code{_AS__} tries to +fill in the missing suffix based on the destination register operand +(the last one by convention). Thus, @samp{mov %ax, %bx} is equivalent +to @samp{movw %ax, %bx}; also, @samp{mov $1, %bx} is equivalent to +@samp{movw $1, %bx}. Note that this is incompatible with the AT&T Unix +assembler which assumes that a missing opcode suffix implies long +operand size. (This incompatibility does not affect compiler output +since compilers always explicitly specify the opcode suffix.) + +Almost all opcodes have the same names in AT&T and Intel format. There +are a few exceptions. The sign extend and zero extend instructions need +two sizes to specify them. They need a size to sign/zero extend +@emph{from} and a size to zero extend @emph{to}. This is accomplished +by using two opcode suffixes in AT&T syntax. Base names for sign extend +and zero extend are @samp{movs@dots{}} and @samp{movz@dots{}} in AT&T +syntax (@samp{movsx} and @samp{movzx} in Intel syntax). The opcode +suffixes are tacked on to this base name, the @emph{from} suffix before +the @emph{to} suffix. Thus, @samp{movsbl %al, %edx} is AT&T syntax for +``move sign extend @emph{from} %al @emph{to} %edx.'' Possible suffixes, +thus, are @samp{bl} (from byte to long), @samp{bw} (from byte to word), +and @samp{wl} (from word to long). + +@cindex conversion instructions, i386 +@cindex i386 conversion instructions +The Intel-syntax conversion instructions + +@itemize @bullet +@item +@samp{cbw} --- sign-extend byte in @samp{%al} to word in @samp{%ax}, + +@item +@samp{cwde} --- sign-extend word in @samp{%ax} to long in @samp{%eax}, + +@item +@samp{cwd} --- sign-extend word in @samp{%ax} to long in @samp{%dx:%ax}, + +@item +@samp{cdq} --- sign-extend dword in @samp{%eax} to quad in @samp{%edx:%eax}, +@end itemize + +@noindent +are called @samp{cbtw}, @samp{cwtl}, @samp{cwtd}, and @samp{cltd} in +AT&T naming. @code{_AS__} accepts either naming for these instructions. + +@cindex jump instructions, i386 +@cindex call instructions, i386 +Far call/jump instructions are @samp{lcall} and @samp{ljmp} in +AT&T syntax, but are @samp{call far} and @samp{jump far} in Intel +convention. + +@node i386-Regs, i386-prefixes, i386-Opcodes, i386-Dependent +_CHAPSEC__(1+_GENERIC__) Register Naming + +@cindex i386 registers +@cindex registers, i386 +Register operands are always prefixes with @samp{%}. The 80386 registers +consist of + +@itemize @bullet +@item +the 8 32-bit registers @samp{%eax} (the accumulator), @samp{%ebx}, +@samp{%ecx}, @samp{%edx}, @samp{%edi}, @samp{%esi}, @samp{%ebp} (the +frame pointer), and @samp{%esp} (the stack pointer). + +@item +the 8 16-bit low-ends of these: @samp{%ax}, @samp{%bx}, @samp{%cx}, +@samp{%dx}, @samp{%di}, @samp{%si}, @samp{%bp}, and @samp{%sp}. + +@item +the 8 8-bit registers: @samp{%ah}, @samp{%al}, @samp{%bh}, +@samp{%bl}, @samp{%ch}, @samp{%cl}, @samp{%dh}, and @samp{%dl} (These +are the high-bytes and low-bytes of @samp{%ax}, @samp{%bx}, +@samp{%cx}, and @samp{%dx}) + +@item +the 6 section registers @samp{%cs} (code section), @samp{%ds} +(data section), @samp{%ss} (stack section), @samp{%es}, @samp{%fs}, +and @samp{%gs}. + +@item +the 3 processor control registers @samp{%cr0}, @samp{%cr2}, and +@samp{%cr3}. + +@item +the 6 debug registers @samp{%db0}, @samp{%db1}, @samp{%db2}, +@samp{%db3}, @samp{%db6}, and @samp{%db7}. + +@item +the 2 test registers @samp{%tr6} and @samp{%tr7}. + +@item +the 8 floating point register stack @samp{%st} or equivalently +@samp{%st(0)}, @samp{%st(1)}, @samp{%st(2)}, @samp{%st(3)}, +@samp{%st(4)}, @samp{%st(5)}, @samp{%st(6)}, and @samp{%st(7)}. +@end itemize + +@node i386-prefixes, i386-Memory, i386-Regs, i386-Dependent +_CHAPSEC__(1+_GENERIC__) Opcode Prefixes + +@cindex i386 opcode prefixes +@cindex opcode prefixes, i386 +@cindex prefixes, i386 +Opcode prefixes are used to modify the following opcode. They are used +to repeat string instructions, to provide section overrides, to perform +bus lock operations, and to give operand and address size (16-bit +operands are specified in an instruction by prefixing what would +normally be 32-bit operands with a ``operand size'' opcode prefix). +Opcode prefixes are usually given as single-line instructions with no +operands, and must directly precede the instruction they act upon. For +example, the @samp{scas} (scan string) instruction is repeated with: +@smallexample + repne + scas +@end smallexample + +Here is a list of opcode prefixes: + +@itemize @bullet +@item +@cindex section override prefixes, i386 +Section override prefixes @samp{cs}, @samp{ds}, @samp{ss}, @samp{es}, +@samp{fs}, @samp{gs}. These are automatically added by specifying +using the @var{section}:@var{memory-operand} form for memory references. + +@item +@cindex size prefixes, i386 +Operand/Address size prefixes @samp{data16} and @samp{addr16} +change 32-bit operands/addresses into 16-bit operands/addresses. Note +that 16-bit addressing modes (i.e. 8086 and 80286 addressing modes) +are not supported (yet). + +@item +@cindex bus lock prefixes, i386 +@cindex inhibiting interrupts, i386 +The bus lock prefix @samp{lock} inhibits interrupts during +execution of the instruction it precedes. (This is only valid with +certain instructions; see a 80386 manual for details). + +@item +@cindex coprocessor wait, i386 +The wait for coprocessor prefix @samp{wait} waits for the +coprocessor to complete the current instruction. This should never be +needed for the 80386/80387 combination. + +@item +@cindex repeat prefixes, i386 +The @samp{rep}, @samp{repe}, and @samp{repne} prefixes are added +to string instructions to make them repeat @samp{%ecx} times. +@end itemize + +@node i386-Memory, i386-jumps, i386-prefixes, i386-Dependent +_CHAPSEC__(1+_GENERIC__) Memory References + +@cindex i386 memory references +@cindex memory references, i386 +An Intel syntax indirect memory reference of the form + +@smallexample +@var{section}:[@var{base} + @var{index}*@var{scale} + @var{disp}] +@end smallexample + +@noindent +is translated into the AT&T syntax + +@smallexample +@var{section}:@var{disp}(@var{base}, @var{index}, @var{scale}) +@end smallexample + +@noindent +where @var{base} and @var{index} are the optional 32-bit base and +index registers, @var{disp} is the optional displacement, and +@var{scale}, taking the values 1, 2, 4, and 8, multiplies @var{index} +to calculate the address of the operand. If no @var{scale} is +specified, @var{scale} is taken to be 1. @var{section} specifies the +optional section register for the memory operand, and may override the +default section register (see a 80386 manual for section register +defaults). Note that section overrides in AT&T syntax @emph{must} have +be preceded by a @samp{%}. If you specify a section override which +coincides with the default section register, @code{_AS__} will @emph{not} +output any section register override prefixes to assemble the given +instruction. Thus, section overrides can be specified to emphasize which +section register is used for a given memory operand. + +Here are some examples of Intel and AT&T style memory references: + +@table @asis +@item AT&T: @samp{-4(%ebp)}, Intel: @samp{[ebp - 4]} +@var{base} is @samp{%ebp}; @var{disp} is @samp{-4}. @var{section} is +missing, and the default section is used (@samp{%ss} for addressing with +@samp{%ebp} as the base register). @var{index}, @var{scale} are both missing. + +@item AT&T: @samp{foo(,%eax,4)}, Intel: @samp{[foo + eax*4]} +@var{index} is @samp{%eax} (scaled by a @var{scale} 4); @var{disp} is +@samp{foo}. All other fields are missing. The section register here +defaults to @samp{%ds}. + +@item AT&T: @samp{foo(,1)}; Intel @samp{[foo]} +This uses the value pointed to by @samp{foo} as a memory operand. +Note that @var{base} and @var{index} are both missing, but there is only +@emph{one} @samp{,}. This is a syntactic exception. + +@item AT&T: @samp{%gs:foo}; Intel @samp{gs:foo} +This selects the contents of the variable @samp{foo} with section +register @var{section} being @samp{%gs}. +@end table + +Absolute (as opposed to PC relative) call and jump operands must be +prefixed with @samp{*}. If no @samp{*} is specified, @code{_AS__} will +always choose PC relative addressing for jump/call labels. + +Any instruction that has a memory operand @emph{must} specify its size (byte, +word, or long) with an opcode suffix (@samp{b}, @samp{w}, or @samp{l}, +respectively). + +@node i386-jumps, i386-Float, i386-Memory, i386-Dependent +_CHAPSEC__(1+_GENERIC__) Handling of Jump Instructions + +@cindex jump optimization, i386 +@cindex i386 jump optimization +Jump instructions are always optimized to use the smallest possible +displacements. This is accomplished by using byte (8-bit) displacement +jumps whenever the target is sufficiently close. If a byte displacement +is insufficient a long (32-bit) displacement is used. We do not support +word (16-bit) displacement jumps (i.e. prefixing the jump instruction +with the @samp{addr16} opcode prefix), since the 80386 insists upon masking +@samp{%eip} to 16 bits after the word displacement is added. + +Note that the @samp{jcxz}, @samp{jecxz}, @samp{loop}, @samp{loopz}, +@samp{loope}, @samp{loopnz} and @samp{loopne} instructions only come in +byte displacements, so that it is possible that use of these +instructions (@code{_GCC__} does not use them) will cause the assembler to +print an error message (and generate incorrect code). The AT&T 80386 +assembler tries to get around this problem by expanding @samp{jcxz foo} to +@smallexample + jcxz cx_zero + jmp cx_nonzero +cx_zero: jmp foo +cx_nonzero: +@end smallexample + +@node i386-Float, i386-Notes, i386-jumps, i386-Dependent +_CHAPSEC__(1+_GENERIC__) Floating Point + +@cindex i386 floating point +@cindex floating point, i386 +All 80387 floating point types except packed BCD are supported. +(BCD support may be added without much difficulty). These data +types are 16-, 32-, and 64- bit integers, and single (32-bit), +double (64-bit), and extended (80-bit) precision floating point. +Each supported type has an opcode suffix and a constructor +associated with it. Opcode suffixes specify operand's data +types. Constructors build these data types into memory. + +@itemize @bullet +@item +@cindex @code{float} directive, i386 +@cindex @code{single} directive, i386 +@cindex @code{double} directive, i386 +@cindex @code{tfloat} directive, i386 +Floating point constructors are @samp{.float} or @samp{.single}, +@samp{.double}, and @samp{.tfloat} for 32-, 64-, and 80-bit formats. +These correspond to opcode suffixes @samp{s}, @samp{l}, and @samp{t}. +@samp{t} stands for temporary real, and that the 80387 only supports +this format via the @samp{fldt} (load temporary real to stack top) and +@samp{fstpt} (store temporary real and pop stack) instructions. + +@item +@cindex @code{word} directive, i386 +@cindex @code{long} directive, i386 +@cindex @code{int} directive, i386 +@cindex @code{quad} directive, i386 +Integer constructors are @samp{.word}, @samp{.long} or @samp{.int}, and +@samp{.quad} for the 16-, 32-, and 64-bit integer formats. The corresponding +opcode suffixes are @samp{s} (single), @samp{l} (long), and @samp{q} +(quad). As with the temporary real format the 64-bit @samp{q} format is +only present in the @samp{fildq} (load quad integer to stack top) and +@samp{fistpq} (store quad integer and pop stack) instructions. +@end itemize + +Register to register operations do not require opcode suffixes, +so that @samp{fst %st, %st(1)} is equivalent to @samp{fstl %st, %st(1)}. + +@cindex i386 @code{fwait} instruction +@cindex @code{fwait instruction}, i386 +Since the 80387 automatically synchronizes with the 80386 @samp{fwait} +instructions are almost never needed (this is not the case for the +80286/80287 and 8086/8087 combinations). Therefore, @code{_AS__} suppresses +the @samp{fwait} instruction whenever it is implicitly selected by one +of the @samp{fn@dots{}} instructions. For example, @samp{fsave} and +@samp{fnsave} are treated identically. In general, all the @samp{fn@dots{}} +instructions are made equivalent to @samp{f@dots{}} instructions. If +@samp{fwait} is desired it must be explicitly coded. + +@node i386-Notes, , i386-Float, i386-Dependent +_CHAPSEC__(1+_GENERIC__) Notes + +@cindex i386 @code{mul}, @code{imul} instructions +@cindex @code{mul} instruction, i386 +@cindex @code{imul} instruction, i386 +There is some trickery concerning the @samp{mul} and @samp{imul} +instructions that deserves mention. The 16-, 32-, and 64-bit expanding +multiplies (base opcode @samp{0xf6}; extension 4 for @samp{mul} and 5 +for @samp{imul}) can be output only in the one operand form. Thus, +@samp{imul %ebx, %eax} does @emph{not} select the expanding multiply; +the expanding multiply would clobber the @samp{%edx} register, and this +would confuse @code{_GCC__} output. Use @samp{imul %ebx} to get the +64-bit product in @samp{%edx:%eax}. + +We have added a two operand form of @samp{imul} when the first operand +is an immediate mode expression and the second operand is a register. +This is just a shorthand, so that, multiplying @samp{%eax} by 69, for +example, can be done with @samp{imul $69, %eax} rather than @samp{imul +$69, %eax, %eax}. + +_fi__(_I80386__) +_if__(0) +@c pesch@cygnus.com: we ignore the following chapters, since internals are +@c changing rapidly. These may need to be moved to another +@c book anyhow, if we adopt the model of user/modifier +@c books. +@node Maintenance, Retargeting, _MACH_DEP__, Top +@chapter Maintaining the Assembler +[[this chapter is still being built]] + +@section Design +We had these goals, in descending priority: +@table @b +@item Accuracy. +For every program composed by a compiler, @code{_AS__} should emit +``correct'' code. This leaves some latitude in choosing addressing +modes, order of @code{relocation_info} structures in the object +file, @emph{etc}. + +@item Speed, for usual case. +By far the most common use of @code{_AS__} will be assembling compiler +emissions. + +@item Upward compatibility for existing assembler code. +Well @dots{} we don't support Vax bit fields but everything else +seems to be upward compatible. + +@item Readability. +The code should be maintainable with few surprises. (JF: ha!) + +@end table + +We assumed that disk I/O was slow and expensive while memory was +fast and access to memory was cheap. We expect the in-memory data +structures to be less than 10 times the size of the emitted object +file. (Contrast this with the C compiler where in-memory structures +might be 100 times object file size!) +This suggests: +@itemize @bullet +@item +Try to read the source file from disk only one time. For other +reasons, we keep large chunks of the source file in memory during +assembly so this is not a problem. Also the assembly algorithm +should only scan the source text once if the compiler composed the +text according to a few simple rules. +@item +Emit the object code bytes only once. Don't store values and then +backpatch later. +@item +Build the object file in memory and do direct writes to disk of +large buffers. +@end itemize + +RMS suggested a one-pass algorithm which seems to work well. By not +parsing text during a second pass considerable time is saved on +large programs (@emph{e.g.} the sort of C program @code{yacc} would +emit). + +It happened that the data structures needed to emit relocation +information to the object file were neatly subsumed into the data +structures that do backpatching of addresses after pass 1. + +Many of the functions began life as re-usable modules, loosely +connected. RMS changed this to gain speed. For example, input +parsing routines which used to work on pre-sanitized strings now +must parse raw data. Hence they have to import knowledge of the +assemblers' comment conventions @emph{etc}. + +@section Deprecated Feature(?)s +We have stopped supporting some features: +@itemize @bullet +@item +@code{.org} statements must have @b{defined} expressions. +@item +Vax Bit fields (@kbd{:} operator) are entirely unsupported. +@end itemize + +It might be a good idea to not support these features in a future release: +@itemize @bullet +@item +@kbd{#} should begin a comment, even in column 1. +@item +Why support the logical line & file concept any more? +@item +Subsections are a good candidate for flushing. +Depends on which compilers need them I guess. +@end itemize + +@section Bugs, Ideas, Further Work +Clearly the major improvement is DON'T USE A TEXT-READING +ASSEMBLER for the back end of a compiler. It is much faster to +interpret binary gobbledygook from a compiler's tables than to +ask the compiler to write out human-readable code just so the +assembler can parse it back to binary. + +Assuming you use @code{_AS__} for human written programs: here are +some ideas: +@itemize @bullet +@item +Document (here) @code{APP}. +@item +Take advantage of knowing no spaces except after opcode +to speed up @code{_AS__}. (Modify @code{app.c} to flush useless spaces: +only keep space/tabs at begin of line or between 2 +symbols.) +@item +Put pointers in this documentation to @file{a.out} documentation. +@item +Split the assembler into parts so it can gobble direct binary +from @emph{e.g.} @code{cc}. It is silly for@code{cc} to compose text +just so @code{_AS__} can parse it back to binary. +@item +Rewrite hash functions: I want a more modular, faster library. +@item +Clean up LOTS of code. +@item +Include all the non-@file{.c} files in the maintenance chapter. +@item +Document flonums. +@item +Implement flonum short literals. +@item +Change all talk of expression operands to expression quantities, +or perhaps to expression arguments. +@item +Implement pass 2. +@item +Whenever a @code{.text} or @code{.data} statement is seen, we close +of the current frag with an imaginary @code{.fill 0}. This is +because we only have one obstack for frags, and we can't grow new +frags for a new subsection, then go back to the old subsection and +append bytes to the old frag. All this nonsense goes away if we +give each subsection its own obstack. It makes code simpler in +about 10 places, but nobody has bothered to do it because C compiler +output rarely changes subsections (compared to ending frags with +relaxable addresses, which is common). +@end itemize + +@section Sources +@c The following files in the @file{_AS__} directory +@c are symbolic links to other files, of +@c the same name, in a different directory. +@c @itemize @bullet +@c @item +@c @file{atof_generic.c} +@c @item +@c @file{atof_vax.c} +@c @item +@c @file{flonum_const.c} +@c @item +@c @file{flonum_copy.c} +@c @item +@c @file{flonum_get.c} +@c @item +@c @file{flonum_multip.c} +@c @item +@c @file{flonum_normal.c} +@c @item +@c @file{flonum_print.c} +@c @end itemize + +Here is a list of the source files in the @file{_AS__} directory. + +@table @file +@item app.c +This contains the pre-processing phase, which deletes comments, +handles whitespace, etc. This was recently re-written, since app +used to be a separate program, but RMS wanted it to be inline. + +@item append.c +This is a subroutine to append a string to another string returning a +pointer just after the last @code{char} appended. (JF: All these +little routines should probably all be put in one file.) + +@item as.c +Here you will find the main program of the assembler @code{_AS__}. + +@item expr.c +This is a branch office of @file{read.c}. This understands +expressions, arguments. Inside @code{_AS__}, arguments are called +(expression) @emph{operands}. This is confusing, because we also talk +(elsewhere) about instruction @emph{operands}. Also, expression +operands are called @emph{quantities} explicitly to avoid confusion +with instruction operands. What a mess. + +@item frags.c +This implements the @b{frag} concept. Without frags, finding the +right size for branch instructions would be a lot harder. + +@item hash.c +This contains the symbol table, opcode table @emph{etc.} hashing +functions. + +@item hex_value.c +This is a table of values of digits, for use in atoi() type +functions. Could probably be flushed by using calls to strtol(), or +something similar. + +@item input-file.c +This contains Operating system dependent source file reading +routines. Since error messages often say where we are in reading +the source file, they live here too. Since @code{_AS__} is intended to +run under GNU and Unix only, this might be worth flushing. Anyway, +almost all C compilers support stdio. + +@item input-scrub.c +This deals with calling the pre-processor (if needed) and feeding the +chunks back to the rest of the assembler the right way. + +@item messages.c +This contains operating system independent parts of fatal and +warning message reporting. See @file{append.c} above. + +@item output-file.c +This contains operating system dependent functions that write an +object file for @code{_AS__}. See @file{input-file.c} above. + +@item read.c +This implements all the directives of @code{_AS__}. This also deals +with passing input lines to the machine dependent part of the +assembler. + +@item strstr.c +This is a C library function that isn't in most C libraries yet. +See @file{append.c} above. + +@item subsegs.c +This implements subsections. + +@item symbols.c +This implements symbols. + +@item write.c +This contains the code to perform relaxation, and to write out +the object file. It is mostly operating system independent, but +different OSes have different object file formats in any case. + +@item xmalloc.c +This implements @code{malloc()} or bust. See @file{append.c} above. + +@item xrealloc.c +This implements @code{realloc()} or bust. See @file{append.c} above. + +@item atof-generic.c +The following files were taken from a machine-independent subroutine +library for manipulating floating point numbers and very large +integers. + +@file{atof-generic.c} turns a string into a flonum internal format +floating-point number. + +@item flonum-const.c +This contains some potentially useful floating point numbers in +flonum format. + +@item flonum-copy.c +This copies a flonum. + +@item flonum-multip.c +This multiplies two flonums together. + +@item bignum-copy.c +This copies a bignum. + +@end table + +Here is a table of all the machine-specific files (this includes +both source and header files). Typically, there is a +@var{machine}.c file, a @var{machine}-opcode.h file, and an +atof-@var{machine}.c file. The @var{machine}-opcode.h file should +be identical to the one used by GDB (which uses it for disassembly.) + +@table @file + +@item atof-ieee.c +This contains code to turn a flonum into a ieee literal constant. +This is used by tye 680x0, 32x32, sparc, and i386 versions of @code{_AS__}. + +@item i386-opcode.h +This is the opcode-table for the i386 version of the assembler. + +@item i386.c +This contains all the code for the i386 version of the assembler. + +@item i386.h +This defines constants and macros used by the i386 version of the assembler. + +@item m-generic.h +generic 68020 header file. To be linked to m68k.h on a +non-sun3, non-hpux system. + +@item m-sun2.h +68010 header file for Sun2 workstations. Not well tested. To be linked +to m68k.h on a sun2. (See also @samp{-DSUN_ASM_SYNTAX} in the +@file{Makefile}.) + +@item m-sun3.h +68020 header file for Sun3 workstations. To be linked to m68k.h before +compiling on a Sun3 system. (See also @samp{-DSUN_ASM_SYNTAX} in the +@file{Makefile}.) + +@item m-hpux.h +68020 header file for a HPUX (system 5?) box. Which box, which +version of HPUX, etc? I don't know. + +@item m68k.h +A hard- or symbolic- link to one of @file{m-generic.h}, +@file{m-hpux.h} or @file{m-sun3.h} depending on which kind of +680x0 you are assembling for. (See also @samp{-DSUN_ASM_SYNTAX} in the +@file{Makefile}.) + +@item m68k-opcode.h +Opcode table for 68020. This is now a link to the opcode table +in the @code{GDB} source directory. + +@item m68k.c +All the mc680x0 code, in one huge, slow-to-compile file. + +@item ns32k.c +This contains the code for the ns32032/ns32532 version of the +assembler. + +@item ns32k-opcode.h +This contains the opcode table for the ns32032/ns32532 version +of the assembler. + +@item vax-inst.h +Vax specific file for describing Vax operands and other Vax-ish things. + +@item vax-opcode.h +Vax opcode table. + +@item vax.c +Vax specific parts of @code{_AS__}. Also includes the former files +@file{vax-ins-parse.c}, @file{vax-reg-parse.c} and @file{vip-op.c}. + +@item atof-vax.c +Turns a flonum into a Vax constant. + +@item vms.c +This file contains the special code needed to put out a VMS +style object file for the Vax. + +@end table + +Here is a list of the header files in the source directory. +(Warning: This section may not be very accurate. I didn't +write the header files; I just report them.) Also note that I +think many of these header files could be cleaned up or +eliminated. + +@table @file + +@item a.out.h +This describes the structures used to create the binary header data +inside the object file. Perhaps we should use the one in +@file{/usr/include}? + +@item as.h +This defines all the globally useful things, and pulls in _0__<stdio.h>_1__ +and _0__<assert.h>_1__. + +@item bignum.h +This defines macros useful for dealing with bignums. + +@item expr.h +Structure and macros for dealing with expression() + +@item flonum.h +This defines the structure for dealing with floating point +numbers. It #includes @file{bignum.h}. + +@item frags.h +This contains macro for appending a byte to the current frag. + +@item hash.h +Structures and function definitions for the hashing functions. + +@item input-file.h +Function headers for the input-file.c functions. + +@item md.h +structures and function headers for things defined in the +machine dependent part of the assembler. + +@item obstack.h +This is the GNU systemwide include file for manipulating obstacks. +Since nobody is running under real GNU yet, we include this file. + +@item read.h +Macros and function headers for reading in source files. + +@item struct-symbol.h +Structure definition and macros for dealing with the _AS__ +internal form of a symbol. + +@item subsegs.h +structure definition for dealing with the numbered subsections +of the text and data sections. + +@item symbols.h +Macros and function headers for dealing with symbols. + +@item write.h +Structure for doing section fixups. +@end table + +@comment ~subsection Test Directory +@comment (Note: The test directory seems to have disappeared somewhere +@comment along the line. If you want it, you'll probably have to find a +@comment REALLY OLD dump tape~dots{}) +@comment +@comment The ~file{test/} directory is used for regression testing. +@comment After you modify ~@code{_AS__}, you can get a quick go/nogo +@comment confidence test by running the new ~@code{_AS__} over the source +@comment files in this directory. You use a shell script ~file{test/do}. +@comment +@comment The tests in this suite are evolving. They are not comprehensive. +@comment They have, however, caught hundreds of bugs early in the debugging +@comment cycle of ~@code{_AS__}. Most test statements in this suite were naturally +@comment selected: they were used to demonstrate actual ~@code{_AS__} bugs rather +@comment than being written ~i{a prioi}. +@comment +@comment Another testing suggestion: over 30 bugs have been found simply by +@comment running examples from this manual through ~@code{_AS__}. +@comment Some examples in this manual are selected +@comment to distinguish boundary conditions; they are good for testing ~@code{_AS__}. +@comment +@comment ~subsubsection Regression Testing +@comment Each regression test involves assembling a file and comparing the +@comment actual output of ~@code{_AS__} to ``known good'' output files. Both +@comment the object file and the error/warning message file (stderr) are +@comment inspected. Optionally the ~@code{_AS__} exit status may be checked. +@comment Discrepencies are reported. Each discrepency means either that +@comment you broke some part of ~@code{_AS__} or that the ``known good'' files +@comment are now out of date and should be changed to reflect the new +@comment definition of ``good''. +@comment +@comment Each regression test lives in its own directory, in a tree +@comment rooted in the directory ~file{test/}. Each such directory +@comment has a name ending in ~file{.ret}, where `ret' stands for +@comment REgression Test. The ~file{.ret} ending allows ~code{find +@comment (1)} to find all regression tests in the tree, without +@comment needing to list them explicitly. +@comment +@comment Any ~file{.ret} directory must contain a file called +@comment ~file{input} which is the source file to assemble. During +@comment testing an object file ~file{output} is created, as well as +@comment a file ~file{stdouterr} which contains the output to both +@comment stderr and stderr. If there is a file ~file{output.good} in +@comment the directory, and if ~file{output} contains exactly the +@comment same data as ~file{output.good}, the file ~file{output} is +@comment deleted. Likewise ~file{stdouterr} is removed if it exactly +@comment matches a file ~file{stdouterr.good}. If file +@comment ~file{status.good} is present, containing a decimal number +@comment before a newline, the exit status of ~@code{_AS__} is compared +@comment to this number. If the status numbers are not equal, a file +@comment ~file{status} is written to the directory, containing the +@comment actual status as a decimal number followed by newline. +@comment +@comment Should any of the ~file{*.good} files fail to match their corresponding +@comment actual files, this is noted by a 1-line message on the screen during +@comment the regression test, and you can use ~@code{find (1)} to find any +@comment files named ~file{status}, ~file {output} or ~file{stdouterr}. +@comment +@node Retargeting, Copying, Maintenance, Top +@chapter Teaching the Assembler about a New Machine + +This chapter describes the steps required in order to make the +assembler work with another machine's assembly language. This +chapter is not complete, and only describes the steps in the +broadest terms. You should look at the source for the +currently supported machine in order to discover some of the +details that aren't mentioned here. + +You should create a new file called @file{@var{machine}.c}, and +add the appropriate lines to the file @file{Makefile} so that +you can compile your new version of the assembler. This should +be straighforward; simply add lines similar to the ones there +for the four current versions of the assembler. + +If you want to be compatible with GDB, (and the current +machine-dependent versions of the assembler), you should create +a file called @file{@var{machine}-opcode.h} which should +contain all the information about the names of the machine +instructions, their opcodes, and what addressing modes they +support. If you do this right, the assembler and GDB can share +this file, and you'll only have to write it once. Note that +while you're writing @code{_AS__}, you may want to use an +independent program (if you have access to one), to make sure +that @code{_AS__} is emitting the correct bytes. Since @code{_AS__} +and @code{GDB} share the opcode table, an incorrect opcode +table entry may make invalid bytes look OK when you disassemble +them with @code{GDB}. + +@section Functions You will Have to Write + +Your file @file{@var{machine}.c} should contain definitions for +the following functions and variables. It will need to include +some header files in order to use some of the structures +defined in the machine-independent part of the assembler. The +needed header files are mentioned in the descriptions of the +functions that will need them. + +@table @code + +@item long omagic; +This long integer holds the value to place at the beginning of +the @file{a.out} file. It is usually @samp{OMAGIC}, except on +machines that store additional information in the magic-number. + +@item char comment_chars[]; +This character array holds the values of the characters that +start a comment anywhere in a line. Comments are stripped off +automatically by the machine independent part of the +assembler. Note that the @samp{/*} will always start a +comment, and that only @samp{*/} will end a comment started by +@samp{*/}. + +@item char line_comment_chars[]; +This character array holds the values of the chars that start a +comment only if they are the first (non-whitespace) character +on a line. If the character @samp{#} does not appear in this +list, you may get unexpected results. (Various +machine-independent parts of the assembler treat the comments +@samp{#APP} and @samp{#NO_APP} specially, and assume that lines +that start with @samp{#} are comments.) + +@item char EXP_CHARS[]; +This character array holds the letters that can separate the +mantissa and the exponent of a floating point number. Typical +values are @samp{e} and @samp{E}. + +@item char FLT_CHARS[]; +This character array holds the letters that--when they appear +immediately after a leading zero--indicate that a number is a +floating-point number. (Sort of how 0x indicates that a +hexadecimal number follows.) + +@item pseudo_typeS md_pseudo_table[]; +(@var{pseudo_typeS} is defined in @file{md.h}) +This array contains a list of the machine_dependent directives +the assembler must support. It contains the name of each +pseudo op (Without the leading @samp{.}), a pointer to a +function to be called when that directive is encountered, and +an integer argument to be passed to that function. + +@item void md_begin(void) +This function is called as part of the assembler's +initialization. It should do any initialization required by +any of your other routines. + +@item int md_parse_option(char **optionPTR, int *argcPTR, char ***argvPTR) +This routine is called once for each option on the command line +that the machine-independent part of @code{_AS__} does not +understand. This function should return non-zero if the option +pointed to by @var{optionPTR} is a valid option. If it is not +a valid option, this routine should return zero. The variables +@var{argcPTR} and @var{argvPTR} are provided in case the option +requires a filename or something similar as an argument. If +the option is multi-character, @var{optionPTR} should be +advanced past the end of the option, otherwise every letter in +the option will be treated as a separate single-character +option. + +@item void md_assemble(char *string) +This routine is called for every machine-dependent +non-directive line in the source file. It does all the real +work involved in reading the opcode, parsing the operands, +etc. @var{string} is a pointer to a null-terminated string, +that comprises the input line, with all excess whitespace and +comments removed. + +@item void md_number_to_chars(char *outputPTR,long value,int nbytes) +This routine is called to turn a C long int, short int, or char +into the series of bytes that represents that number on the +target machine. @var{outputPTR} points to an array where the +result should be stored; @var{value} is the value to store; and +@var{nbytes} is the number of bytes in 'value' that should be +stored. + +@item void md_number_to_imm(char *outputPTR,long value,int nbytes) +This routine is called to turn a C long int, short int, or char +into the series of bytes that represent an immediate value on +the target machine. It is identical to the function @code{md_number_to_chars}, +except on NS32K machines.@refill + +@item void md_number_to_disp(char *outputPTR,long value,int nbytes) +This routine is called to turn a C long int, short int, or char +into the series of bytes that represent an displacement value on +the target machine. It is identical to the function @code{md_number_to_chars}, +except on NS32K machines.@refill + +@item void md_number_to_field(char *outputPTR,long value,int nbytes) +This routine is identical to @code{md_number_to_chars}, +except on NS32K machines. + +@item void md_ri_to_chars(struct relocation_info *riPTR,ri) +(@code{struct relocation_info} is defined in @file{a.out.h}) +This routine emits the relocation info in @var{ri} +in the appropriate bit-pattern for the target machine. +The result should be stored in the location pointed +to by @var{riPTR}. This routine may be a no-op unless you are +attempting to do cross-assembly. + +@item char *md_atof(char type,char *outputPTR,int *sizePTR) +This routine turns a series of digits into the appropriate +internal representation for a floating-point number. +@var{type} is a character from @var{FLT_CHARS[]} that describes +what kind of floating point number is wanted; @var{outputPTR} +is a pointer to an array that the result should be stored in; +and @var{sizePTR} is a pointer to an integer where the size (in +bytes) of the result should be stored. This routine should +return an error message, or an empty string (not (char *)0) for +success. + +@item int md_short_jump_size; +This variable holds the (maximum) size in bytes of a short (16 +bit or so) jump created by @code{md_create_short_jump()}. This +variable is used as part of the broken-word feature, and isn't +needed if the assembler is compiled with +@samp{-DWORKING_DOT_WORD}. + +@item int md_long_jump_size; +This variable holds the (maximum) size in bytes of a long (32 +bit or so) jump created by @code{md_create_long_jump()}. This +variable is used as part of the broken-word feature, and isn't +needed if the assembler is compiled with +@samp{-DWORKING_DOT_WORD}. + +@item void md_create_short_jump(char *resultPTR,long from_addr, +@code{long to_addr,fragS *frag,symbolS *to_symbol)} +This function emits a jump from @var{from_addr} to @var{to_addr} in +the array of bytes pointed to by @var{resultPTR}. If this creates a +type of jump that must be relocated, this function should call +@code{fix_new()} with @var{frag} and @var{to_symbol}. The jump +emitted by this function may be smaller than @var{md_short_jump_size}, +but it must never create a larger one. +(If it creates a smaller jump, the extra bytes of memory will not be +used.) This function is used as part of the broken-word feature, +and isn't needed if the assembler is compiled with +@samp{-DWORKING_DOT_WORD}.@refill + +@item void md_create_long_jump(char *ptr,long from_addr, +@code{long to_addr,fragS *frag,symbolS *to_symbol)} +This function is similar to the previous function, +@code{md_create_short_jump()}, except that it creates a long +jump instead of a short one. This function is used as part of +the broken-word feature, and isn't needed if the assembler is +compiled with @samp{-DWORKING_DOT_WORD}. + +@item int md_estimate_size_before_relax(fragS *fragPTR,int segment_type) +This function does the initial setting up for relaxation. This +includes forcing references to still-undefined symbols to the +appropriate addressing modes. + +@item relax_typeS md_relax_table[]; +(relax_typeS is defined in md.h) +This array describes the various machine dependent states a +frag may be in before relaxation. You will need one group of +entries for each type of addressing mode you intend to relax. + +@item void md_convert_frag(fragS *fragPTR) +(@var{fragS} is defined in @file{as.h}) +This routine does the required cleanup after relaxation. +Relaxation has changed the type of the frag to a type that can +reach its destination. This function should adjust the opcode +of the frag to use the appropriate addressing mode. +@var{fragPTR} points to the frag to clean up. + +@item void md_end(void) +This function is called just before the assembler exits. It +need not free up memory unless the operating system doesn't do +it automatically on exit. (In which case you'll also have to +track down all the other places where the assembler allocates +space but never frees it.) + +@end table + +@section External Variables You will Need to Use + +You will need to refer to or change the following external variables +from within the machine-dependent part of the assembler. + +@table @code +@item extern char flagseen[]; +This array holds non-zero values in locations corresponding to +the options that were on the command line. Thus, if the +assembler was called with @samp{-W}, @var{flagseen['W']} would +be non-zero. + +@item extern fragS *frag_now; +This pointer points to the current frag--the frag that bytes +are currently being added to. If nothing else, you will need +to pass it as an argument to various machine-independent +functions. It is maintained automatically by the +frag-manipulating functions; you should never have to change it +yourself. + +@item extern LITTLENUM_TYPE generic_bignum[]; +(@var{LITTLENUM_TYPE} is defined in @file{bignum.h}. +This is where @dfn{bignums}--numbers larger than 32 bits--are +returned when they are encountered in an expression. You will +need to use this if you need to implement directives (or +anything else) that must deal with these large numbers. +@code{Bignums} are of @code{segT} @code{SEG_BIG} (defined in +@file{as.h}, and have a positive @code{X_add_number}. The +@code{X_add_number} of a @code{bignum} is the number of +@code{LITTLENUMS} in @var{generic_bignum} that the number takes +up. + +@item extern FLONUM_TYPE generic_floating_point_number; +(@var{FLONUM_TYPE} is defined in @file{flonum.h}. +The is where @dfn{flonums}--floating-point numbers within +expressions--are returned. @code{Flonums} are of @code{segT} +@code{SEG_BIG}, and have a negative @code{X_add_number}. +@code{Flonums} are returned in a generic format. You will have +to write a routine to turn this generic format into the +appropriate floating-point format for your machine. + +@item extern int need_pass_2; +If this variable is non-zero, the assembler has encountered an +expression that cannot be assembled in a single pass. Since +the second pass isn't implemented, this flag means that the +assembler is punting, and is only looking for additional syntax +errors. (Or something like that.) + +@item extern segT now_seg; +This variable holds the value of the section the assembler is +currently assembling into. + +@end table + +@section External functions will you need + +You will find the following external functions useful (or +indispensable) when you're writing the machine-dependent part +of the assembler. + +@table @code + +@item char *frag_more(int bytes) +This function allocates @var{bytes} more bytes in the current +frag (or starts a new frag, if it can't expand the current frag +any more.) for you to store some object-file bytes in. It +returns a pointer to the bytes, ready for you to store data in. + +@item void fix_new(fragS *frag, int where, short size, symbolS *add_symbol, symbolS *sub_symbol, long offset, int pcrel) +This function stores a relocation fixup to be acted on later. +@var{frag} points to the frag the relocation belongs in; +@var{where} is the location within the frag where the relocation begins; +@var{size} is the size of the relocation, and is usually 1 (a single byte), + 2 (sixteen bits), or 4 (a longword). +The value @var{add_symbol} @minus{} @var{sub_symbol} + @var{offset}, is added to the byte(s) +at _0__@var{frag->literal[where]}_1__. If @var{pcrel} is non-zero, the address of the +location is subtracted from the result. A relocation entry is also added +to the @file{a.out} file. @var{add_symbol}, @var{sub_symbol}, and/or +@var{offset} may be NULL.@refill + +@item char *frag_var(relax_stateT type, int max_chars, int var, +@code{relax_substateT subtype, symbolS *symbol, char *opcode)} +This function creates a machine-dependent frag of type @var{type} +(usually @code{rs_machine_dependent}). +@var{max_chars} is the maximum size in bytes that the frag may grow by; +@var{var} is the current size of the variable end of the frag; +@var{subtype} is the sub-type of the frag. The sub-type is used to index into +@var{md_relax_table[]} during @code{relaxation}. +@var{symbol} is the symbol whose value should be used to when relax-ing this frag. +@var{opcode} points into a byte whose value may have to be modified if the +addressing mode used by this frag changes. It typically points into the +@var{fr_literal[]} of the previous frag, and is used to point to a location +that @code{md_convert_frag()}, may have to change.@refill + +@item void frag_wane(fragS *fragPTR) +This function is useful from within @code{md_convert_frag}. It +changes a frag to type rs_fill, and sets the variable-sized +piece of the frag to zero. The frag will never change in size +again. + +@item segT expression(expressionS *retval) +(@var{segT} is defined in @file{as.h}; @var{expressionS} is defined in @file{expr.h}) +This function parses the string pointed to by the external char +pointer @var{input_line_pointer}, and returns the section-type +of the expression. It also stores the results in the +@var{expressionS} pointed to by @var{retval}. +@var{input_line_pointer} is advanced to point past the end of +the expression. (@var{input_line_pointer} is used by other +parts of the assembler. If you modify it, be sure to restore +it to its original value.) + +@item as_warn(char *message,@dots{}) +If warning messages are disabled, this function does nothing. +Otherwise, it prints out the current file name, and the current +line number, then uses @code{fprintf} to print the +@var{message} and any arguments it was passed. + +@item as_bad(char *message,@dots{}) +This function should be called when @code{_AS__} encounters +conditions that are bad enough that @code{_AS__} should not +produce an object file, but should continue reading input and +printing warning and bad error messages. + +@item as_fatal(char *message,@dots{}) +This function prints out the current file name and line number, +prints the word @samp{FATAL:}, then uses @code{fprintf} to +print the @var{message} and any arguments it was passed. Then +the assembler exits. This function should only be used for +serious, unrecoverable errors. + +@item void float_const(int float_type) +This function reads floating-point constants from the current +input line, and calls @code{md_atof} to assemble them. It is +useful as the function to call for the directives +@samp{.single}, @samp{.double}, @samp{.float}, etc. +@var{float_type} must be a character from @var{FLT_CHARS}. + +@item void demand_empty_rest_of_line(void); +This function can be used by machine-dependent directives to +make sure the rest of the input line is empty. It prints a +warning message if there are additional characters on the line. + +@item long int get_absolute_expression(void) +This function can be used by machine-dependent directives to +read an absolute number from the current input line. It +returns the result. If it isn't given an absolute expression, +it prints a warning message and returns zero. + +@end table + + +@section The concept of Frags + +This assembler works to optimize the size of certain addressing +modes. (e.g. branch instructions) This means the size of many +pieces of object code cannot be determined until after assembly +is finished. (This means that the addresses of symbols cannot be +determined until assembly is finished.) In order to do this, +@code{_AS__} stores the output bytes as @dfn{frags}. + +Here is the definition of a frag (from @file{as.h}) +@smallexample +struct frag +@{ + long int fr_fix; + long int fr_var; + relax_stateT fr_type; + relax_substateT fr_substate; + unsigned long fr_address; + long int fr_offset; + struct symbol *fr_symbol; + char *fr_opcode; + struct frag *fr_next; + char fr_literal[]; +@} +@end smallexample + +@table @var +@item fr_fix +is the size of the fixed-size piece of the frag. + +@item fr_var +is the maximum (?) size of the variable-sized piece of the frag. + +@item fr_type +is the type of the frag. +Current types are: +rs_fill +rs_align +rs_org +rs_machine_dependent + +@item fr_substate +This stores the type of machine-dependent frag this is. (what +kind of addressing mode is being used, and what size is being +tried/will fit/etc. + +@item fr_address +@var{fr_address} is only valid after relaxation is finished. +Before relaxation, the only way to store an address is (pointer +to frag containing the address) plus (offset into the frag). + +@item fr_offset +This contains a number, whose meaning depends on the type of +the frag. +for machine_dependent frags, this contains the offset from +fr_symbol that the frag wants to go to. Thus, for branch +instructions it is usually zero. (unless the instruction was +@samp{jba foo+12} or something like that.) + +@item fr_symbol +for machine_dependent frags, this points to the symbol the frag +needs to reach. + +@item fr_opcode +This points to the location in the frag (or in a previous frag) +of the opcode for the instruction that caused this to be a frag. +@var{fr_opcode} is needed if the actual opcode must be changed +in order to use a different form of the addressing mode. +(For example, if a conditional branch only comes in size tiny, +a large-size branch could be implemented by reversing the sense +of the test, and turning it into a tiny branch over a large jump. +This would require changing the opcode.) + +@var{fr_literal} is a variable-size array that contains the +actual object bytes. A frag consists of a fixed size piece of +object data, (which may be zero bytes long), followed by a +piece of object data whose size may not have been determined +yet. Other information includes the type of the frag (which +controls how it is relaxed), + +@item fr_next +This is the next frag in the singly-linked list. This is +usually only needed by the machine-independent part of +@code{_AS__}. + +@end table +_fi__(0) + +@node Copying, Index, _MACH_DEP__, Top +@unnumbered GNU GENERAL PUBLIC LICENSE + +@cindex license +@cindex GPL +@cindex copying @code{_AS__} +@center Version 2, June 1991 + +@display +Copyright @copyright{} 1989, 1991 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. +@end display + +@unnumberedsec Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU 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. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), 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 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 show them these terms so they know 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. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + +@iftex +@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +@end iftex +@ifinfo +@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +@end ifinfo + +@enumerate +@item +This License 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 derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term ``modification''.) Each licensee is addressed as ``you''. + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + +@item +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 License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +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. + +@item +You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +@enumerate a +@item +You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change. + +@item +You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any +part thereof, to be licensed as a whole at no charge to all third +parties under the terms of this License. + +@item +If the modified program normally reads commands interactively +when run, you must cause it, when started running for such +interactive use in the most ordinary 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 +License. (Exception: if the Program itself is interactive but +does not normally print such an announcement, your work based on +the Program is not required to print an announcement.) +@end enumerate + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +@item +You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + +@enumerate a +@item +Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections +1 and 2 above on a medium customarily used for software interchange; or, + +@item +Accompany it with a written offer, valid for at least three +years, to give any third party, for a charge no more than your +cost of physically performing source distribution, a complete +machine-readable copy of the corresponding source code, to be +distributed under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange; or, + +@item +Accompany it with the information you received as to the offer +to distribute corresponding source code. (This alternative is +allowed only for noncommercial distribution and only if you +received the program in object code or executable form with such +an offer, in accord with Subsection b above.) +@end enumerate + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +@item +You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + +@item +You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing 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 for copying, distributing or modifying +the Program or works based on it. + +@item +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. +You are not responsible for enforcing compliance by third parties to +this License. + +@item +If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +@item +If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + +@item +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 this 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 +this License, you may choose any version ever published by the Free Software +Foundation. + +@item +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. + +@iftex +@heading NO WARRANTY +@end iftex +@ifinfo +@center NO WARRANTY +@end ifinfo + +@item +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. + +@item +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 enumerate + +@iftex +@heading END OF TERMS AND CONDITIONS +@end iftex +@ifinfo +@center END OF TERMS AND CONDITIONS +@end ifinfo + +@page +@unnumberedsec Applying These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, 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. + +@smallexample +@var{one line to give the program's name and an idea of what it does.} +Copyright (C) 19@var{yy} @var{name of author} + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, 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. +@end smallexample + +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: + +@smallexample +Gnomovision version 69, Copyright (C) 19@var{yy} @var{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. +@end smallexample + +The hypothetical commands @samp{show w} and @samp{show c} should show +the appropriate parts of the General Public License. Of course, the +commands you use may be called something other than @samp{show w} and +@samp{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 is a sample; alter the names: + +@smallexample +Yoyodyne, Inc., hereby disclaims all copyright interest in +the program `Gnomovision' (which makes passes at compilers) +written by James Hacker. + +@var{signature of Ty Coon}, 1 April 1989 +Ty Coon, President of Vice +@end smallexample + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +@node Index, , Copying, Top +@unnumbered Index + +@printindex cp + +@summarycontents +@contents +@bye diff --git a/gnu/usr.bin/as/doc/config.status b/gnu/usr.bin/as/doc/config.status new file mode 100644 index 000000000000..f1e7f63fdd36 --- /dev/null +++ b/gnu/usr.bin/as/doc/config.status @@ -0,0 +1,5 @@ +#!/bin/sh +# This file was generated automatically by configure. Do not edit. +# /d/users/pk/src/gnu/usr.bin/gas.1.93/gas/doc was configured as follows: +/d/users/pk/src/gnu/usr.bin/gas.1.93/./configure i386 -target=i386 -norecursion +# diff --git a/gnu/usr.bin/as/doc/configure.in b/gnu/usr.bin/as/doc/configure.in new file mode 100644 index 000000000000..f9820ea19032 --- /dev/null +++ b/gnu/usr.bin/as/doc/configure.in @@ -0,0 +1,34 @@ +# This file is configure.in +# +# Copyright (C) 1987-1992 Free Software Foundation, Inc. +# +# This file is part of GAS, the GNU Assembler. +# +# GAS is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# GAS is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GAS; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +# + +# This file is a shell script that supplies the information necessary +# to tailor a template configure script into the configure script +# appropriate for this directory. For more information, check any +# existing configure script. + +srctrigger=all.m4 +srcname="gas doc" + +# per-host: + +# per-target: + +# end of gas/doc/configure.in diff --git a/gnu/usr.bin/as/doc/gen.m4 b/gnu/usr.bin/as/doc/gen.m4 new file mode 100644 index 000000000000..64a7a223b5f4 --- /dev/null +++ b/gnu/usr.bin/as/doc/gen.m4 @@ -0,0 +1,14 @@ +_divert__(-1) +<$Id: gen.m4,v 1.1 1993/11/03 00:55:32 paul Exp $> +_define__(<_GENERIC__>,<1>) In case none.m4 changes its mind abt default + +_define__(<_AOUT__>,<1>) +_define__(<_COFF__>,<1>) +_define__(<_ELF__>,<1>) + +_define__(<_I80386__>,<1>) +_define__(<_M680X0__>,<1>) +_define__(<_SPARC__>,<1>) +_define__(<_VAX__>,<1>) + +_divert__<> diff --git a/gnu/usr.bin/as/doc/h8.m4 b/gnu/usr.bin/as/doc/h8.m4 new file mode 100644 index 000000000000..ed52c857cf62 --- /dev/null +++ b/gnu/usr.bin/as/doc/h8.m4 @@ -0,0 +1,15 @@ +_divert__(-1) +_define__(<_H8__>,<1>) +_define__(<_AS__>,<as83>) +_define__(<_GENERIC__>,<0>) +_define__(<_HOST__>,<H8/300>) +_define__(<_MACH_DEP__>,<H8/300-Dependent>) +_define__(<_AOUT__>,<0>) +_define__(<_BOUT__>,<0>) +_define__(<_COFF__>,<1>) +_define__(<_ELF__>,<0>) +_define__(<_DIFFTABKLUG__>,0) NO difference-table kluge +_define__(<_IEEEFLOAT__>,1) IEEE floating point +_define__(<_W32__>,0) +_define__(<_W16__>,1) 16-bit words +_divert__<> diff --git a/gnu/usr.bin/as/doc/i80386.m4 b/gnu/usr.bin/as/doc/i80386.m4 new file mode 100644 index 000000000000..e8718aa74716 --- /dev/null +++ b/gnu/usr.bin/as/doc/i80386.m4 @@ -0,0 +1,12 @@ +_divert__(-1) +_define__(<_I80386__>,<1>) +_define__(<_GENERIC__>,<0>) +_define__(<_HOST__>,<Intel 80386>) +_define__(<_MACH_DEP__>,<i386-Dependent>) +_define__(<_AOUT__>,<1>) +_define__(<_BOUT__>,<0>) +_define__(<_COFF__>,<0>) +_define__(<_ELF__>,<0>) +_define__(<_W32__>,0) +_define__(<_W16__>,1) 16-bit words +_divert__<> diff --git a/gnu/usr.bin/as/doc/i960.m4 b/gnu/usr.bin/as/doc/i960.m4 new file mode 100644 index 000000000000..1fca14725df9 --- /dev/null +++ b/gnu/usr.bin/as/doc/i960.m4 @@ -0,0 +1,16 @@ +_divert__(-1) +_define__(<_I960__>,<1>) +_define__(<_AOUT__>,<0>) +_define__(<_BOUT__>,<1>) +_define__(<_COFF__>,<1>) +_define__(<_AS__>,<gas960>) +_define__(<_GCC__>,<gcc960>) +_define__(<_LD__>,<gld960>) +_define__(<_GDB__>,<gdb960>) +_define__(<_HOST__>,<Intel 960>) +_define__(<_MACH_DEP__>,<i960-Dependent>) +_define__(<_DIFFTABKLUG__>,0) NO difference-table kluge +_define__(<_IEEEFLOAT__>,1) IEEE floating point +_define__(<_W32__>,1) 32-bit words +_define__(<_W16__>,0) +_divert__<> diff --git a/gnu/usr.bin/as/doc/m680x0.m4 b/gnu/usr.bin/as/doc/m680x0.m4 new file mode 100644 index 000000000000..4013e72a3646 --- /dev/null +++ b/gnu/usr.bin/as/doc/m680x0.m4 @@ -0,0 +1,8 @@ +_divert__(-1) +_define__(<_GENERIC__>,<0>) +_define__(<_M680X0__>,<1>) +_define__(<_HOST__>,<Motorola 680x0>) +_define__(<_MACH_DEP__>,<M68K-Dependent>) +_define__(<_W32__>,0) +_define__(<_W16__>,1) 16-bit words +_divert__<> diff --git a/gnu/usr.bin/as/doc/none.m4 b/gnu/usr.bin/as/doc/none.m4 new file mode 100644 index 000000000000..275758bc38fe --- /dev/null +++ b/gnu/usr.bin/as/doc/none.m4 @@ -0,0 +1,57 @@ +_divert__(-1) +<$Id: none.m4,v 1.1 1993/11/03 00:55:39 paul Exp $> + +Switches: + +_define__(<_ALL_ARCH__>,<0>) (Meant as most inclusive; file turning + it on is expected to also turn on + all arch-related switches including + "_GENERIC__") +_define__(<_GENERIC__>,<1>) (may not be quite all configs; + meant for "most vanilla" manual) +_define__(<_INTERNALS__>,<0>) + +_define__(<_AOUT__>,<1>) Object formats. Note we turn on one. +_define__(<_BOUT__>,<0>) +_define__(<_COFF__>,<0>) +_define__(<_ELF__>,<0>) + + Properties of the assembler +_define__(<_DIFFTABKLUG__>,1) Do we use the difference-table kluge? +_define__(<_IEEEFLOAT__>,0) IEEE floating-point? +_define__(<_W32__>,0) word is 32 bits +_define__(<_W16__>,1) word is 16 bits + +_define__(<_A29K__>,<0>) Specific architectures. Note none +_define__(<_H8__>,<0>) starts out on. +_define__(<_I80386__>,<0>) +_define__(<_I960__>,<0>) +_define__(<_M680X0__>,<0>) +_define__(<_SPARC__>,<0>) +_define__(<_VAX__>,<0>) +_define__(<_VXWORKS__>,<0>) + +Text: + +Default names; individual configs may override +Assembler: +_define__(<_AS__>,<as>) +C Compiler: +_define__(<_GCC__>,<gcc>) +Linker: +_define__(<_LD__>,<ld>) +Debugger name: +_define__(<_GDBN__>,<GDB>) +Debugger program: +_define__(<_GDBP__>,<gdb>) +Debugger init file: +_define__(<_GDBINIT__>,<.gdbinit>) + +Text for host; individual configs *should* override, but this may +catch some flubs +_define__(<_HOST__>,<machine specific>) + +"Machine Dependent" nodename +_define__(<_MACH_DEP__>,<Machine Dependent>) + +_divert__<> diff --git a/gnu/usr.bin/as/doc/pretex.m4 b/gnu/usr.bin/as/doc/pretex.m4 new file mode 100644 index 000000000000..2c62784da602 --- /dev/null +++ b/gnu/usr.bin/as/doc/pretex.m4 @@ -0,0 +1,268 @@ +divert(-1) -*-Text-*- +` Copyright (c) 1991 Free Software Foundation, Inc.' +` This file defines and documents the M4 macros used ' +` to preprocess some GNU manuals' +` $Id: pretex.m4,v 1.1 1993/11/03 00:55:40 paul Exp $' + +I. INTRODUCTION + +This collection of M4 macros is meant to help in pre-processing texinfo +files to allow configuring them by hosts; for example, the reader of an +as manual who only has access to a 386 may not really want to see crud about +VAXen. + +A preprocessor is used, rather than extending texinfo, because this +way we can hack the conditionals in only one place; otherwise we would +have to write TeX macros, update makeinfo, and update the Emacs +info-formatting functions. + +II. COMPATIBILITY + +These macros should work with GNU m4 and System V m4; they do not work +with Sun or Berkeley M4. + +III. USAGE + +A. M4 INVOCATION +Assume this file is called "pretex.m4". Then, to preprocess a +document "mybook.texinfo" you might do something like the following: + + m4 pretex.m4 none.m4 PARTIC.m4 mybook.texinfo >mybook-PARTIC.texinfo + +---where your path is set to find GNU or SysV "m4", and the other m4 +files mentioned are as follows: + + none.m4: A file that defines, as 0, all the options you might + want to turn on using the conditionals defined below. + Unlike the C preprocessor, m4 does not default + undefined macros to 0. For example, here is a "none.m4" + I have been using: + _divert__(-1) + + _define__(<_ALL_ARCH__>,<0>) + _define__(<_INTERNALS__>,<0>) + + _define__(<_AMD29K__>,<0>) + _define__(<_I80386__>,<0>) + _define__(<_I960__>,<0>) + _define__(<_M680X0__>,<0>) + _define__(<_SPARC__>,<0>) + _define__(<_VAX__>,<0>) + + _divert__<> + + PARTIC.m4: A file that turns on whichever options you actually + want the manual configured for, in this particular + instance. Its contents are similar to one or more of + the lines in "none.m4", but of course the second + argument to _define__ is <1> rather than <0>. + + This is also a convenient place to _define__ any macros + that you want to expand to different text for + different configurations---for example, the name of + the program being described. + +Naturally, these are just suggested conventions; you could put your macro +definitions in any files or combinations of files you like. + +These macros use the characters < and > as m4 quotes; if you need +these characters in your text, you will also want to use the macros +_0__ and _1__ from this package---see the description of "Quote +Handling" in the "Implementation" section below. + +B. WHAT GOES IN THE PRE-TEXINFO SOURCE + +For the most part, the text of your book. In addition, you can +have text that is included only conditionally, using the macros +_if__ and _fi__ defined below. They BOTH take an argument! This is +primarily meant for readability (so a human can more easily see what +conditional end matches what conditional beginning), but the argument +is actually used in the _fi__ as well as the _if__ implementation. +You should always give a _fi__ the same argument as its matching +_if__. Other arguments may appear to work for a while, but are almost +certain to produce the wrong output for some configurations. + +For example, here is an excerpt from the very beginning of the +documentation for GNU as, to name the info file appropriately for +different configurations: + _if__(_ALL_ARCH__) + @setfilename as.info + _fi__(_ALL_ARCH__) + _if__(_M680X0__ && !_ALL_ARCH__) + @setfilename as-m680x0.info + _fi__(_M680X0__ && !_ALL_ARCH__) + _if__(_AMD29K__ && !_ALL_ARCH__) + @setfilename as-29k.info + _fi__(_AMD29K__ && !_ALL_ARCH__) + +Note that you can use Boolean expressions in the arguments; the +expression language is that of the built-in m4 macro `eval', described +in the m4 manual. + +IV. IMPLEMENTATION + +A.PRIMITIVE RENAMING +First, we redefine m4's built-ins to avoid conflict with plain text. +The naming convention used is that our macros all begin with a single +underbar and end with two underbars. The asymmetry is meant to avoid +conflict with some other conventions (which we may want to document) that +are intended to avoid conflict, like ANSI C predefined macros. + +define(`_undefine__',defn(`undefine')) +define(`_define__',defn(`define')) +define(`_defn__',defn(`defn')) +define(`_ppf__',`_define__(`_$1__',_defn__(`$1'))_undefine__(`$1')') +_ppf__(`builtin') +_ppf__(`changecom') +_ppf__(`changequote') +_ppf__(`decr') +_ppf__(`define') +_ppf__(`defn') +_ppf__(`divert') +_ppf__(`divnum') +_ppf__(`dnl') +_ppf__(`dumpdef') +_ppf__(`errprint') +_ppf__(`esyscmd') +_ppf__(`eval') +_ppf__(`format') +_ppf__(`ifdef') +_ppf__(`ifelse') +_ppf__(`include') +_ppf__(`incr') +_ppf__(`index') +_ppf__(`len') +_ppf__(`m4exit') +_ppf__(`m4wrap') +_ppf__(`maketemp') +_ppf__(`patsubst') +_ppf__(`popdef') +_ppf__(`pushdef') +_ppf__(`regexp') +_ppf__(`shift') +_ppf__(`sinclude') +_ppf__(`substr') +_ppf__(`syscmd') +_ppf__(`sysval') +_ppf__(`traceoff') +_ppf__(`traceon') +_ppf__(`translit') +_ppf__(`undefine') +_ppf__(`undivert') +_ppf__(`unix') + +B. QUOTE HANDLING. + +The characters used as quotes by M4, by default, are unfortunately +quite likely to occur in ordinary text. To avoid surprises, we will +use the characters <> ---which are just as suggestive (more so to +Francophones, perhaps) but a little less common in text (save for +those poor Francophones. You win some, you lose some). Still, we +expect also to have to set < and > occasionally in text; to do that, +we define a macro to turn off quote handling (_0__) and a macro to +turn it back on (_1__), according to our convention. + + BEWARE: This seems to make < and > unusable as relational operations + in calls to the builtin "eval". So far I've gotten + along without; but a better choice may be possible. + +Note that we postponed this for a while, for convenience in discussing +the issue and in the primitive renaming---not to mention in defining +_0__ and _1__ themselves! However, the quote redefinitions MUST +precede the _if__ / _fi__ definitions, because M4 will expand the text +as given---if we use the wrong quotes here, we will get the wrong +quotes when we use the conditionals. + +_define__(_0__,`_changequote__(,)')_define__(_1__,`_changequote__(<,>)') +_1__ + +C. CONDITIONALS + +We define two macros, _if__ and _fi__. BOTH take arguments! This is +meant both to help the human reader match up a _fi__ with its +corresponding _if__ and to aid in the implementation. You may use the +full expression syntax supported by M4 (see docn of `eval' builtin in +the m4 manual). + +The conditional macros are carefully defined to avoid introducing +extra whitespace (i.e., blank lines or blank characters). One side +effect exists--- + + BEWARE: text following an `_if__' on the same line is + DISCARDED even if the condition is true; text + following a `_fi__' on the same line is also + always discarded. + +The recommended convention is to always place _if__ and _fi__ on a +line by themselves. This will also aid the human reader. TeX won't +care about the line breaks; as for info, you may want to insert calls +to `@refill' at the end of paragraphs containing conditionalized text, +where you don't want line breaks separating unconditional from +conditional text. info formatting will then give you nice looking +paragraphs in the info file. + +Nesting: conditionals are designed to nest, in the following way: +*nothing* is output between an outer pair of false conditionals, even +if there are true conditionals inside. A false conditional "defeats" +all conditionals within it. The counter _IF_FS__ is used to +implement this; kindly avoid redefining it directly. + +_define__(<_IF_FS__>,<0>) + +NOTE: The definitions for our "pushf" and "popf" macros use eval +rather than incr and decr, because GNU m4 (0.75) tries to call eval +for us when we say "incr" or "decr"---but doesn't notice we've changed +eval's name. + +_define__( + <_pushf__>, + <_define__(<_IF_FS__>, + _eval__((_IF_FS__)+1))>) +_define__( + <_popf__>, + <_ifelse__(0,_IF_FS__, + <<>_dnl__<>>, + <_define__(<_IF_FS__>,_eval__((_IF_FS__)-1))>)>) + +_define__( + <_if__>, + <_ifelse__(1,_eval__( ($1) ), + <<>_dnl__<>>, + <_pushf__<>_divert__(-1)>)>) +_define__( + <_fi__>, + <_ifelse__(1,_eval__( ($1) ), + <<>_dnl__<>>, + <_popf__<>_ifelse__(0,_IF_FS__, + <_divert__<>_dnl__<>>,<>)>)>) + +D. CHAPTER/SECTION MACRO +In a parametrized manual, the heading level may need to be calculated; +for example, a manual that has a chapter on machine dependencies +should be conditionally structured as follows: + - IF the manual is configured for a SINGLE machine type, use +the chapter heading for that machine type, and run headings down +from there (top level for a particular machine is chapter, then within +that we have section, subsection etc); + - ELSE, if MANY machine types are described in the chapter, +use a generic chapter heading such as "@chapter Machine Dependencies", +use "section" for the top level description of EACH machine, and run +headings down from there (top level for a particular machine is +section, then within that we have subsection, subsubsection etc). + +The macro <_CHAPSEC__> is for this purpose: its argument is evaluated (so +you can construct expressions to express choices such as above), then +expands as follows: + 0: @chapter + 1: @section + 2: @subsection + 3: @subsubsection + ...and so on. + +_define__(<_CHAPSEC__>,<@_cs__(_eval__($1))>) +_define__(<_cs__>,<_ifelse__( + 0, $1, <chapter>, + 1, $1, <section>, + <sub<>_cs__(_eval__($1 - 1))>)>) + +_divert__<>_dnl__<> diff --git a/gnu/usr.bin/as/doc/sparc.m4 b/gnu/usr.bin/as/doc/sparc.m4 new file mode 100644 index 000000000000..121855a97865 --- /dev/null +++ b/gnu/usr.bin/as/doc/sparc.m4 @@ -0,0 +1,8 @@ +_divert__(-1) +_define__(<_SPARC__>,<1>) +_define__(<_HOST__>,<SPARC>) +_define__(<_MACH_DEP__>,<Sparc-Dependent>) +_define__(<_IEEEFLOAT__>,1) IEEE floating point +_define__(<_W32__>,1) 32-bit words +_define__(<_W16__>,0) +_divert__<> diff --git a/gnu/usr.bin/as/doc/vax.m4 b/gnu/usr.bin/as/doc/vax.m4 new file mode 100644 index 000000000000..009e3343bbfe --- /dev/null +++ b/gnu/usr.bin/as/doc/vax.m4 @@ -0,0 +1,7 @@ +_divert__(-1) +_define__(<_VAX__>,<1>) +_define__(<_HOST__>,<VAX>) +_define__(<_MACH_DEP__>,<VAX-Dependent>) +_define__(<_W32__>,0) +_define__(<_W16__>,1) 16-bit words +_divert__<> diff --git a/gnu/usr.bin/as/doc/vintage.m4 b/gnu/usr.bin/as/doc/vintage.m4 new file mode 100644 index 000000000000..4e17b9a499a0 --- /dev/null +++ b/gnu/usr.bin/as/doc/vintage.m4 @@ -0,0 +1,11 @@ +_divert__(-1) +<$Id: vintage.m4,v 1.1 1993/11/03 00:55:45 paul Exp $> +_define__(<_ALL_ARCH__>,<1>) +_define__(<_GENERIC__>,<1>) In case none.m4 changes its mind abt default + +_define__(<_AOUT__>,<1>) + +_define__(<_M680X0__>,<1>) +_define__(<_SPARC__>,<1>) + +_divert__<> diff --git a/gnu/usr.bin/as/expr.c b/gnu/usr.bin/as/expr.c new file mode 100644 index 000000000000..25836976042c --- /dev/null +++ b/gnu/usr.bin/as/expr.c @@ -0,0 +1,1000 @@ +/* expr.c -operands, expressions- + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 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. + */ + +#ifndef lint +static char rcsid[] = "$Id: expr.c,v 1.2 1993/11/03 00:51:28 paul Exp $"; +#endif + +#include <ctype.h> +#include <string.h> + +#include "as.h" + +#include "obstack.h" + +#if __STDC__ == 1 +static void clean_up_expression(expressionS *expressionP); +#else /* __STDC__ */ +static void clean_up_expression(); /* Internal. */ +#endif /* not __STDC__ */ +extern const char EXP_CHARS[]; /* JF hide MD floating pt stuff all the same place */ +extern const char FLT_CHARS[]; + +#ifdef LOCAL_LABELS_DOLLAR +extern int local_label_defined[]; +#endif + +/* + * Build any floating-point literal here. + * Also build any bignum literal here. + */ + +/* LITTLENUM_TYPE generic_buffer[6]; */ /* JF this is a hack */ +/* Seems atof_machine can backscan through generic_bignum and hit whatever + happens to be loaded before it in memory. And its way too complicated + for me to fix right. Thus a hack. JF: Just make generic_bignum bigger, + and never write into the early words, thus they'll always be zero. + I hate Dean's floating-point code. Bleh. + */ +LITTLENUM_TYPE generic_bignum[SIZE_OF_LARGE_NUMBER+6]; +FLONUM_TYPE generic_floating_point_number = +{ + &generic_bignum[6], /* low (JF: Was 0) */ + &generic_bignum[SIZE_OF_LARGE_NUMBER+6 - 1], /* high JF: (added +6) */ + 0, /* leader */ + 0, /* exponent */ + 0 /* sign */ + }; +/* If nonzero, we've been asked to assemble nan, +inf or -inf */ +int generic_floating_point_magic; + +/* + * Summary of operand(). + * + * in: Input_line_pointer points to 1st char of operand, which may + * be a space. + * + * out: A expressionS. X_seg determines how to understand the rest of the + * expressionS. + * The operand may have been empty: in this case X_seg == SEG_ABSENT. + * Input_line_pointer->(next non-blank) char after operand. + * + */ + +static segT + operand (expressionP) +register expressionS * expressionP; +{ + register char c; + register char *name; /* points to name of symbol */ + register symbolS * symbolP; /* Points to symbol */ + + extern const char hex_value[]; /* In hex_value.c */ + +#ifdef PIC +/* XXX */ expressionP->X_got_symbol = 0; +#endif + SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */ + c = * input_line_pointer ++; /* Input_line_pointer->past char in c. */ + if (isdigit(c) || (c == 'H' && input_line_pointer[0] == '\'')) + { + register valueT number; /* offset or (absolute) value */ + register short int digit; /* value of next digit in current radix */ + /* invented for humans only, hope */ + /* optimising compiler flushes it! */ + register short int radix; /* 2, 8, 10 or 16 */ + /* 0 means we saw start of a floating- */ + /* point constant. */ + register short int maxdig = 0;/* Highest permitted digit value. */ + register int too_many_digits = 0; /* If we see >= this number of */ + /* digits, assume it is a bignum. */ + register char * digit_2; /*->2nd digit of number. */ + int small; /* TRUE if fits in 32 bits. */ + + + if (c == 'H' || c == '0') { /* non-decimal radix */ + if ((c = *input_line_pointer ++) == 'x' || c == 'X' || c == '\'') { + c = *input_line_pointer ++; /* read past "0x" or "0X" or H' */ + maxdig = radix = 16; + too_many_digits = 9; + } else { + /* If it says '0f' and the line ends or it DOESN'T look like + a floating point #, its a local label ref. DTRT */ + /* likewise for the b's. xoxorich. */ + if ((c == 'f' || c == 'b' || c == 'B') + && (!*input_line_pointer || + (!strchr("+-.0123456789",*input_line_pointer) && + !strchr(EXP_CHARS,*input_line_pointer)))) { + maxdig = radix = 10; + too_many_digits = 11; + c = '0'; + input_line_pointer -= 2; + + } else if (c == 'b' || c == 'B') { + c = *input_line_pointer++; + maxdig = radix = 2; + too_many_digits = 33; + + } else if (c && strchr(FLT_CHARS,c)) { + radix = 0; /* Start of floating-point constant. */ + /* input_line_pointer->1st char of number. */ + expressionP->X_add_number = -(isupper(c) ? tolower(c) : c); + + } else { /* By elimination, assume octal radix. */ + radix = maxdig = 8; + too_many_digits = 11; + } + } /* c == char after "0" or "0x" or "0X" or "0e" etc. */ + } else { + maxdig = radix = 10; + too_many_digits = 11; + } /* if operand starts with a zero */ + + if (radix) { /* Fixed-point integer constant. */ + /* May be bignum, or may fit in 32 bits. */ + /* + * Most numbers fit into 32 bits, and we want this case to be fast. + * So we pretend it will fit into 32 bits. If, after making up a 32 + * bit number, we realise that we have scanned more digits than + * comfortably fit into 32 bits, we re-scan the digits coding + * them into a bignum. For decimal and octal numbers we are conservative: some + * numbers may be assumed bignums when in fact they do fit into 32 bits. + * Numbers of any radix can have excess leading zeros: we strive + * to recognise this and cast them back into 32 bits. + * We must check that the bignum really is more than 32 + * bits, and change it back to a 32-bit number if it fits. + * The number we are looking for is expected to be positive, but + * if it fits into 32 bits as an unsigned number, we let it be a 32-bit + * number. The cavalier approach is for speed in ordinary cases. + */ + digit_2 = input_line_pointer; + for (number=0; (digit=hex_value[c])<maxdig; c = * input_line_pointer ++) + { + number = number * radix + digit; + } + /* C contains character after number. */ + /* Input_line_pointer->char after C. */ + small = input_line_pointer - digit_2 < too_many_digits; + if (!small) + { + /* + * We saw a lot of digits. Manufacture a bignum the hard way. + */ + LITTLENUM_TYPE *leader; /*->high order littlenum of the bignum. */ + LITTLENUM_TYPE *pointer; /*->littlenum we are frobbing now. */ + long carry; + + leader = generic_bignum; + generic_bignum[0] = 0; + generic_bignum[1] = 0; + /* We could just use digit_2, but lets be mnemonic. */ + input_line_pointer = --digit_2; /*->1st digit. */ + c = *input_line_pointer++; + for (; (carry = hex_value[c]) < maxdig; c = *input_line_pointer++) + { + for (pointer = generic_bignum; + pointer <= leader; + pointer++) + { + long work; + + work = carry + radix * *pointer; + *pointer = work & LITTLENUM_MASK; + carry = work >> LITTLENUM_NUMBER_OF_BITS; + } + if (carry) + { + if (leader < generic_bignum + SIZE_OF_LARGE_NUMBER - 1) + { /* Room to grow a longer bignum. */ + *++leader = carry; + } + } + } + /* Again, C is char after number, */ + /* input_line_pointer->after C. */ + know(sizeof (int) * 8 == 32); + know(LITTLENUM_NUMBER_OF_BITS == 16); + /* Hence the constant "2" in the next line. */ + if (leader < generic_bignum + 2) + { /* Will fit into 32 bits. */ + number = + ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS) + | (generic_bignum[0] & LITTLENUM_MASK); + small = 1; + } + else + { + number = leader - generic_bignum + 1; /* Number of littlenums in the bignum. */ + } + } + if (small) + { + /* + * Here with number, in correct radix. c is the next char. + * Note that unlike Un*x, we allow "011f" "0x9f" to + * both mean the same as the (conventional) "9f". This is simply easier + * than checking for strict canonical form. Syntax sux! + */ + if (number<10) + { + if (0 +#ifdef LOCAL_LABELS_FB + || c == 'b' +#endif +#ifdef LOCAL_LABELS_DOLLAR + || (c == '$' && local_label_defined[number]) +#endif + ) + { + /* + * Backward ref to local label. + * Because it is backward, expect it to be DEFINED. + */ + /* + * Construct a local label. + */ + name = local_label_name ((int)number, 0); + if (((symbolP = symbol_find(name)) != NULL) /* seen before */ + && (S_IS_DEFINED(symbolP))) /* symbol is defined: OK */ + { /* Expected path: symbol defined. */ + /* Local labels are never absolute. Don't waste time checking absoluteness. */ + know(SEG_NORMAL(S_GET_SEGMENT(symbolP))); + + expressionP->X_add_symbol = symbolP; + expressionP->X_add_number = 0; + expressionP->X_seg = S_GET_SEGMENT(symbolP); + } + else + { /* Either not seen or not defined. */ + as_bad("Backw. ref to unknown label \"%d:\", 0 assumed.", + number); + expressionP->X_add_number = 0; + expressionP->X_seg = SEG_ABSOLUTE; + } + } + else + { + if (0 +#ifdef LOCAL_LABELS_FB + || c == 'f' +#endif +#ifdef LOCAL_LABELS_DOLLAR + || (c == '$' && !local_label_defined[number]) +#endif + ) + { + /* + * Forward reference. Expect symbol to be undefined or + * unknown. Undefined: seen it before. Unknown: never seen + * it in this pass. + * Construct a local label name, then an undefined symbol. + * Don't create a XSEG frag for it: caller may do that. + * Just return it as never seen before. + */ + name = local_label_name((int)number, 1); + symbolP = symbol_find_or_make(name); + /* We have no need to check symbol properties. */ +#ifndef MANY_SEGMENTS + /* Since "know" puts its arg into a "string", we + can't have newlines in the argument. */ + know(S_GET_SEGMENT(symbolP) == SEG_UNKNOWN || S_GET_SEGMENT(symbolP) == SEG_TEXT || S_GET_SEGMENT(symbolP) == SEG_DATA); +#endif + expressionP->X_add_symbol = symbolP; + expressionP->X_seg = SEG_UNKNOWN; + expressionP->X_subtract_symbol = NULL; + expressionP->X_add_number = 0; + } + else + { /* Really a number, not a local label. */ + expressionP->X_add_number = number; + expressionP->X_seg = SEG_ABSOLUTE; + input_line_pointer--; /* Restore following character. */ + } /* if (c == 'f') */ + } /* if (c == 'b') */ + } + else + { /* Really a number. */ + expressionP->X_add_number = number; + expressionP->X_seg = SEG_ABSOLUTE; + input_line_pointer--; /* Restore following character. */ + } /* if (number<10) */ + } + else + { + expressionP->X_add_number = number; + expressionP->X_seg = SEG_BIG; + input_line_pointer --; /*->char following number. */ + } /* if (small) */ + } /* (If integer constant) */ + else + { /* input_line_pointer->*/ + /* floating-point constant. */ + int error_code; + + error_code = atof_generic + (& input_line_pointer, ".", EXP_CHARS, + & generic_floating_point_number); + + if (error_code) + { + if (error_code == ERROR_EXPONENT_OVERFLOW) + { + as_bad("Bad floating-point constant: exponent overflow, probably assembling junk"); + } + else + { + as_bad("Bad floating-point constant: unknown error code=%d.", error_code); + } + } + expressionP->X_seg = SEG_BIG; + /* input_line_pointer->just after constant, */ + /* which may point to whitespace. */ + know(expressionP->X_add_number < 0); /* < 0 means "floating point". */ + } /* if (not floating-point constant) */ + } + else if (c == '.' && !is_part_of_name(*input_line_pointer)) { + extern struct obstack frags; + + /* + JF: '.' is pseudo symbol with value of current location in current + segment... + */ + symbolP = symbol_new("\001L0", + now_seg, + (valueT)(obstack_next_free(&frags)-frag_now->fr_literal), + frag_now); + + expressionP->X_add_number=0; + expressionP->X_add_symbol=symbolP; + expressionP->X_seg = now_seg; + + } else if (is_name_beginner(c)) { /* here if did not begin with a digit */ + + /* + * Identifier begins here. + * This is kludged for speed, so code is repeated. + */ + name = input_line_pointer - 1; + c = get_symbol_end(); + symbolP = symbol_find_or_make(name); + /* + * If we have an absolute symbol or a reg, then we know its value now. + */ + expressionP->X_seg = S_GET_SEGMENT(symbolP); + switch (expressionP->X_seg) + { + case SEG_ABSOLUTE: + case SEG_REGISTER: + expressionP->X_add_number = S_GET_VALUE(symbolP); + break; + + default: + expressionP->X_add_number = 0; +#ifdef PIC + if (symbolP == GOT_symbol) { + expressionP->X_got_symbol = symbolP; + got_referenced = 1; + } else +#endif + expressionP->X_add_symbol = symbolP; + } + *input_line_pointer = c; + expressionP->X_subtract_symbol = NULL; + } else if (c == '(' || c == '[') {/* didn't begin with digit & not a name */ + (void)expression(expressionP); + /* Expression() will pass trailing whitespace */ + if (c == '(' && *input_line_pointer++ != ')' || + c == '[' && *input_line_pointer++ != ']') { + as_bad("Missing ')' assumed"); + input_line_pointer--; + } + /* here with input_line_pointer->char after "(...)" */ + } else if (c == '~' || c == '-' || c == '+') { + /* unary operator: hope for SEG_ABSOLUTE */ + switch (operand (expressionP)) { + case SEG_ABSOLUTE: + /* input_line_pointer->char after operand */ + if (c == '-') { + expressionP->X_add_number = - expressionP->X_add_number; + /* + * Notice: '-' may overflow: no warning is given. This is compatible + * with other people's assemblers. Sigh. + */ + } else if (c == '~') { + expressionP->X_add_number = ~ expressionP->X_add_number; + } else if (c != '+') { + know(0); + } /* switch on unary operator */ + break; + + default: /* unary on non-absolute is unsuported */ + if (!SEG_NORMAL(operand(expressionP))) + { + as_bad("Unary operator %c ignored because bad operand follows", c); + break; + } + /* Fall through for normal segments ****/ + 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; + } + /* Expression undisturbed from operand(). */ + } + } + else if (c == '\'') + { + /* + * Warning: to conform to other people's assemblers NO ESCAPEMENT is permitted + * for a single quote. The next character, parity errors and all, is taken + * as the value of the operand. VERY KINKY. + */ + expressionP->X_add_number = * input_line_pointer ++; + expressionP->X_seg = SEG_ABSOLUTE; + } + else + { + /* can't imagine any other kind of operand */ + expressionP->X_seg = SEG_ABSENT; + input_line_pointer --; + md_operand (expressionP); + } + /* + * It is more 'efficient' to clean up the expressions when they are created. + * Doing it here saves lines of code. + */ + clean_up_expression(expressionP); + SKIP_WHITESPACE(); /*->1st char after operand. */ + know(*input_line_pointer != ' '); + return(expressionP->X_seg); +} /* operand() */ + +/* Internal. Simplify a struct expression for use by expr() */ + +/* + * In: address of a expressionS. + * The X_seg field of the expressionS may only take certain values. + * Now, we permit SEG_PASS1 to make code smaller & faster. + * Elsewise we waste time special-case testing. Sigh. Ditto SEG_ABSENT. + * Out: expressionS may have been modified: + * 'foo-foo' symbol references cancelled to 0, + * which changes X_seg from SEG_DIFFERENCE to SEG_ABSOLUTE; + * Unused fields zeroed to help expr(). + */ + +static void + clean_up_expression (expressionP) +register expressionS *expressionP; +{ + switch (expressionP->X_seg) { + case SEG_ABSENT: + case SEG_PASS1: + expressionP->X_add_symbol = NULL; + expressionP->X_subtract_symbol = NULL; + expressionP->X_add_number = 0; + break; + + case SEG_BIG: + case SEG_ABSOLUTE: + expressionP->X_subtract_symbol = NULL; + expressionP->X_add_symbol = NULL; + break; + + case SEG_UNKNOWN: + expressionP->X_subtract_symbol = NULL; + break; + + case SEG_DIFFERENCE: + /* + * It does not hurt to 'cancel' NULL == NULL + * when comparing symbols for 'eq'ness. + * It is faster to re-cancel them to NULL + * than to check for this special case. + */ + if (expressionP->X_subtract_symbol == expressionP->X_add_symbol + || (expressionP->X_subtract_symbol + && expressionP->X_add_symbol + && expressionP->X_subtract_symbol->sy_frag == expressionP->X_add_symbol->sy_frag + && S_GET_VALUE(expressionP->X_subtract_symbol) == S_GET_VALUE(expressionP->X_add_symbol))) { + expressionP->X_subtract_symbol = NULL; + expressionP->X_add_symbol = NULL; + expressionP->X_seg = SEG_ABSOLUTE; + } + break; + + case SEG_REGISTER: + expressionP->X_add_symbol = NULL; + expressionP->X_subtract_symbol = NULL; + break; + + default: + if (SEG_NORMAL(expressionP->X_seg)) { + expressionP->X_subtract_symbol = NULL; + } + else { + BAD_CASE (expressionP->X_seg); + } + break; + } +} /* clean_up_expression() */ + +/* + * expr_part () + * + * Internal. Made a function because this code is used in 2 places. + * Generate error or correct X_?????_symbol of expressionS. + */ + +/* + * symbol_1 += symbol_2 ... well ... sort of. + */ + +static segT + expr_part (symbol_1_PP, symbol_2_P) +symbolS ** symbol_1_PP; +symbolS * symbol_2_P; +{ + segT return_value; +#ifndef MANY_SEGMENTS + know((* symbol_1_PP) == NULL || (S_GET_SEGMENT(*symbol_1_PP) == SEG_TEXT) || (S_GET_SEGMENT(*symbol_1_PP) == SEG_DATA) || (S_GET_SEGMENT(*symbol_1_PP) == SEG_BSS) || (!S_IS_DEFINED(* symbol_1_PP))); + know(symbol_2_P == NULL || (S_GET_SEGMENT(symbol_2_P) == SEG_TEXT) || (S_GET_SEGMENT(symbol_2_P) == SEG_DATA) || (S_GET_SEGMENT(symbol_2_P) == SEG_BSS) || (!S_IS_DEFINED(symbol_2_P))); +#endif + if (* symbol_1_PP) + { + if (!S_IS_DEFINED(* symbol_1_PP)) + { + if (symbol_2_P) + { + return_value = SEG_PASS1; + * symbol_1_PP = NULL; + } + else + { + know(!S_IS_DEFINED(* symbol_1_PP)); + return_value = SEG_UNKNOWN; + } + } + else + { + if (symbol_2_P) + { + if (!S_IS_DEFINED(symbol_2_P)) + { + * symbol_1_PP = NULL; + return_value = SEG_PASS1; + } + else + { + /* {seg1} - {seg2} */ + as_bad("Expression too complex, 2 symbols forgotten: \"%s\" \"%s\"", + S_GET_NAME(* symbol_1_PP), S_GET_NAME(symbol_2_P)); + * symbol_1_PP = NULL; + return_value = SEG_ABSOLUTE; + } + } + else + { + return_value = S_GET_SEGMENT(* symbol_1_PP); + } + } + } + else + { /* (* symbol_1_PP) == NULL */ + if (symbol_2_P) + { + * symbol_1_PP = symbol_2_P; + return_value = S_GET_SEGMENT(symbol_2_P); + } + else + { + * symbol_1_PP = NULL; + return_value = SEG_ABSOLUTE; + } + } +#ifndef MANY_SEGMENTS + 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); +#endif + know((*symbol_1_PP) == NULL || (S_GET_SEGMENT(*symbol_1_PP) == return_value)); + return (return_value); +} /* expr_part() */ + +void ps (s) +symbolS *s; +{ + fprintf (stdout, "%s type %s%s", + S_GET_NAME(s), + S_IS_EXTERNAL(s) ? "EXTERNAL " : "", + segment_name(S_GET_SEGMENT(s))); +} +void pe (e) +expressionS *e; +{ + fprintf (stdout, " segment %s\n", segment_name (e->X_seg)); + fprintf (stdout, " add_number %d (%x)\n", + e->X_add_number, e->X_add_number); + if (e->X_add_symbol) { + fprintf (stdout, " add_symbol "); + ps (e->X_add_symbol); + fprintf (stdout, "\n"); + } + if (e->X_subtract_symbol) { + fprintf (stdout, " sub_symbol "); + ps (e->X_subtract_symbol); + fprintf (stdout, "\n"); + } +} + +/* Expression parser. */ + +/* + * We allow an empty expression, and just assume (absolute,0) silently. + * Unary operators and parenthetical expressions are treated as operands. + * As usual, Q == quantity == operand, O == operator, X == expression mnemonics. + * + * We used to do a aho/ullman shift-reduce parser, but the logic got so + * warped that I flushed it and wrote a recursive-descent parser instead. + * Now things are stable, would anybody like to write a fast parser? + * Most expressions are either register (which does not even reach here) + * or 1 symbol. Then "symbol+constant" and "symbol-symbol" are common. + * So I guess it doesn't really matter how inefficient more complex expressions + * are parsed. + * + * After expr(RANK,resultP) input_line_pointer->operator of rank <= RANK. + * Also, we have consumed any leading or trailing spaces (operand does that) + * and done all intervening operators. + */ + +typedef enum +{ + O_illegal, /* (0) what we get for illegal op */ + + O_multiply, /* (1) * */ + O_divide, /* (2) / */ + O_modulus, /* (3) % */ + O_left_shift, /* (4) < */ + O_right_shift, /* (5) > */ + O_bit_inclusive_or, /* (6) | */ + O_bit_or_not, /* (7) ! */ + O_bit_exclusive_or, /* (8) ^ */ + O_bit_and, /* (9) & */ + O_add, /* (10) + */ + O_subtract /* (11) - */ + } +operatorT; + +#define __ O_illegal + +static const operatorT op_encoding[256] = { /* maps ASCII->operators */ + + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + + __, O_bit_or_not, __, __, __, O_modulus, O_bit_and, __, + __, __, O_multiply, O_add, __, O_subtract, __, O_divide, + __, __, __, __, __, __, __, __, + __, __, __, __, O_left_shift, __, O_right_shift, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, O_bit_exclusive_or, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, + __, __, __, __, O_bit_inclusive_or, __, __, __, + + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __ + }; + + +/* + * Rank Examples + * 0 operand, (expression) + * 1 + - + * 2 & ^ ! | + * 3 * / % << >> + */ +static const operator_rankT + op_rank[] = { 0, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1 }; + +/* Return resultP->X_seg. */ +segT expr(rank, resultP) + register operator_rankT rank; /* Larger # is higher rank. */ + register expressionS *resultP; /* Deliver result here. */ +{ + expressionS right; + register operatorT op_left; + register char c_left; /* 1st operator character. */ + register operatorT op_right; + register char c_right; + + know(rank >= 0); + (void) operand(resultP); + know(*input_line_pointer != ' '); /* Operand() gobbles spaces. */ + c_left = *input_line_pointer; /* Potential operator character. */ + op_left = op_encoding[c_left]; + + while (op_left != O_illegal && op_rank[(int) op_left] > rank) { + input_line_pointer++; /*->after 1st character of operator. */ + + /* Operators "<<" and ">>" have 2 characters. */ + if (*input_line_pointer == c_left && (c_left == '<' || c_left == '>')) { + input_line_pointer ++; + } /*->after operator. */ + if (SEG_ABSENT == expr (op_rank[(int) op_left], &right)) { + as_warn("Missing operand value assumed absolute 0."); + resultP->X_add_number = 0; + resultP->X_subtract_symbol = NULL; + resultP->X_add_symbol = NULL; + resultP->X_seg = SEG_ABSOLUTE; + } + + know(*input_line_pointer != ' '); + c_right = *input_line_pointer; + op_right = op_encoding[c_right]; + + if (*input_line_pointer == c_right && (c_right == '<' || c_right == '>')) { + input_line_pointer ++; + } /*->after operator. */ + + know((int) op_right == 0 || op_rank[(int) op_right] <= op_rank[(int) op_left]); + /* input_line_pointer->after right-hand quantity. */ + /* left-hand quantity in resultP */ + /* right-hand quantity in right. */ + /* operator in op_left. */ + if (resultP->X_seg == SEG_PASS1 || right.X_seg == SEG_PASS1) { + resultP->X_seg = SEG_PASS1; + } else { + if (resultP->X_seg == SEG_BIG) { + as_warn("Left operand of %c is a %s. Integer 0 assumed.", + c_left, resultP->X_add_number > 0 ? "bignum" : "float"); + resultP->X_seg = SEG_ABSOLUTE; + resultP->X_add_symbol = 0; + resultP->X_subtract_symbol = 0; + resultP->X_add_number = 0; + } + if (right.X_seg == SEG_BIG) { + as_warn("Right operand of %c is a %s. Integer 0 assumed.", + c_left, right.X_add_number > 0 ? "bignum" : "float"); + right.X_seg = SEG_ABSOLUTE; + right.X_add_symbol = 0; + right.X_subtract_symbol = 0; + right.X_add_number = 0; + } + if (op_left == O_subtract) { + /* + * Convert - into + by exchanging symbols and negating number. + * I know -infinity can't be negated in 2's complement: + * but then it can't be subtracted either. This trick + * does not cause any further inaccuracy. + */ + + register symbolS * symbolP; + + right.X_add_number = - right.X_add_number; + symbolP = right.X_add_symbol; + right.X_add_symbol = right.X_subtract_symbol; + right.X_subtract_symbol = symbolP; + if (symbolP) { + right.X_seg = SEG_DIFFERENCE; + } + op_left = O_add; + } + + if (op_left == O_add) { + segT seg1; + segT seg2; +#ifndef MANY_SEGMENTS + 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); +#endif + clean_up_expression(& right); + clean_up_expression(resultP); + +#ifdef PIC +/* XXX - kludge here to accomodate "_GLOBAL_OFFSET_TABLE + (x - y)" + * expressions: this only works for this special case, the + * _GLOBAL_OFFSET_TABLE thing *must* be the left operand, the whole + * expression is given the segment of right expression (always a DIFFERENCE, + * which should get resolved by fixup_segment()) + */ + if (resultP->X_got_symbol) { + resultP->X_add_symbol = right.X_add_symbol; + resultP->X_subtract_symbol = right.X_subtract_symbol; + seg1 = S_GET_SEGMENT(right.X_add_symbol); + seg2 = S_GET_SEGMENT(right.X_subtract_symbol); + resultP->X_seg = right.X_seg; + } else { +#endif + seg1 = expr_part(&resultP->X_add_symbol, right.X_add_symbol); + seg2 = expr_part(&resultP->X_subtract_symbol, right.X_subtract_symbol); +#ifdef PIC + } +#endif + if (seg1 == SEG_PASS1 || seg2 == SEG_PASS1) { + need_pass_2 = 1; + resultP->X_seg = SEG_PASS1; + } else if (seg2 == SEG_ABSOLUTE) + resultP->X_seg = seg1; + else if (seg1 != SEG_UNKNOWN + && seg1 != SEG_ABSOLUTE + && seg2 != SEG_UNKNOWN + && seg1 != seg2) { + know(seg2 != SEG_ABSOLUTE); + know(resultP->X_subtract_symbol); +#ifndef MANY_SEGMENTS + know(seg1 == SEG_TEXT || seg1 == SEG_DATA || seg1 == SEG_BSS); + know(seg2 == SEG_TEXT || seg2 == SEG_DATA || seg2 == SEG_BSS); +#endif + know(resultP->X_add_symbol); + know(resultP->X_subtract_symbol); + as_bad("Expression too complex: forgetting %s - %s", + S_GET_NAME(resultP->X_add_symbol), + S_GET_NAME(resultP->X_subtract_symbol)); + resultP->X_seg = SEG_ABSOLUTE; + /* Clean_up_expression() will do the rest. */ + } else + resultP->X_seg = SEG_DIFFERENCE; + + resultP->X_add_number += right.X_add_number; + clean_up_expression(resultP); + } else { /* Not +. */ + if (resultP->X_seg == SEG_UNKNOWN || right.X_seg == SEG_UNKNOWN) { + resultP->X_seg = SEG_PASS1; + need_pass_2 = 1; + } else { + resultP->X_subtract_symbol = NULL; + resultP->X_add_symbol = NULL; + + /* Will be SEG_ABSOLUTE. */ + if (resultP->X_seg != SEG_ABSOLUTE || right.X_seg != SEG_ABSOLUTE) { + as_bad("Relocation error. Absolute 0 assumed."); + resultP->X_seg = SEG_ABSOLUTE; + resultP->X_add_number = 0; + } else { + switch (op_left) { + case O_bit_inclusive_or: + resultP->X_add_number |= right.X_add_number; + break; + + case O_modulus: + if (right.X_add_number) { + resultP->X_add_number %= right.X_add_number; + } else { + as_warn("Division by 0. 0 assumed."); + resultP->X_add_number = 0; + } + break; + + case O_bit_and: + resultP->X_add_number &= right.X_add_number; + break; + + case O_multiply: + resultP->X_add_number *= right.X_add_number; + break; + + case O_divide: + if (right.X_add_number) { + resultP->X_add_number /= right.X_add_number; + } else { + as_warn("Division by 0. 0 assumed."); + resultP->X_add_number = 0; + } + break; + + case O_left_shift: + resultP->X_add_number <<= right.X_add_number; + break; + + case O_right_shift: + resultP->X_add_number >>= right.X_add_number; + break; + + case O_bit_exclusive_or: + resultP->X_add_number ^= right.X_add_number; + break; + + case O_bit_or_not: + resultP->X_add_number |= ~ right.X_add_number; + break; + + default: + BAD_CASE(op_left); + break; + } /* switch (operator) */ + } + } /* If we have to force need_pass_2. */ + } /* If operator was +. */ + } /* If we didn't set need_pass_2. */ + op_left = op_right; + } /* While next operator is >= this rank. */ + + return(resultP->X_seg); +} /* expr() */ + +/* + * 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); +} + + +unsigned int get_single_number() +{ + expressionS exp; + operand(&exp); + return exp.X_add_number; + +} +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of expr.c */ diff --git a/gnu/usr.bin/as/expr.h b/gnu/usr.bin/as/expr.h new file mode 100644 index 000000000000..7c12862cbf54 --- /dev/null +++ b/gnu/usr.bin/as/expr.h @@ -0,0 +1,85 @@ +/* expr.h -> header file for expr.c + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: expr.h,v 1.2 1993/11/03 00:51:31 paul Exp $ + */ + + +/* + * 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 */ + symbolS *X_got_symbol; /* got */ + long X_add_number; /* 42. Must be signed. */ + segT X_seg; /* What segment (expr type)? */ +} +expressionS; + +/* result should be type (expressionS *). */ +#define expression(result) expr(0,result) + +/* If an expression is SEG_BIG, look here */ +/* for its value. These common data may */ +/* be clobbered whenever expr() is called. */ +extern FLONUM_TYPE generic_floating_point_number; /* Flonums returned here. */ +/* Enough to hold most precise flonum. */ +extern LITTLENUM_TYPE generic_bignum[]; /* Bignums returned here. */ +#define SIZE_OF_LARGE_NUMBER (20) /* Number of littlenums in above. */ + +typedef char operator_rankT; + +#if __STDC__ == 1 + +char get_symbol_end(void); +segT expr(int rank, expressionS *resultP); +unsigned int get_single_number(void); + +#else /* not __STDC__ */ + +char get_symbol_end(); +segT expr(); +unsigned int get_single_number(); + +#endif /* not __STDC__ */ + +/* end of expr.h */ diff --git a/gnu/usr.bin/as/flo-const.c b/gnu/usr.bin/as/flo-const.c new file mode 100644 index 000000000000..2d346e7a09f8 --- /dev/null +++ b/gnu/usr.bin/as/flo-const.c @@ -0,0 +1,161 @@ +/* flonum_const.c - Useful Flonum constants + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef lint +static char rcsid[] = "$Id: flo-const.c,v 1.1 1993/11/03 00:51:32 paul Exp $"; +#endif + +#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 HO_VMS +dummy1() +{ +} +#endif +/* end of flonum_const.c */ diff --git a/gnu/usr.bin/as/flo-copy.c b/gnu/usr.bin/as/flo-copy.c new file mode 100644 index 000000000000..ba80325856d8 --- /dev/null +++ b/gnu/usr.bin/as/flo-copy.c @@ -0,0 +1,70 @@ +/* flonum_copy.c - copy a flonum + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef lint +static char rcsid[] = "$Id: flo-copy.c,v 1.1 1993/11/03 00:51:34 paul Exp $"; +#endif + +#include "as.h" + +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) { +memset((char *)(out->low + in_length + 1), '\0', out_length - in_length); + } + } + memcpy((void *)(out->low), (void *)(in->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 ! */ + memcpy((void *)( out->low), (void *)(in->low + shorten), (int)((out_length + 1) * sizeof(LITTLENUM_TYPE))); + out->leader = out->high; + out->exponent = in->exponent + shorten; + } + } /* if any significant bits */ +} /* flonum_copy() */ + +/* end of flonum_copy.c */ diff --git a/gnu/usr.bin/as/flonum-mult.c b/gnu/usr.bin/as/flonum-mult.c new file mode 100644 index 000000000000..5952bd653dfc --- /dev/null +++ b/gnu/usr.bin/as/flonum-mult.c @@ -0,0 +1,203 @@ +/* flonum_mult.c - multiply two flonums + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of Gas, the GNU Assembler. + + The GNU assembler is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY. No author or distributor + accepts responsibility to anyone for the consequences of using it + or for whether it serves any particular purpose or works at all, + unless he says so in writing. Refer to the GNU Assembler General + Public License for full details. + + Everyone is granted permission to copy, modify and redistribute + the GNU Assembler, but only under the conditions described in the + GNU Assembler General Public License. A copy of this license is + supposed to have been given to you along with the GNU Assembler + so you can know your rights and responsibilities. It should be + in a file named COPYING. Among other things, the copyright + notice and this notice must be preserved on all copies. */ + +#ifndef lint +static char rcsid[] = "$Id: flonum-mult.c,v 1.2 1993/11/03 00:51:36 paul Exp $"; +#endif + +#include "flonum.h" + +/* plan for a . b => p(roduct) + + + +-------+-------+-/ /-+-------+-------+ + | a | a | ... | a | a | + | A | A-1 | | 1 | 0 | + +-------+-------+-/ /-+-------+-------+ + + + +-------+-------+-/ /-+-------+-------+ + | b | b | ... | b | b | + | B | B-1 | | 1 | 0 | + +-------+-------+-/ /-+-------+-------+ + + + +-------+-------+-/ /-+-------+-/ /-+-------+-------+ + | p | p | ... | p | ... | p | p | + | A+B+1| A+B | | N | | 1 | 0 | + +-------+-------+-/ /-+-------+-/ /-+-------+-------+ + + /^\ + (carry) a .b ... | ... a .b a .b + A B | 0 1 0 0 + | + ... | ... a .b + | 1 0 + | + | ... + | + | + | + | ___ + | \ + +----- P = > a .b + N /__ i j + + N = 0 ... A+B + + for all i,j where i+j=N + [i,j integers > 0] + + a[], b[], p[] may not intersect. + Zero length factors signify 0 significant bits: treat as 0.0. + 0.0 factors do the right thing. + Zero length product OK. + + I chose the ForTran accent "foo[bar]" instead of the C accent "*garply" + because I felt the ForTran way was more intuitive. The C way would + probably yield better code on most C compilers. Dean Elsner. + (C style also gives deeper insight [to me] ... oh well ...) + */ + +void flonum_multip (a, b, product) +const FLONUM_TYPE *a; +const FLONUM_TYPE *b; +FLONUM_TYPE *product; +{ + int size_of_a; /* 0 origin */ + int size_of_b; /* 0 origin */ + int size_of_product; /* 0 origin */ + int size_of_sum; /* 0 origin */ + int extra_product_positions;/* 1 origin */ + unsigned long work; + unsigned long carry; + long exponent; + LITTLENUM_TYPE * q; + long significant; /* TRUE when we emit a non-0 littlenum */ + /* ForTran accent follows. */ + int P; /* Scan product low-order -> high. */ + int N; /* As in sum above. */ + int A; /* Which [] of a? */ + int B; /* Which [] of b? */ + + if ((a->sign != '-' && a->sign != '+') || (b->sign != '-' && b->sign != '+')) { + /* ... + Got to fail somehow. Any suggestions? */ + product->sign=0; + return; + } + product->sign = (a->sign == b->sign) ? '+' : '-'; + size_of_a = a->leader - a->low; + size_of_b = b->leader - b->low; + exponent = a->exponent + b->exponent; + size_of_product = product->high - product->low; + size_of_sum = size_of_a + size_of_b; + extra_product_positions = size_of_product - size_of_sum; + if (extra_product_positions < 0) + { + P = extra_product_positions; /* P < 0 */ + exponent -= extra_product_positions; /* Increases exponent. */ + } + else + { + P = 0; + } + carry = 0; + significant = 0; + for (N = 0; + N <= size_of_sum; + N++) + { + work = carry; + carry = 0; + for (A = 0; + A <= N; + A ++) + { + B = N - A; + if (A <= size_of_a && B <= size_of_b && B >= 0) + { +#ifdef TRACE + printf("a:low[%d.]=%04x b:low[%d.]=%04x work_before=%08x\n", A, a->low[A], B, b->low[B], work); +#endif + 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 of flonum_mult.c */ diff --git a/gnu/usr.bin/as/flonum.h b/gnu/usr.bin/as/flonum.h new file mode 100644 index 000000000000..6135c449d652 --- /dev/null +++ b/gnu/usr.bin/as/flonum.h @@ -0,0 +1,125 @@ +/* flonum.h - Floating point package + + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: flonum.h,v 1.2 1993/11/03 00:51:37 paul Exp $ + */ + + +/***********************************************************************\ + * * + * 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 (__STDC__ != 1) && !defined(const) +#define const /* empty */ +#endif + +#include "bignum.h" + +/***********************************************************************\ + * * + * Variable precision floating point numbers. * + * * + * Exponent is the place value of the low littlenum. E.g.: * + * If 0: low points to the units littlenum. * + * If 1: low points to the LITTLENUM_RADIX littlenum. * + * If -1: low points to the 1/LITTLENUM_RADIX littlenum. * + * * + \***********************************************************************/ + +/* JF: A sign value of 0 means we have been asked to assemble NaN + A sign value of 'P' means we've been asked to assemble +Inf + A sign value of 'N' means we've been asked to assemble -Inf + */ +struct FLONUM_STRUCT +{ + LITTLENUM_TYPE *low; /* low order littlenum of a bignum */ + LITTLENUM_TYPE *high; /* high order littlenum of a bignum */ + LITTLENUM_TYPE *leader; /* -> 1st non-zero littlenum */ + /* If flonum is 0.0, leader == low-1 */ + long exponent; /* base LITTLENUM_RADIX */ + char sign; /* '+' or '-' */ +}; + +typedef struct FLONUM_STRUCT FLONUM_TYPE; + + +/***********************************************************************\ + * * + * Since we can (& do) meet with exponents like 10^5000, it * + * is silly to make a table of ~ 10,000 entries, one for each * + * power of 10. We keep a table where item [n] is a struct * + * FLONUM_FLOATING_POINT representing 10^(2^n). We then * + * multiply appropriate entries from this table to get any * + * particular power of 10. For the example of 10^5000, a table * + * of just 25 entries suffices: 10^(2^-12)...10^(2^+12). * + * * + \***********************************************************************/ + + +extern const FLONUM_TYPE flonum_positive_powers_of_ten[]; +extern const FLONUM_TYPE flonum_negative_powers_of_ten[]; +extern const int table_size_of_flonum_powers_of_ten; +/* Flonum_XXX_powers_of_ten[] table has */ +/* legal indices from 0 to */ +/* + this number inclusive. */ + + + +/***********************************************************************\ + * * + * Declare worker functions. * + * * + \***********************************************************************/ + +#if __STDC__ == 1 + +int atof_generic(char **address_of_string_pointer, + const char *string_of_decimal_marks, + const char *string_of_decimal_exponent_marks, + FLONUM_TYPE *address_of_generic_floating_point_number); + +void flonum_copy(FLONUM_TYPE *in, FLONUM_TYPE *out); +void flonum_multip(const FLONUM_TYPE *a, const FLONUM_TYPE *b, FLONUM_TYPE *product); + +#else /* not __STDC__ */ + +int atof_generic(); +void flonum_copy(); +void flonum_multip(); + +#endif /* not __STDC__ */ + +/***********************************************************************\ + * * + * Declare error codes. * + * * + \***********************************************************************/ + +#define ERROR_EXPONENT_OVERFLOW (2) + +/* end of flonum.h */ diff --git a/gnu/usr.bin/as/frags.c b/gnu/usr.bin/as/frags.c new file mode 100644 index 000000000000..92269e6261ed --- /dev/null +++ b/gnu/usr.bin/as/frags.c @@ -0,0 +1,296 @@ +/* frags.c - manage frags - + + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef lint +static char rcsid[] = "$Id: frags.c,v 1.2 1993/11/03 00:51:39 paul Exp $"; +#endif + +#include "as.h" +#include "subsegs.h" +#include "obstack.h" + +struct obstack frags; /* All, and only, frags live here. */ + +fragS zero_address_frag = { + 0, /* fr_address */ + NULL, /* fr_next */ + 0, /* fr_fix */ + 0, /* fr_var */ + 0, /* fr_symbol */ + 0, /* fr_offset */ + NULL, /* fr_opcode */ + rs_fill, /* fr_type */ + 0, /* fr_subtype */ + 0, /* fr_pcrel_adjust */ + 0, /* fr_bsr */ + 0 /* fr_literal[0] */ + }; + +fragS bss_address_frag = { + 0, /* fr_address. Gets filled in to make up + sy_value-s. */ + NULL, /* fr_next */ + 0, /* fr_fix */ + 0, /* fr_var */ + 0, /* fr_symbol */ + 0, /* fr_offset */ + NULL, /* fr_opcode */ + rs_fill, /* fr_type */ + 0, /* fr_subtype */ + 0, /* fr_pcrel_adjust */ + 0, /* fr_bsr */ + 0 /* fr_literal[0] */ + }; + +/* + * frag_grow() + * + * Internal. + * Try to augment current frag by nchars chars. + * If there is no room, close of the current frag with a ".fill 0" + * and begin a new frag. Unless the new frag has nchars chars available + * do not return. Do not set up any fields of *now_frag. + */ +static void frag_grow(nchars) +unsigned int nchars; +{ + if (obstack_room (&frags) < nchars) { + unsigned int n,oldn; + long oldc; + + frag_wane(frag_now); + frag_new(0); + oldn=(unsigned)-1; + oldc=frags.chunk_size; + frags.chunk_size=2*nchars; + while ((n=obstack_room(&frags))<nchars && n<oldn) { + frag_wane(frag_now); + frag_new(0); + oldn=n; + } + frags.chunk_size=oldc; + } + if (obstack_room (&frags) < nchars) + as_fatal("Can't extend frag %d. chars", nchars); +} /* frag_grow() */ + +/* + * 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 */ + memset(frag_now, '\0', 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; + +#ifndef NO_LISTING + { + extern struct list_info_struct *listing_tail; + frag_now->line = listing_tail; + } +#endif + + 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 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 offset; +char *opcode; +int pcrel_adjust; +char bsr; +{ + register char *retval; + + /* frag_grow (max_chars); */ + retval = obstack_next_free (&frags); + /* obstack_blank_fast (&frags, max_chars); */ /* OVE: so far the only diff */ + frag_now->fr_var = var; + frag_now->fr_type = type; + frag_now->fr_subtype = subtype; + frag_now->fr_symbol = symbol; + frag_now->fr_offset = offset; + frag_now->fr_opcode = opcode; + frag_now->fr_pcrel_adjust = pcrel_adjust; + frag_now->fr_bsr = bsr; + frag_new(max_chars); + return(retval); +} /* frag_variant() */ + +/* + * 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; +} /* frag_align() */ + +/* end of frags.c */ diff --git a/gnu/usr.bin/as/frags.h b/gnu/usr.bin/as/frags.h new file mode 100644 index 000000000000..fc73a55869a3 --- /dev/null +++ b/gnu/usr.bin/as/frags.h @@ -0,0 +1,89 @@ +/* frags.h - Header file for the frag concept. + + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: frags.h,v 1.2 1993/11/03 00:51:40 paul Exp $ + */ + + +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 ); \ + } + + +#if __STDC__ == 1 + +char *frag_more(int nchars); +void frag_align(int alignment, int fill_character); +void frag_new(int old_frags_var_max_size); +void frag_wane(fragS *fragP); + +char *frag_variant(relax_stateT type, + int max_chars, + int var, + relax_substateT subtype, + symbolS *symbol, + long offset, + char *opcode, + int pcrel_adjust, + int bsr); + +char *frag_var(relax_stateT type, + int max_chars, + int var, + relax_substateT subtype, + symbolS *symbol, + long offset, + char *opcode); + +#else /* not __STDC__ */ + +char *frag_more(); +char *frag_var(); +char *frag_variant(); +void frag_align(); +void frag_new(); +void frag_wane(); + +#endif /* not __STDC__ */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of frags.h */ diff --git a/gnu/usr.bin/as/gas-format.el b/gnu/usr.bin/as/gas-format.el new file mode 100644 index 000000000000..32c6426170d3 --- /dev/null +++ b/gnu/usr.bin/as/gas-format.el @@ -0,0 +1,79 @@ +;; -*- lisp-interaction -*- +;; -*- emacs-lisp -*- +;; +;; +;; originally from... +;; Rich's personal .emacs file. feel free to copy. +;; +;; this file sets emacs up for the type of C source code formatting used within +;; gas. I don't use gnu indent. If you do, and find a setup that approximates +;; these settings, please send it to me. +;; +;; Last Mod Thu Feb 13 00:59:16 PST 1992, by rich@sendai +;; + +;; +;; +;; This section sets constants used by c-mode for formating +;; +;; + + +;; If `c-auto-newline' is non-`nil', newlines are inserted both +;;before and after braces that you insert, and after colons and semicolons. +;;Correct C indentation is done on all the lines that are made this way. + +(setq c-auto-newline nil) + + +;; If `c-tab-always-indent' is non-`nil', the TAB command +;;in C mode does indentation only if point is at the left margin or within +;;the line's indentation. If there is non-whitespace to the left of point, +;;then TAB just inserts a tab character in the buffer. Normally, +;;this variable is `nil', and TAB always reindents the current line. + +(setq c-tab-always-indent nil) + +;; C does not have anything analogous to particular function names for which +;;special forms of indentation are desirable. However, it has a different +;;need for customization facilities: many different styles of C indentation +;;are in common use. +;; +;; There are six variables you can set to control the style that Emacs C +;;mode will use. +;; +;;`c-indent-level' +;; Indentation of C statements within surrounding block. The surrounding +;; block's indentation is the indentation of the line on which the +;; open-brace appears. + +(setq c-indent-level 8) + +;;`c-continued-statement-offset' +;; Extra indentation given to a substatement, such as the then-clause of +;; an if or body of a while. + +(setq c-continued-statement-offset 4) + +;;`c-brace-offset' +;; Extra indentation for line if it starts with an open brace. + +(setq c-brace-offset 0) + +;;`c-brace-imaginary-offset' +;; An open brace following other text is treated as if it were this far +;; to the right of the start of its line. + +(setq c-brace-imaginary-offset 0) + +;;`c-argdecl-indent' +;; Indentation level of declarations of C function arguments. + +(setq c-argdecl-indent 0) + +;;`c-label-offset' +;; Extra indentation for line that is a label, or case or default. + +(setq c-label-offset -8) + +;; end of gas-format.el diff --git a/gnu/usr.bin/as/hash.c b/gnu/usr.bin/as/hash.c new file mode 100644 index 000000000000..e42ae12a4aa1 --- /dev/null +++ b/gnu/usr.bin/as/hash.c @@ -0,0 +1,992 @@ +/* hash.c - hash table lookup strings - + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 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!) + * + */ + +#ifndef lint +static char rcsid[] = "$Id: hash.c,v 1.2 1993/11/03 00:51:44 paul Exp $"; +#endif + +#include <stdio.h> + +#ifndef FALSE +#define FALSE (0) +#define TRUE (!FALSE) +#endif /* no FALSE yet */ + +#include <ctype.h> +#define min(a, b) ((a) < (b) ? (a) : (b)) + +#include "as.h" + +#define error as_fatal + +#define DELETED ((char *)1) /* guarenteed invalid address */ +#define START_POWER (11) /* power of two: size of new hash table *//* JF was 6 */ +/* JF These next two aren't used any more. */ +/* #define START_SIZE (64) / * 2 ** START_POWER */ +/* #define START_FULL (32) / * number of entries before table expands */ +#define islive(ptr) (ptr->hash_string && ptr->hash_string != DELETED) +/* above TRUE if a symbol is in entry @ ptr */ + +#define STAT_SIZE (0) /* number of slots in hash table */ +/* the wall does not count here */ +/* we expect this is always a power of 2 */ +#define STAT_ACCESS (1) /* number of hash_ask()s */ +#define STAT__READ (0) /* reading */ +#define STAT__WRITE (1) /* writing */ +#define STAT_COLLIDE (3) /* number of collisions (total) */ +/* this may exceed STAT_ACCESS if we have */ +/* lots of collisions/access */ +#define STAT_USED (5) /* slots used right now */ +#define STATLENGTH (6) /* size of statistics block */ +#if STATLENGTH != HASH_STATLENGTH +Panic! Please make #include "stat.h" agree with previous definitions! +#endif + + /* #define SUSPECT to do runtime checks */ + /* #define TEST to be a test jig for hash...() */ + +#ifdef TEST /* TEST: use smaller hash table */ +#undef START_POWER +#define START_POWER (3) +#undef START_SIZE +#define START_SIZE (8) +#undef START_FULL +#define START_FULL (4) +#endif + +/*------------------ 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; + register int * ip; /* scan stats block of struct hash_control */ + register int * nd; /* limit of stats block */ + + if (( room = (struct hash_entry *) malloc( sizeof(struct + hash_entry)*((1<<START_POWER) + 1) ) ) != NULL) + /* +1 for the wall entry */ + { + if (( retval = (struct hash_control *) malloc(sizeof(struct + hash_control)) ) != NULL) + { + nd = retval->hash_stat + STATLENGTH; + for (ip=retval->hash_stat; ip<nd; ip++) + { + *ip = 0; + } + + retval->hash_stat[STAT_SIZE] = 1<<START_POWER; + retval->hash_mask = (1<<START_POWER) - 1; + retval->hash_sizelog = START_POWER; + /* works for 1's compl ok */ + retval->hash_where = room; + retval->hash_wall = + wall = room + (1<<START_POWER); + retval->hash_full = (1<<START_POWER)/2; + for (entry=room; entry <= wall; entry++) + { + entry->hash_string = NULL; + } + } + } + else + { + retval = NULL; /* no room for table: fake a failure */ + } + return(retval); /* return NULL or set-up structs */ +} + +/* + * h a s h _ d i e ( ) + * + * Table should be empty, but this is not checked. + * To empty the table, try hash_apply()ing a symbol deleter. + * Return to free memory both the hash table and it's control + * block. + * 'handle' has no meaning after this function. + * No errors are recoverable. + */ +void + hash_die(handle) +struct hash_control * handle; +{ + free((char *)handle->hash_where); + free((char *)handle); +} + +/* + * h a s h _ s a y ( ) + * + * Return the size of the statistics table, and as many statistics as + * we can until either (a) we have run out of statistics or (b) caller + * has run out of buffer. + * NOTE: hash_say treats all statistics alike. + * These numbers may change with time, due to insertions, deletions + * and expansions of the table. + * The first "statistic" returned is the length of hash_stat[]. + * Then contents of hash_stat[] are read out (in ascending order) + * until your buffer or hash_stat[] is exausted. + */ +void + hash_say(handle,buffer,bufsiz) +register struct hash_control * handle; +register int buffer[/*bufsiz*/]; +register int bufsiz; +{ + register int * nd; /* limit of statistics block */ + register int * ip; /* scan statistics */ + + ip = handle->hash_stat; + nd = ip + min(bufsiz-1,STATLENGTH); + if (bufsiz>0) /* trust nothing! bufsiz <= 0 is dangerous */ + { + *buffer++ = STATLENGTH; + for (; ip<nd; ip++,buffer++) + { + *buffer = *ip; + } + } +} + +/* + * h a s h _ d e l e t e ( ) + * + * Try to delete a symbol from the table. + * If it was there, return its value (and adjust STAT_USED). + * Otherwise, return NULL. + * Anyway, the symbol is not present after this function. + * + */ +char * /* NULL if string not in table, else */ + /* returns value of deleted symbol */ + hash_delete(handle,string) +register struct hash_control * handle; +register char * string; +{ + register char * retval; /* NULL if string not in table */ + register struct hash_entry * entry; /* NULL or entry of this symbol */ + + entry = hash_ask(handle,string,STAT__WRITE); + if (hash_found) + { + retval = entry->hash_value; + entry->hash_string = DELETED; /* mark as deleted */ + handle->hash_stat[STAT_USED] -= 1; /* slots-in-use count */ +#ifdef SUSPECT + if (handle->hash_stat[STAT_USED]<0) + { + error("hash_delete"); + } +#endif /* def SUSPECT */ + } + else + { + retval = NULL; + } + return(retval); +} + +/* + * h a s h _ r e p l a c e ( ) + * + * Try to replace the old value of a symbol with a new value. + * Normally return the old value. + * Return NULL and don't change the table if the symbol is not already + * in the table. + */ +char * + hash_replace(handle,string,value) +register struct hash_control * handle; +register char * string; +register char * value; +{ + register struct hash_entry * entry; + register char * retval; + + entry = hash_ask(handle,string,STAT__WRITE); + if (hash_found) + { + retval = entry->hash_value; + entry->hash_value = value; + } + else + { + retval = NULL; + } + ; + return (retval); +} + +/* + * h a s h _ i n s e r t ( ) + * + * Insert a (symbol-string, value) into the hash table. + * Return an error string, "" means OK. + * It is an 'error' to insert an existing symbol. + */ + +char * /* return error string */ + hash_insert(handle,string,value) +register struct hash_control * handle; +register char * string; +register char * value; +{ + register struct hash_entry * entry; + register char * retval; + + retval = ""; + if (handle->hash_stat[STAT_USED] > handle->hash_full) + { + retval = hash_grow(handle); + } + if ( ! * retval) + { + entry = hash_ask(handle,string,STAT__WRITE); + if (hash_found) + { + retval = "exists"; + } + else + { + entry->hash_value = value; + entry->hash_string = string; + handle->hash_stat[STAT_USED] += 1; + } + } + return(retval); +} + +/* + * h a s h _ j a m ( ) + * + * Regardless of what was in the symbol table before, after hash_jam() + * the named symbol has the given value. The symbol is either inserted or + * (its value is) relpaced. + * An error message string is returned, "" means OK. + * + * WARNING: this may decide to grow the hashed symbol table. + * To do this, we call hash_grow(), WHICH WILL recursively CALL US. + * + * We report status internally: hash_found is TRUE if we replaced, but + * false if we inserted. + */ +char * + hash_jam(handle,string,value) +register struct hash_control * handle; +register char * string; +register char * value; +{ + register char * retval; + register struct hash_entry * entry; + + retval = ""; + if (handle->hash_stat[STAT_USED] > handle->hash_full) + { + retval = hash_grow(handle); + } + if (! * retval) + { + entry = hash_ask(handle,string,STAT__WRITE); + if ( ! hash_found) + { + entry->hash_string = string; + handle->hash_stat[STAT_USED] += 1; + } + entry->hash_value = value; + } + return(retval); +} + +/* + * h a s h _ g r o w ( ) + * + * Grow a new (bigger) hash table from the old one. + * We choose to double the hash table's size. + * Return a human-scrutible error string: "" if OK. + * Warning! This uses hash_jam(), which had better not recurse + * back here! Hash_jam() conditionally calls us, but we ALWAYS + * call hash_jam()! + * Internal. + */ +static char * + hash_grow(handle) /* make a hash table grow */ +struct hash_control * handle; +{ + register struct hash_entry * newwall; + register struct hash_entry * newwhere; + struct hash_entry * newtrack; + register struct hash_entry * oldtrack; + register struct hash_entry * oldwhere; + register struct hash_entry * oldwall; + register int temp; + int newsize; + char * string; + char * retval; +#ifdef SUSPECT + int oldused; +#endif + + /* + * capture info about old hash table + */ + oldwhere = handle->hash_where; + oldwall = handle->hash_wall; +#ifdef SUSPECT + oldused = handle->hash_stat[STAT_USED]; +#endif + /* + * attempt to get enough room for a hash table twice as big + */ + temp = handle->hash_stat[STAT_SIZE]; + if (( newwhere = (struct hash_entry *) + xmalloc((long)((temp+temp+1)*sizeof(struct hash_entry)))) != NULL) + /* +1 for wall slot */ + { + retval = ""; /* assume success until proven otherwise */ + /* + * have enough room: now we do all the work. + * double the size of everything in handle, + * note: hash_mask frob works for 1's & for 2's complement machines + */ + handle->hash_mask = handle->hash_mask + handle->hash_mask + 1; + handle->hash_stat[STAT_SIZE] <<= 1; + newsize = handle->hash_stat[STAT_SIZE]; + handle->hash_where = newwhere; + handle->hash_full <<= 1; + handle->hash_sizelog += 1; + handle->hash_stat[STAT_USED] = 0; + handle->hash_wall = + newwall = newwhere + newsize; + /* + * set all those pesky new slots to vacant. + */ + for (newtrack=newwhere; newtrack <= newwall; newtrack++) + { + newtrack->hash_string = NULL; + } + /* + * we will do a scan of the old table, the hard way, using the + * new control block to re-insert the data into new hash table. + */ + handle->hash_stat[STAT_USED] = 0; /* inserts will bump it up to correct */ + for (oldtrack=oldwhere; oldtrack < oldwall; oldtrack++) + { + if (((string = oldtrack->hash_string) != NULL) && string != DELETED) + { + if ( * (retval = hash_jam(handle,string,oldtrack->hash_value) ) ) + { + break; + } + } + } +#ifdef SUSPECT + if ( !*retval && handle->hash_stat[STAT_USED] != oldused) + { + retval = "hash_used"; + } +#endif + if (!*retval) + { + /* + * we have a completely faked up control block. + * return the old hash table. + */ + free((char *)oldwhere); + /* + * Here with success. retval is already "". + */ + } + } + else + { + retval = "no room"; + } + return(retval); +} + +/* + * 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) != NULL) && s != DELETED) + { + for (string1=string;;) { + if ((c= *s++) == 0) { + if (!*string1) + hash_found = TRUE; + break; + } + if (*string1++ != c) + break; + } + if (hash_found) + break; + collision++; + slot++; + } + /* + * slot: return: + * in use: we found string slot + * at empty: + * at wall: we fell off: wrap round ???? + * in table: dig here slot + * at DELETED: dig here slot + */ + if (slot == handle->hash_wall) + { + slot = handle->hash_where; /* now look again */ + while (((s = slot->hash_string) != NULL) && s != DELETED) + { + for (string1=string;*s;string1++,s++) { + if (*string1 != *s) + break; + } + if (*s == *string1) { + hash_found = TRUE; + break; + } + collision++; + slot++; + } + /* + * slot: return: + * in use: we found it slot + * empty: wall: ERROR IMPOSSIBLE !!!! + * in table: dig here slot + * DELETED:dig here slot + */ + } + /* fprintf(stderr,"hash_ask(%s)->%d(%d)\n",string,hash_code(handle,string),collision); */ + handle->hash_stat[STAT_COLLIDE+access] += collision; + return(slot); /* also return hash_found */ +} + +/* + * h a s h _ c o d e + * + * Does hashing of symbol string to hash number. + * Internal. + */ +static int + hash_code(handle,string) +struct hash_control * handle; +register char * string; +{ + register long h; /* hash code built here */ + register long c; /* each character lands here */ + register int n; /* Amount to shift h by */ + + n = (handle->hash_sizelog - 3); + h = 0; + while ((c = *string++) != 0) + { + h += c; + h = (h<<3) + (h>>n) + c; + } + return (h & handle->hash_mask); +} + +/* + * Here is a test program to exercise above. + */ +#ifdef TEST + +#define TABLES (6) /* number of hash tables to maintain */ +/* (at once) in any testing */ +#define STATBUFSIZE (12) /* we can have 12 statistics */ + +int statbuf[STATBUFSIZE]; /* display statistics here */ +char answer[100]; /* human farts here */ +char * hashtable[TABLES]; /* we test many hash tables at once */ +char * h; /* points to curent hash_control */ +char ** pp; +char * p; +char * name; +char * value; +int size; +int used; +char command; +int number; /* number 0:TABLES-1 of current hashed */ +/* symbol table */ + +main() +{ + char (*applicatee()); + char * hash_find(); + char * destroy(); + char * what(); + struct hash_control * hash_new(); + char * hash_replace(); + int * ip; + + number = 0; + h = 0; + printf("type h <RETURN> for help\n"); + for (;;) + { + printf("hash_test command: "); + gets(answer); + command = answer[0]; + if (isupper(command)) command = tolower(command); /* ecch! */ + switch (command) + { + case '#': + printf("old hash table #=%d.\n",number); + whattable(); + break; + case '?': + for (pp=hashtable; pp<hashtable+TABLES; pp++) + { + printf("address of hash table #%d control block is %xx\n" + ,pp-hashtable,*pp); + } + break; + case 'a': + hash_apply(h,applicatee); + break; + case 'd': + hash_apply(h,destroy); + hash_die(h); + break; + case 'f': + p = hash_find(h,name=what("symbol")); + printf("value of \"%s\" is \"%s\"\n",name,p?p:"NOT-PRESENT"); + break; + case 'h': + printf("# show old, select new default hash table number\n"); + printf("? display all hashtable control block addresses\n"); + printf("a apply a simple display-er to each symbol in table\n"); + printf("d die: destroy hashtable\n"); + printf("f find value of nominated symbol\n"); + printf("h this help\n"); + printf("i insert value into symbol\n"); + printf("j jam value into symbol\n"); + printf("n new hashtable\n"); + printf("r replace a value with another\n"); + printf("s say what %% of table is used\n"); + printf("q exit this program\n"); + printf("x delete a symbol from table, report its value\n"); + break; + case 'i': + p = hash_insert(h,name=what("symbol"),value=what("value")); + if (*p) + { + printf("symbol=\"%s\" value=\"%s\" error=%s\n",name,value,p); + } + break; + case 'j': + p = hash_jam(h,name=what("symbol"),value=what("value")); + if (*p) + { + printf("symbol=\"%s\" value=\"%s\" error=%s\n",name,value,p); + } + break; + case 'n': + h = hashtable[number] = (char *) hash_new(); + break; + case 'q': + exit(); + case 'r': + p = hash_replace(h,name=what("symbol"),value=what("value")); + printf("old value was \"%s\"\n",p?p:"{}"); + break; + case 's': + hash_say(h,statbuf,STATBUFSIZE); + for (ip=statbuf; ip<statbuf+STATBUFSIZE; ip++) + { + printf("%d ",*ip); + } + printf("\n"); + break; + case 'x': + p = hash_delete(h,name=what("symbol")); + printf("old value was \"%s\"\n",p?p:"{}"); + break; + default: + printf("I can't understand command \"%c\"\n",command); + break; + } + } +} + +char * + what(description) +char * description; +{ + char * retval; + char * malloc(); + + printf(" %s : ",description); + gets(answer); + /* will one day clean up answer here */ + retval = malloc(strlen(answer)+1); + if (!retval) + { + error("room"); + } + (void)strcpy(retval,answer); + return(retval); +} + +char * + destroy(string,value) +char * string; +char * value; +{ + free(string); + free(value); + return(NULL); +} + + +char * + applicatee(string,value) +char * string; +char * value; +{ + printf("%.20s-%.20s\n",string,value); + return(NULL); +} + +whattable() /* determine number: what hash table to use */ +/* also determine h: points to hash_control */ +{ + + for (;;) + { + printf(" what hash table (%d:%d) ? ",0,TABLES-1); + gets(answer); + sscanf(answer,"%d",&number); + if (number >= 0 && number<TABLES) + { + h = hashtable[number]; + if (!h) + { + printf("warning: current hash-table-#%d. has no hash-control\n",number); + } + return; + } + else + { + printf("invalid hash table number: %d\n",number); + } + } +} + + + +#endif /* #ifdef TEST */ + +/* end of hash.c */ diff --git a/gnu/usr.bin/as/hash.h b/gnu/usr.bin/as/hash.h new file mode 100644 index 000000000000..bfb67730d5b6 --- /dev/null +++ b/gnu/usr.bin/as/hash.h @@ -0,0 +1,65 @@ +/* hash.h - for hash.c + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: hash.h,v 1.2 1993/11/03 00:51:46 paul Exp $ + */ + + +#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 */ +}; + + /* fixme: prototype. */ + +/* 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 of hash.h */ diff --git a/gnu/usr.bin/as/hex-value.c b/gnu/usr.bin/as/hex-value.c new file mode 100644 index 000000000000..beea0aed776b --- /dev/null +++ b/gnu/usr.bin/as/hex-value.c @@ -0,0 +1,61 @@ +/* hex_value.c - char=>radix-value - + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 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. + */ + +#ifndef lint +static char rcsid[] = "$Id: hex-value.c,v 1.2 1993/11/03 00:51:47 paul Exp $"; +#endif + +#define __ (42) /* blatently illegal digit value */ +/* exceeds any normal radix */ + +#if (__STDC__ != 1) && !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 HO_VMS +dummy2() +{ +} +#endif + +/* end of hex_value.c */ diff --git a/gnu/usr.bin/as/input-file.c b/gnu/usr.bin/as/input-file.c new file mode 100644 index 000000000000..6bf2aa3b5144 --- /dev/null +++ b/gnu/usr.bin/as/input-file.c @@ -0,0 +1,327 @@ +/* input_file.c - Deal with Input Files - + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 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! + */ + +#ifndef lint +static char rcsid[] = "$Id: input-file.c,v 1.2 1993/11/03 00:51:48 paul Exp $"; +#endif + +#ifdef USG +#define setbuffer(stream, buf, size) setvbuf((stream), (buf), _IOFBF, (size)) +#endif + +#include <stdio.h> +#include <string.h> + +#include "as.h" +#include "input-file.h" + +/* This variable is non-zero if the file currently being read should be + preprocessed by app. It is zero if the file can be read straight in. + */ +int preprocess = 0; + +/* + * This code opens a file, then delivers BUFFER_SIZE character + * chunks of the file on demand. + * BUFFER_SIZE is supposed to be a number chosen for speed. + * The caller only asks once what BUFFER_SIZE is, and asks before + * the nature of the input files (if any) is known. + */ + +#define BUFFER_SIZE (32 * 1024) + +/* + * We use static data: the data area is not sharable. + */ + +FILE *f_in; +/* static JF remove static so app.c can use file_name */ +char * file_name; + +/* Struct for saving the state of this module for file includes. */ +struct saved_file { + FILE *f_in; + char *file_name; + int preprocess; + char *app_save; +}; + +/* These hooks accomodate most operating systems. */ + +void input_file_begin() { + f_in = (FILE *)0; +} + +void input_file_end () { } + +/* Return BUFFER_SIZE. */ +int input_file_buffer_size() { + return (BUFFER_SIZE); +} + +int input_file_is_open() { + return f_in != (FILE *)0; +} + +/* Push the state of our input, returning a pointer to saved info that + can be restored with input_file_pop (). */ +char *input_file_push () { + register struct saved_file *saved; + + saved = (struct saved_file *)xmalloc (sizeof *saved); + + saved->f_in = f_in; + saved->file_name = file_name; + saved->preprocess = preprocess; + if (preprocess) + saved->app_save = app_push (); + + input_file_begin (); /* Initialize for new file */ + + return (char *)saved; +} + +void + input_file_pop (arg) +char *arg; +{ + register struct saved_file *saved = (struct saved_file *)arg; + + input_file_end (); /* Close out old file */ + + f_in = saved->f_in; + file_name = saved->file_name; + preprocess = saved->preprocess; + if (preprocess) + app_pop (saved->app_save); + + free(arg); +} + +#ifdef DONTDEF /* JF save old version in case we need it */ +void + input_file_open (filename, preprocess, debugging) +char * filename; /* "" means use stdin. Must not be 0. */ +int preprocess; /* TRUE if needs app. */ +int debugging; /* TRUE if we are debugging assembler. */ +{ + assert( filename != 0 ); /* Filename may not be NULL. */ + if (filename[0]) + { /* We have a file name. Suck it and see. */ + file_handle = open (filename, O_RDONLY, 0); + file_name = filename; + } + else + { /* use stdin for the input file. */ + file_handle = fileno (stdin); + file_name = "{standard input}"; /* For error messages. */ + } + if (file_handle < 0) + as_perror ("Can't open %s for reading", file_name); + if ( preprocess ) + { + /* + * This code was written in haste for a frobbed BSD 4.2. + * I have a flight to catch: will someone please do proper + * error checks? - Dean. + */ + int pid; + char temporary_file_name[12]; + int fd; + union wait status; + + (void)strcpy (temporary_file_name, "#appXXXXXX"); + (void)mktemp (temporary_file_name); + pid = vfork (); + if (pid == -1) + { + as_perror ("Vfork failed", file_name); + _exit (144); + } + if (pid == 0) + { + (void)dup2 (file_handle, fileno(stdin)); + fd = open (temporary_file_name, O_WRONLY + O_TRUNC + O_CREAT, 0666); + if (fd == -1) + { + (void)write(2,"Can't open temporary\n",21); + _exit (99); + } + (void)dup2 (fd, fileno(stdout)); + /* JF for testing #define PREPROCESSOR "/lib/app" */ +#define PREPROCESSOR "./app" + execl (PREPROCESSOR, PREPROCESSOR, 0); + execl ("app","app",0); + (void)write(2,"Exec of app failed. Get help.\n",31); + (void)unlink(temporary_file_name); + _exit (11); + } + (void)wait (& status); + if (status.w_status & 0xFF00) /* JF was 0xF000, was wrong */ + { + file_handle = -1; + as_bad( "Can't preprocess file \"%s\", status = %xx", file_name, status.w_status ); + } + else + { + file_handle = open (temporary_file_name, O_RDONLY, 0); + if ( ! debugging && unlink(temporary_file_name)) + as_perror ("Can't delete temp file %s", temporary_file_name); + } + if (file_handle == -1) + as_perror ("Can't retrieve temp file %s", temporary_file_name); + } +} +#else + +void + input_file_open (filename,pre) +char * filename; /* "" means use stdin. Must not be 0. */ +int pre; +{ + int c; + char buf[80]; + + preprocess = pre; + + assert( filename != 0 ); /* Filename may not be NULL. */ + if (filename[0]) { /* We have a file name. Suck it and see. */ + f_in=fopen(filename,"r"); + file_name=filename; + } else { /* use stdin for the input file. */ + f_in = stdin; + file_name = "{standard input}"; /* For error messages. */ + } + if (f_in == (FILE *)0) { + as_perror ("Can't open %s for reading", file_name); + return; + } + +#ifndef HO_VMS + /* Ask stdio to buffer our input at BUFFER_SIZE, with a dynamically + allocated buffer. */ + setvbuf(f_in, (char *)NULL, _IOFBF, BUFFER_SIZE); +#endif /* HO_VMS */ + + c = getc(f_in); + if (c == '#') { /* Begins with comment, may not want to preprocess */ + c = getc(f_in); + if (c == 'N') { + fgets(buf,80,f_in); + if (!strcmp(buf,"O_APP\n")) + preprocess=0; + if (!strchr(buf,'\n')) + ungetc('#',f_in); /* It was longer */ + else + ungetc('\n',f_in); + } else if (c == '\n') + ungetc('\n',f_in); + else + ungetc('#',f_in); + } else + ungetc(c,f_in); + +#ifdef DONTDEF + if ( preprocess ) { + char temporary_file_name[17]; + FILE *f_out; + + (void)strcpy (temporary_file_name, "/tmp/#appXXXXXX"); + (void)mktemp (temporary_file_name); + f_out=fopen(temporary_file_name,"w+"); + if (f_out == (FILE *)0) + as_perror("Can't open temp file %s",temporary_file_name); + + /* JF this will have to be moved on any system that + does not support removal of open files. */ + (void)unlink(temporary_file_name);/* JF do it NOW */ + do_scrub(f_in,f_out); + (void)fclose(f_in); /* All done with it */ + (void)rewind(f_out); + f_in=f_out; + } +#endif +} +#endif + +/* Close input file. */ +void input_file_close() { + if (f_in != NULL) { + fclose (f_in); + } /* don't close a null file pointer */ + f_in = 0; +} /* input_file_close() */ + +char * + input_file_give_next_buffer (where) +char * where; /* Where to place 1st character of new buffer. */ +{ + char * return_value; /* -> Last char of what we read, + 1. */ + register int size; + + if (f_in == (FILE *)0) + return 0; + /* + * fflush (stdin); could be done here if you want to synchronise + * stdin and stdout, for the case where our input file is stdin. + * Since the assembler shouldn't do any output to stdout, we + * don't bother to synch output and input. + */ + if (preprocess) { + char *p; + int n; + int ch; + extern FILE *scrub_file; + + scrub_file=f_in; + for (p = where, n = BUFFER_SIZE; n; --n) { + + ch = do_scrub_next_char(scrub_from_file, scrub_to_file); + if (ch == EOF) + break; + *p++=ch; + } + size=BUFFER_SIZE-n; + } else + size= fread(where,sizeof(char),BUFFER_SIZE,f_in); + if (size < 0) + { + as_perror ("Can't read from %s", file_name); + size = 0; + } + if (size) + return_value = where + size; + else + { + if (fclose (f_in)) + as_perror ("Can't close %s", file_name); + f_in = (FILE *)0; + return_value = 0; + } + return (return_value); +} + +/* end of input-file.c */ diff --git a/gnu/usr.bin/as/input-file.h b/gnu/usr.bin/as/input-file.h new file mode 100644 index 000000000000..6a37aefdd3f3 --- /dev/null +++ b/gnu/usr.bin/as/input-file.h @@ -0,0 +1,88 @@ +/* input_file.h header for input-file.c + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/*"input_file.c":Operating-system dependant functions to read source files.*/ + +/* + * $Id: input-file.h,v 1.2 1993/11/03 00:51:50 paul Exp $ + */ + + +/* + * No matter what the operating system, this module must provide the + * following services to its callers. + * + * input_file_begin() Call once before anything else. + * + * input_file_end() Call once after everything else. + * + * input_file_buffer_size() Call anytime. Returns largest possible + * delivery from + * input_file_give_next_buffer(). + * + * input_file_open(name) Call once for each input file. + * + * input_file_give_next_buffer(where) Call once to get each new buffer. + * Return 0: no more chars left in file, + * the file has already been closed. + * Otherwise: return a pointer to just + * after the last character we read + * into the buffer. + * If we can only read 0 characters, then + * end-of-file is faked. + * + * input_file_push() Push state, which can be restored + * later. Does implicit input_file_begin. + * Returns char * to saved state. + * + * input_file_pop (arg) Pops previously saved state. + * + * input_file_close () Closes opened file. + * + * All errors are reported (using as_perror) so caller doesn't have to think + * about I/O errors. No I/O errors are fatal: an end-of-file may be faked. + */ + +#if __STDC__ == 1 + +char *input_file_give_next_buffer(char *where); +char *input_file_push(void); +int input_file_buffer_size(void); +int input_file_is_open(void); +void input_file_begin(void); +void input_file_close(void); +void input_file_end(void); +void input_file_open(char *filename, int pre); +void input_file_pop(char *arg); + +#else /* not __STDC__ */ + +char *input_file_give_next_buffer(); +char *input_file_push(); +int input_file_buffer_size(); +int input_file_is_open(); +void input_file_begin(); +void input_file_close(); +void input_file_end(); +void input_file_open(); +void input_file_pop(); + +#endif /* not __STDC__ */ + +/* end of input_file.h */ diff --git a/gnu/usr.bin/as/input-scrub.c b/gnu/usr.bin/as/input-scrub.c new file mode 100644 index 000000000000..b263358628bb --- /dev/null +++ b/gnu/usr.bin/as/input-scrub.c @@ -0,0 +1,436 @@ +/* input_scrub.c - Break up input buffers into whole numbers of lines. + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef lint +static char rcsid[] = "$Id: input-scrub.c,v 1.2 1993/11/03 00:51:51 paul Exp $"; +#endif + +#include <errno.h> /* Need this to make errno declaration right */ +#include "as.h" +#include "input-file.h" + +/* + * O/S independent module to supply buffers of sanitised source code + * to rest of assembler. We get sanitized input data of arbitrary length. + * We break these buffers on line boundaries, recombine pieces that + * were broken across buffers, and return a buffer of full lines to + * the caller. + * The last partial line begins the next buffer we build and return to caller. + * The buffer returned to caller is preceeded by BEFORE_STRING and followed + * by AFTER_STRING, as sentinels. The last character before AFTER_STRING + * is a newline. + * Also looks after line numbers, for e.g. error messages. + */ + +/* + * We don't care how filthy our buffers are, but our callers assume + * that the following sanitation has already been done. + * + * No comments, reduce a comment to a space. + * Reduce a tab to a space unless it is 1st char of line. + * All multiple tabs and spaces collapsed into 1 char. Tab only + * legal if 1st char of line. + * # line file statements converted to .line x;.file y; statements. + * Escaped newlines at end of line: remove them but add as many newlines + * to end of statement as you removed in the middle, to synch line numbers. + */ + +#define BEFORE_STRING ("\n") +#define AFTER_STRING ("\0") /* memcpy of 0 chars might choke. */ +#define BEFORE_SIZE (1) +#define AFTER_SIZE (1) + +static char * buffer_start; /*->1st char of full buffer area. */ +static char * partial_where; /*->after last full line in buffer. */ +static int partial_size; /* >= 0. Number of chars in partial line in buffer. */ +static char save_source[AFTER_SIZE]; +/* Because we need AFTER_STRING just after last */ +/* full line, it clobbers 1st part of partial */ +/* line. So we preserve 1st part of partial */ +/* line here. */ +static int buffer_length; /* What is the largest size buffer that */ +/* input_file_give_next_buffer() could */ +/* return to us? */ + +/* Saved information about the file that .include'd this one. When we hit EOF, + we automatically pop to that file. */ + +static char *next_saved_file; + +/* We can have more than one source file open at once, though the info for all + but the latest one are saved off in a struct input_save. These files remain + open, so we are limited by the number of open files allowed by the + underlying OS. We may also sequentially read more than one source file in an + assembly. */ + +/* We must track the physical file and line number for error messages. We also + track a "logical" file and line number corresponding to (C?) compiler + source line numbers. Whenever we open a file we must fill in + physical_input_file. So if it is NULL we have not opened any files yet. */ + +char *physical_input_file; +char *logical_input_file; + +typedef unsigned int line_numberT; /* 1-origin line number in a source file. */ +/* A line ends in '\n' or eof. */ + +line_numberT physical_input_line; +line_numberT logical_input_line; + +/* Struct used to save the state of the input handler during include files */ +struct input_save { + char *buffer_start; + char *partial_where; + int partial_size; + char save_source[AFTER_SIZE]; + int buffer_length; + char *physical_input_file; + char *logical_input_file; + line_numberT physical_input_line; + line_numberT logical_input_line; + char *next_saved_file; /* Chain of input_saves */ + char *input_file_save; /* Saved state of input routines */ + char *saved_position; /* Caller's saved position in buf */ +}; + +#if __STDC__ == 1 +static void as_1_char(unsigned int c, FILE *stream); +#else /* __STDC__ */ +static void as_1_char(); +#endif /* not __STDC__ */ + +/* Push the state of input reading and scrubbing so that we can #include. + The return value is a 'void *' (fudged for old compilers) to a save + area, which can be restored by passing it to input_scrub_pop(). */ +char *input_scrub_push(saved_position) +char *saved_position; +{ + register struct input_save *saved; + + saved = (struct input_save *) xmalloc(sizeof *saved); + + saved->saved_position = saved_position; + saved->buffer_start = buffer_start; + saved->partial_where = partial_where; + saved->partial_size = partial_size; + saved->buffer_length = buffer_length; + saved->physical_input_file = physical_input_file; + saved->logical_input_file = logical_input_file; + saved->physical_input_line = physical_input_line; + saved->logical_input_line = logical_input_line; + memcpy(save_source, saved->save_source, sizeof(save_source)); + saved->next_saved_file = next_saved_file; + saved->input_file_save = input_file_push(); + + input_scrub_begin(); /* Reinitialize! */ + + return((char *) saved); +} /* input_scrub_push() */ + +char * + input_scrub_pop (arg) +char *arg; +{ + register struct input_save *saved; + char *saved_position; + + input_scrub_end (); /* Finish off old buffer */ + + saved = (struct input_save *)arg; + + input_file_pop (saved->input_file_save); + saved_position = saved->saved_position; + buffer_start = saved->buffer_start; + buffer_length = saved->buffer_length; + physical_input_file = saved->physical_input_file; + logical_input_file = saved->logical_input_file; + physical_input_line = saved->physical_input_line; + logical_input_line = saved->logical_input_line; + partial_where = saved->partial_where; + partial_size = saved->partial_size; + next_saved_file = saved->next_saved_file; + memcpy(saved->save_source, save_source, sizeof (save_source)); + + free(arg); + return saved_position; +} + + +void + input_scrub_begin () +{ + know(strlen(BEFORE_STRING) == BEFORE_SIZE); + know(strlen(AFTER_STRING) == AFTER_SIZE || (AFTER_STRING[0] == '\0' && AFTER_SIZE == 1)); + + input_file_begin (); + + buffer_length = input_file_buffer_size (); + + buffer_start = xmalloc((long)(BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE)); + memcpy(buffer_start, BEFORE_STRING, (int) BEFORE_SIZE); + + /* Line number things. */ + logical_input_line = 0; + logical_input_file = (char *)NULL; + physical_input_file = NULL; /* No file read yet. */ + next_saved_file = NULL; /* At EOF, don't pop to any other file */ + do_scrub_begin(); +} + +void + input_scrub_end () +{ + if (buffer_start) + { + free (buffer_start); + buffer_start = 0; + input_file_end (); + } +} + +/* Start reading input from a new file. */ + +char * /* Return start of caller's part of buffer. */ + input_scrub_new_file (filename) +char * filename; +{ + input_file_open (filename, !flagseen['f']); + physical_input_file = filename[0] ? filename : "{standard input}"; + physical_input_line = 0; + + partial_size = 0; + return (buffer_start + BEFORE_SIZE); +} + + +/* Include a file from the current file. Save our state, cause it to + be restored on EOF, and begin handling a new file. Same result as + input_scrub_new_file. */ + +char * + input_scrub_include_file (filename, position) +char *filename; +char *position; +{ + next_saved_file = input_scrub_push(position); + return input_scrub_new_file (filename); +} + +void + input_scrub_close () +{ + input_file_close (); +} +char * + input_scrub_next_buffer (bufp) +char **bufp; +{ + register char * limit; /*->just after last char of buffer. */ + + *bufp = buffer_start + BEFORE_SIZE; + +#ifdef DONTDEF + if (preprocess) { + if (save_buffer) { + *bufp = save_buffer; + save_buffer = 0; + } + limit = input_file_give_next_buffer(buffer_start+BEFORE_SIZE); + if (!limit) { + partial_where = 0; + if (partial_size) + as_warn("Partial line at end of file ignored"); + return partial_where; + } + + if (partial_size) + memcpy(partial_where, save_source, (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; + memcpy(save_source, partial_where, (int) AFTER_SIZE); + memcpy(partial_where, AFTER_STRING, (int) AFTER_SIZE); + + save_buffer = *bufp; + *bufp = out_string; + + return partial_where; + } + + /* We're not preprocessing. Do the right thing */ +#endif + if (partial_size) { + memcpy(buffer_start + BEFORE_SIZE, partial_where, (int) partial_size); + memcpy(buffer_start + BEFORE_SIZE, save_source, (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; + memcpy(save_source, partial_where, (int) AFTER_SIZE); + memcpy(partial_where, AFTER_STRING, (int) AFTER_SIZE); + } else { + partial_where = 0; + if (partial_size > 0) { + as_warn("Partial line at end of file ignored"); + } + /* If we should pop to another file at EOF, do it. */ + if (next_saved_file) { + *bufp = input_scrub_pop (next_saved_file); /* Pop state */ + /* partial_where is now correct to return, since we popped it. */ + } + } + return(partial_where); +} /* input_scrub_next_buffer() */ + +/* + * The remaining part of this file deals with line numbers, error + * messages and so on. + */ + + +int + seen_at_least_1_file () /* TRUE if we opened any file. */ +{ + return (physical_input_file != NULL); +} + +void + bump_line_counters () +{ + ++ physical_input_line; + /* ++ logical_input_line; FIXME-now remove this. */ +} + +/* + * new_logical_line() + * + * Tells us what the new logical line number and file are. + * If the line_number is <0, we don't change the current logical line number. + * If the fname is NULL, we don't change the current logical file name. + */ +void new_logical_line(fname, line_number) +char *fname; /* DON'T destroy it! We point to it! */ +int line_number; +{ + if (fname) { + logical_input_file = fname; + } /* if we have a file name */ + + if (line_number >= 0) { + logical_input_line = line_number; + } /* if we have a line number */ +} /* new_logical_line() */ + +/* + * 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; + extern char *myname; + + if (logical_input_file && (logical_input_line > 0)) { + p = logical_input_file; + line = logical_input_line; + } else { + p = physical_input_file; + line = physical_input_line; + } /* line number should match file name */ + + fprintf(stderr, "%s: %s:%u: ", myname, p, line); + + return; +} /* as_where() */ + + + + +/* + * a s _ h o w m u c h () + * + * Output to given stream how much of line we have scanned so far. + * Assumes we have scanned up to and including input_line_pointer. + * No free '\n' at end of line. + */ +void + as_howmuch (stream) +FILE * stream; /* Opened for write please. */ +{ + register char * p; /* Scan input line. */ + /* register char c; JF unused */ + + for (p = input_line_pointer - 1; * p != '\n'; --p) + { + } + ++ p; /* p->1st char of line. */ + for (; p <= input_line_pointer; p++) + { + /* Assume ASCII. EBCDIC & other micro-computer char sets ignored. */ + /* c = *p & 0xFF; JF unused */ + as_1_char(*p, stream); + } +} + +static void as_1_char (c,stream) +unsigned int c; +FILE *stream; +{ + if (c > 127) + { + (void)putc('%', stream); + c -= 128; + } + if (c < 32) + { + (void)putc('^', stream); + c += '@'; + } + (void)putc(c, stream); +} + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of input_scrub.c */ diff --git a/gnu/usr.bin/as/link.cmd b/gnu/usr.bin/as/link.cmd new file mode 100644 index 000000000000..a035ca87daa9 --- /dev/null +++ b/gnu/usr.bin/as/link.cmd @@ -0,0 +1,10 @@ +ALIGN=1024 +RESNUM 0x0000, 0x8000 +; Putting in .lit1 gives errors. +ORDER .data=0x80002000, .data1, .lit, .bss +; Let's put this on the command line so it goes first, which is what +; GDB expects. +; LOAD /s2/amd/29k/lib/crt0.o +LOAD /s2/amd/29k/lib/libqcb0h.lib +LOAD /s2/amd/29k/lib/libscb0h.lib +LOAD /s2/amd/29k/lib/libacb0h.lib diff --git a/gnu/usr.bin/as/listing.c b/gnu/usr.bin/as/listing.c new file mode 100644 index 000000000000..650b4a09ab64 --- /dev/null +++ b/gnu/usr.bin/as/listing.c @@ -0,0 +1,849 @@ +/* listing.c - mainting assembly listings + Copyright (C) 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + Contributed by Steve Chamberlain + sac@cygnus.com + + + A listing page looks like: + + LISTING_HEADER sourcefilename pagenumber + TITLE LINE + SUBTITLE LINE + linenumber address data source + linenumber address data source + linenumber address data source + linenumber address data source + + If not overridden, the listing commands are: + + .title "stuff" + Put "stuff" onto the title line + .sbttl "stuff" + Put stuff onto the subtitle line + + If these commands come within 10 lines of the top of the page, they + will affect the page they are on, as well as any subsequent page + + .eject + Thow a page + .list + Increment the enable listing counter + .nolist + Decrement the enable listing counter + + .psize Y[,X] + Set the paper size to X wide and Y high. Setting a psize Y of + zero will suppress form feeds except where demanded by .eject + + If the counter goes below zero, listing is suppressed. + + + Listings are a maintained by read calling various listing_<foo> + functions. What happens most is that the macro NO_LISTING is not + defined (from the Makefile), then the macro LISTING_NEWLINE expands + into a call to listing_newline. The call is done from read.c, every + time it sees a newline, and -l is on the command line. + + The function listing_newline remembers the frag associated with the + newline, and creates a new frag - note that this is wasteful, but not + a big deal, since listing slows things down a lot anyway. The + function also rememebers when the filename changes. + + When all the input has finished, and gas has had a chance to settle + down, the listing is output. This is done by running down the list of + frag/source file records, and opening the files as needed and printing + out the bytes and chars associated with them. + + The only things which the architecture can change about the listing + are defined in these macros: + + LISTING_HEADER The name of the architecture + LISTING_WORD_SIZE The make of the number of bytes in a word, this determines + the clumping of the output data. eg a value of + 2 makes words look like 1234 5678, whilst 1 + would make the same value look like 12 34 56 + 78 + LISTING_LHS_WIDTH Number of words of above size for the lhs + + LISTING_LHS_WIDTH_SECOND Number of words for the data on the lhs + for the second line + + LISTING_LHS_CONT_LINES Max number of lines to use up for a continutation + LISTING_RHS_WIDTH Number of chars from the input file to print + on a line + */ + +#ifndef lint +static char rcsid[] = "$Id: listing.c,v 1.1 1993/11/03 00:51:54 paul Exp $"; +#endif + +#include "as.h" + +#ifndef NO_LISTING + +#include <obstack.h> +#include "input-file.h" +#include "targ-cpu.h" + +#ifndef LISTING_HEADER +#define LISTING_HEADER "GAS LISTING" +#endif +#ifndef LISTING_WORD_SIZE +#define LISTING_WORD_SIZE 4 +#endif +#ifndef LISTING_LHS_WIDTH +#define LISTING_LHS_WIDTH 1 +#endif +#ifndef LISTING_LHS_WIDTH_SECOND +#define LISTING_LHS_WIDTH_SECOND 1 +#endif +#ifndef LISTING_RHS_WIDTH +#define LISTING_RHS_WIDTH 100 +#endif +#ifndef LISTING_LHS_CONT_LINES +#define LISTING_LHS_CONT_LINES 4 +#endif + + +/* This structure remembers which .s were used */ +typedef struct file_info_struct { + char *filename; + int linenum; + FILE *file; + struct file_info_struct *next; + int end_pending; +} file_info_type ; + + +/* this structure rememebrs which line from which file goes into which frag */ +typedef struct list_info_struct { + /* Frag which this line of source is nearest to */ + fragS *frag; + /* The actual line in the source file */ + unsigned int line; + /* Pointer to the file info struct for the file which this line + belongs to */ + file_info_type *file; + + /* Next in list */ + struct list_info_struct *next; + + + /* Pointer to the file info struct for the high level language + source line that belongs here */ + file_info_type *hll_file; + + /* High level language source line */ + int hll_line; + + + /* Pointer to any error message associated with this line */ + char *message; + + enum { + EDICT_NONE, + EDICT_SBTTL, + EDICT_TITLE, + EDICT_NOLIST, + EDICT_LIST, + EDICT_EJECT, + } edict; + char *edict_arg; +} list_info_type; + +static struct list_info_struct *head; +struct list_info_struct *listing_tail; +extern int listing; +extern unsigned int physical_input_line; +extern fragS *frag_now; + +static int paper_width = 200; +static int paper_height = 60; + +/* this static array is used to keep the text of data to be printed + before the start of the line. It is stored so we can give a bit + more info on the next line. To much, and large initialized arrays + will use up lots of paper. */ + +static char data_buffer[100]; +static unsigned int data_buffer_size; + +static void + listing_message(name, message) +char *name; +char *message; +{ + unsigned int l = strlen(name) + strlen(message) + 1; + char *n = malloc(l); + strcpy(n,name); + strcat(n,message); + if (listing_tail != (list_info_type *)NULL) { + listing_tail->message = n; + } + + return; +} /* lising_message() */ + +void + listing_warning(message) +char *message; +{ + listing_message("Warning:", message); +} + +void + listing_error(message) +char *message; +{ + listing_message("Error:", message); +} + +static file_info_type *file_info_head; + +static file_info_type * + file_info(file_name) +char *file_name; +{ + /* Find an entry with this file name */ + file_info_type *p = file_info_head; + + while (p != (file_info_type *)NULL) { + if (strcmp(p->filename, file_name) == 0) + return(p); + p = p->next; + } + + /* Make new entry */ + + p = (file_info_type *) xmalloc(sizeof(file_info_type)); + p->next = file_info_head; + file_info_head = p; + p->filename = xmalloc(strlen(file_name)+1); + strcpy(p->filename, file_name); + p->linenum = 0; + p->end_pending = 0; + + p->file = fopen(p->filename,"r"); + return(p); +} /* file_info() */ + + +static void + new_frag() +{ + frag_wane(frag_now); + frag_new(0); +} + +void + listing_newline(ps) +char *ps; +{ + char *s = ps; + extern char *file_name; + static unsigned int last_line = 0xffff ; + + + list_info_type *new; + if (physical_input_line != last_line) { + last_line = physical_input_line; + new_frag(); + + new = (list_info_type *) malloc(sizeof(list_info_type)); + new->frag = frag_now; + new->line = physical_input_line ; + new->file = file_info(file_name); + + if (listing_tail) { + listing_tail->next = new; + } else { + head = new; + } + + listing_tail = new; + new->next = (list_info_type *) NULL; + new->message = (char *) NULL; + new->edict = EDICT_NONE; + new->hll_file = (file_info_type*) NULL; + new->hll_line = 0; + new_frag(); + } + + return; +} /* listing_newline() */ + + +/* This function returns the next source line from the file supplied, + truncated to size. It appends a fake line to the end of each input + file to make. */ + +static char * + buffer_line(file, line, size) +file_info_type *file; +char *line; +unsigned int size; +{ + unsigned int count = 0; + int c; + + char *p = line; + + /* If we couldn't open the file, return an empty line */ + if (file->file == (FILE*) NULL) { + return(""); + } + + if (file->end_pending == 10) { + *p ++ = '\n'; + rewind(file->file); + file->linenum = 0; + file->end_pending = 0; + } + + c = fgetc(file->file); + size -= 1; /* leave room for null */ + + while (c != EOF && c != '\n') { + if (count < size) + *p++ = c; + count++; + + c = fgetc(file->file); + } + + if (c == EOF) { + file->end_pending ++; + *p++ = 'E'; + *p++ = 'O'; + *p++ = 'F'; + } + + file->linenum++; + *p++ = 0; + return(line); +} /* buffer_line() */ + +static char *fn; + +static unsigned int eject; /* Eject pending */ +static unsigned int page; /* Current page number */ +static char *title; /* current title */ +static char *subtitle; /* current subtitle */ +static unsigned int on_page; /* number of lines printed on current page */ + +static void + listing_page(list) +list_info_type *list; +{ + /* Grope around, see if we can see a title or subtitle edict + coming up soon (we look down 10 lines of the page and see + if it's there). */ + + if ((eject || (on_page >= paper_height)) && paper_height != 0) { + unsigned int c = 10; + int had_title = 0; + int had_subtitle = 0; + + page++; + + while (c != 0 && list) { + if (list->edict == EDICT_SBTTL && !had_subtitle) { + had_subtitle = 1; + subtitle = list->edict_arg; + } + + if (list->edict == EDICT_TITLE && !had_title) { + had_title = 1; + title = list->edict_arg; + } + list = list->next; + --c; + } + + if (page > 1) { + printf("\f"); + } + + printf("%s %s \t\t\tpage %d\n", LISTING_HEADER, fn, page); + printf("%s\n", title); + printf("%s\n", subtitle); + on_page = 3; + eject = 0; + } + + return; +} /* listing_page() */ + + +static unsigned int + calc_hex(list) +list_info_type *list; +{ + list_info_type *first = list; + list_info_type *last = first; + unsigned int address = ~0; + + fragS *frag; + fragS *frag_ptr; + + unsigned int byte_in_frag = 0; + + int anything = 0; + + /* Find first frag which says it belongs to this line */ + frag = list->frag; + while (frag && frag->line != list) + frag = frag->fr_next; + + frag_ptr = frag; + + data_buffer_size = 0; + + /* Dump all the frags which belong to this line */ + while (frag_ptr != (fragS *)NULL && frag_ptr->line == first) { + /* Print as many bytes from the fixed part as is sensible */ + while (byte_in_frag < frag_ptr->fr_fix && data_buffer_size < sizeof(data_buffer)-10) { + if (address == ~0) { + address = frag_ptr->fr_address; + } + + sprintf(data_buffer + data_buffer_size, "%02X", (frag_ptr->fr_literal[byte_in_frag]) & 0xff); + data_buffer_size += 2; + byte_in_frag++; + } + + /* Print as many bytes from the variable part as is sensible */ + while (byte_in_frag < frag_ptr->fr_var * frag_ptr->fr_offset + && data_buffer_size < sizeof(data_buffer)-10) { + if (address == ~0) { + address = frag_ptr->fr_address; + } + data_buffer[data_buffer_size++] = '*'; + data_buffer[data_buffer_size++] = '*'; + + byte_in_frag++; + } + + frag_ptr = frag_ptr->fr_next; + } + + data_buffer[data_buffer_size++] = 0; + return address; +} /* calc_hex() */ + +static void + print_lines(list, string, address) +list_info_type *list; +char *string; +unsigned int address; +{ + unsigned int idx; + unsigned int nchars; + unsigned int lines; + unsigned int byte_in_word =0; + char *src = data_buffer; + + /* Print the stuff on the first line */ + listing_page(list); + nchars = (LISTING_WORD_SIZE * 2 + 1) * LISTING_LHS_WIDTH ; + + /* Print the hex for the first line */ + if (address == ~0) { + printf("% 4d ", list->line); + for (idx = 0; idx < nchars; idx++) + printf(" "); + + printf("\t%s\n", string ? string : ""); + on_page++; + listing_page(0); + } else { + if (had_errors()) { + printf("% 4d ???? ", list->line); + } else { + printf("% 4d %04x ", list->line, address); + } + + /* And the data to go along with it */ + idx = 0; + + while (*src && idx < nchars) { + printf("%c%c", src[0], src[1]); + src += 2; + byte_in_word++; + + if (byte_in_word == LISTING_WORD_SIZE) { + printf(" "); + idx++; + byte_in_word = 0; + } + idx+=2; + } + + for (;idx < nchars; idx++) + printf(" "); + + printf("\t%s\n", string ? string : ""); + on_page++; + listing_page(list); + if (list->message) { + printf("**** %s\n",list->message); + listing_page(list); + on_page++; + } + + for (lines = 0; lines < LISTING_LHS_CONT_LINES && *src; lines++) { + nchars = ((LISTING_WORD_SIZE*2) +1) * LISTING_LHS_WIDTH_SECOND -1; + idx = 0; + /* Print any more lines of data, but more compactly */ + printf("% 4d ", list->line); + + while (*src && idx < nchars) { + printf("%c%c", src[0], src[1]); + src+=2; + idx+=2; + byte_in_word++; + if (byte_in_word == LISTING_WORD_SIZE) { + printf(" "); + idx++; + byte_in_word = 0; + } + } + + printf("\n"); + on_page++; + listing_page(list); + } + } +} /* print_lines() */ + + +static void + list_symbol_table() +{ + extern symbolS *symbol_rootP; + symbolS *ptr; + + eject = 1; + listing_page(0); + printf("DEFINED SYMBOLS\n"); + on_page++; + + for (ptr = symbol_rootP; ptr != (symbolS*)NULL; ptr = symbol_next(ptr)) { + if (ptr->sy_frag->line) { + if (strlen(S_GET_NAME(ptr))) { + printf("%20s:%-5d %2d:%08x %s \n", + ptr->sy_frag->line->file->filename, + ptr->sy_frag->line->line, + S_GET_SEGMENT(ptr), + S_GET_VALUE(ptr), + S_GET_NAME(ptr)); + + on_page++; + listing_page(0); + } + } + + } + + printf("\n"); + on_page++; + listing_page(0); + printf("UNDEFINED SYMBOLS\n"); + on_page++; + listing_page(0); + + for (ptr = symbol_rootP; ptr != (symbolS*)NULL; ptr = symbol_next(ptr)) { + if (ptr && strlen(S_GET_NAME(ptr)) != 0) { + if (ptr->sy_frag->line == 0) { + printf("%s\n", S_GET_NAME(ptr)); + on_page++; + listing_page(0); + } + } + } + + return; +} /* list_symbol_table() */ + +void + print_source(current_file, list, buffer, width) +file_info_type *current_file; +list_info_type *list; +char *buffer; +unsigned int width; +{ + if (current_file->file) { + while (current_file->linenum < list->hll_line) { + char * p = buffer_line(current_file, buffer, width); + printf("%4d:%-13s **** %s\n", current_file->linenum, current_file->filename, p); + on_page++; + listing_page(list); + } + } + + return; +} /* print_source() */ + +/* Sometimes the user doesn't want to be bothered by the debugging + records inserted by the compiler, see if the line is suspicioous */ + +static int + debugging_pseudo(line) +char *line; +{ + while (isspace(*line)) + line++; + + if (*line != '.') return 0; + + line++; + + if (strncmp(line, "def",3) == 0) return 1; + if (strncmp(line, "val",3) == 0) return 1; + if (strncmp(line, "scl",3) == 0) return 1; + if (strncmp(line, "line",4) == 0) return 1; + if (strncmp(line, "endef",5) == 0) return 1; + if (strncmp(line, "ln",2) == 0) return 1; + if (strncmp(line, "type",4) == 0) return 1; + if (strncmp(line, "size",4) == 0) return 1; + if (strncmp(line, "dim",3) == 0) return 1; + if (strncmp(line, "tag",3) == 0) return 1; + + return(0); +} /* debugging_pseudo() */ + +void + listing_listing(name) +char *name; +{ + char *buffer; + char *message; + char *p; + file_info_type *current_hll_file = (file_info_type *) NULL; + int on_page = 0; + int show_listing = 1; + list_info_type *list = head; + unsigned int addr = 0; + unsigned int page = 1; + unsigned int prev = 0; + unsigned int width; + + buffer = malloc(LISTING_RHS_WIDTH); + eject = 1; + list = head; + + while (list != (list_info_type *)NULL && 0) { + if (list->next) + list->frag = list->next->frag; + list = list->next; + } + + list = head->next; + + while (list) { + width = LISTING_RHS_WIDTH > paper_width ? paper_width : LISTING_RHS_WIDTH; + + switch (list->edict) { + case EDICT_LIST: + show_listing++; + break; + case EDICT_NOLIST: + show_listing--; + break; + case EDICT_EJECT: + break; + case EDICT_NONE: + break; + case EDICT_TITLE: + title = list->edict_arg; + break; + case EDICT_SBTTL: + subtitle = list->edict_arg; + break; + default: + abort(); + } + + if (show_listing > 0) { + /* Scan down the list and print all the stuff which can be done + with this line (or lines) */ + message = 0; + + if (list->hll_file) { + current_hll_file = list->hll_file; + } + + if (current_hll_file && list->hll_line && listing & LISTING_HLL) { + print_source(current_hll_file, list, buffer, width); + } + + p = buffer_line(list->file, buffer, width); + + if (! ((listing & LISTING_NODEBUG) && debugging_pseudo(p))) { + print_lines(list, p, calc_hex(list)); + } + + if (list->edict == EDICT_EJECT) { + eject = 1; + } + } else { + + p = buffer_line(list->file, buffer, width); + } + + list = list->next; + } + free(buffer); +} /* listing_listing() */ + +void + listing_print(name) +char *name; +{ + title = ""; + subtitle = ""; + + if (listing & LISTING_NOFORM) + { + paper_height = 0; + } + + if (listing & LISTING_LISTING) + { + listing_listing(name); + + } + if (listing & LISTING_SYMBOLS) + { + list_symbol_table(); + } +} /* listing_print() */ + + +void + listing_file(name) +char *name; +{ + fn = name; +} + +void + listing_eject() +{ + listing_tail->edict = EDICT_EJECT; + return; +} + +void + listing_flags() +{ + +} + +void + listing_list(on) +unsigned int on; +{ + listing_tail->edict = on ? EDICT_LIST : EDICT_NOLIST; +} + + +void + listing_psize() +{ + paper_height = get_absolute_expression(); + + if (paper_height < 0 || paper_height > 1000) { + paper_height = 0; + as_warn("strantge paper height, set to no form"); + } + + if (*input_line_pointer == ',') { + input_line_pointer++; + paper_width = get_absolute_expression(); + } + + return; +} /* listing_psize() */ + + +void + listing_title(depth) +unsigned int depth; +{ + char *start; + char *title; + unsigned int length; + + SKIP_WHITESPACE(); + + if (*input_line_pointer == '\"') { + input_line_pointer++; + start = input_line_pointer; + + while (*input_line_pointer) { + if (*input_line_pointer == '\"') { + length = input_line_pointer - start; + title = malloc(length + 1); + memcpy(title, start, length); + title[length] = 0; + listing_tail->edict = depth ? EDICT_SBTTL : EDICT_TITLE; + listing_tail->edict_arg = title; + input_line_pointer++; + demand_empty_rest_of_line(); + return; + } else if (*input_line_pointer == '\n') { + as_bad("New line in title"); + demand_empty_rest_of_line(); + return; + } else { + input_line_pointer++; + } + } + } else { + as_bad("expecting title in quotes"); + } + + return; +} /* listing_title() */ + + + +void + listing_source_line(line) +unsigned int line; +{ + new_frag(); + listing_tail->hll_line = line; + new_frag(); + return; +} /* lising_source_line() */ + +void + listing_source_file(file) +char *file; +{ + listing_tail->hll_file = file_info(file); +} + +#endif /* not NO_LISTING */ + +/* end of listing.c */ diff --git a/gnu/usr.bin/as/listing.h b/gnu/usr.bin/as/listing.h new file mode 100644 index 000000000000..ae8054ed19af --- /dev/null +++ b/gnu/usr.bin/as/listing.h @@ -0,0 +1,95 @@ +/* This file is listing.h + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: listing.h,v 1.1 1993/11/03 00:51:56 paul Exp $ + */ + + + +#ifndef __listing_h__ +#define __listing_h__ + +#define LISTING_LISTING 1 +#define LISTING_SYMBOLS 2 +#define LISTING_NOFORM 4 +#define LISTING_HLL 8 +#define LISTING_NODEBUG 16 + +#define LISTING_DEFAULT (LISTING_LISTING | LISTING_HLL | LISTING_SYMBOLS) + +#ifndef NO_LISTING + +#define LISTING_NEWLINE() { if (listing) listing_newline(input_line_pointer); } + + +#if __STDC__ == 1 + +void listing_eject(void); +void listing_error(char *message); +void listing_file(char *name); +void listing_flags(void); +void listing_list(unsigned int on); +void listing_newline(char *ps); +void listing_print(char *name); +void listing_psize(void); +void listing_source_file(char *); +void listing_source_line(unsigned int); +void listing_title(unsigned int depth); +void listing_warning(char *message); +void listing_width(unsigned int x); + +#else /* not __STDC__ */ + +void listing_eject(); +void listing_error(); +void listing_file(); +void listing_flags(); +void listing_list(); +void listing_newline(); +void listing_print(); +void listing_psize(); +void listing_source_file(); +void listing_source_line(); +void listing_title(); +void listing_warning(); +void listing_width(); + +#endif /* not __STDC__ */ + +#else /* NO_LISTING */ + +#define LISTING_NEWLINE() {;} + +/* Dummy functions for when compiled without listing enabled */ + +#define listing_flags() {;} +#define listing_list() {;} +#define listing_eject() {;} +#define listing_psize() {;} +#define listing_title(depth) {;} +#define listing_file(name) {;} +#define listing_newline(name) {;} +#define listing_source_line(n) {;} +#define listing_source_file(n) {;} + +#endif /* NO_LISTING */ + +#endif /* __listing_h__ */ + +/* end of listing.h */ diff --git a/gnu/usr.bin/as/make-gas.com b/gnu/usr.bin/as/make-gas.com new file mode 100644 index 000000000000..cb3064d88373 --- /dev/null +++ b/gnu/usr.bin/as/make-gas.com @@ -0,0 +1,86 @@ +$! 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. +$! +$! Caution: Versions 1.38.1 and earlier had a bug in the handling of +$! some static constants. If you are using such a version of the +$! assembler, and you wish to compile without the "const=" hack, +$! you should first build this version *with* the "const=" +$! definition, and then use that assembler to rebuild it without the +$! "const=" definition. Failure to do this will result in an assembler +$! that will mung floating point constants. +$! +$! Note: The version of gas shipped on the GCC VMS tapes has been patched +$! to fix the above mentioned bug. +$! +$ write sys$output "If this assembler is going to be used with GCC 1.n, you" +$ write sys$Output "need to modify the driver to supply the -1 switch to gas." +$ write sys$output "This is required because of a small change in how global" +$ write sys$Output "constant variables are handled. Failure to include this" +$ write sys$output "will result in linker warning messages about mismatched +$ write sys$output "psect attributes." +$! +$ C_DEFS :="""VMS""" +$! C_DEFS :="""VMS""","""const=""" +$ C_INCLUDES :=/include=([],[.config],[-.include]) +$ C_FLAGS := /debug 'c_includes' +$! +$! +$ if "''p1'" .eqs. "LINK" then goto Link +$! +$! This helps gcc 1.nn find the aout/* files. +$! +$ aout_dev = f$parse(flnm,,,"DEVICE") +$ tmp = aout_dev - ":" +$if f$trnlnm(tmp).nes."" then aout_dev = f$trnlnm(tmp) +$ aout_dir = aout_dev+f$parse(flnm,,,"DIRECTORY")' - + - "GAS]" + "INCLUDE.AOUT.]" - "][" +$assign 'aout_dir' aout/tran=conc +$ opcode_dir = aout_dev+f$parse(flnm,,,"DIRECTORY")' - + - "GAS]" + "INCLUDE.OPCODE.]" - "][" +$assign 'opcode_dir' opcode/tran=conc +$! +$ gcc 'c_flags'/define=('C_DEFS') as.c +$ gcc 'c_flags'/define=("error=as_fatal",'C_DEFS') xrealloc.c +$ gcc 'c_flags'/define=("error=as_fatal",'C_DEFS') xmalloc.c +$ gcc 'c_flags'/define=("error=as_fatal",'C_DEFS') hash.c +$ gcc 'c_flags'/define=('C_DEFS') obstack.c +$ gcc 'c_flags'/define=('C_DEFS') hex-value.c +$ gcc 'c_flags'/define=('C_DEFS') messages.c +$ gcc 'c_flags'/define=('C_DEFS') atof-generic.c +$ gcc 'c_flags'/define=('C_DEFS') expr.c +$ gcc 'c_flags'/define=('C_DEFS') cond.c +$ gcc 'c_flags'/define=('C_DEFS') app.c +$ gcc 'c_flags'/define=('C_DEFS') frags.c +$ gcc 'c_flags'/define=('C_DEFS') input-file.c +$ gcc 'c_flags'/define=('C_DEFS') input-scrub.c +$ gcc 'c_flags'/define=('C_DEFS') output-file.c +$ gcc 'c_flags'/define=('C_DEFS') read.c +$ gcc 'c_flags'/define=('C_DEFS') subsegs.c +$ gcc 'c_flags'/define=('C_DEFS') symbols.c +$ gcc 'c_flags'/define=('C_DEFS') write.c +$ gcc 'c_flags'/define=('C_DEFS') version.c +$ gcc 'c_flags'/define=('C_DEFS') flonum-const.c +$ gcc 'c_flags'/define=('C_DEFS') flonum-copy.c +$ gcc 'c_flags'/define=('C_DEFS') flonum-mult.c +$ gcc 'c_flags'/define=('C_DEFS') strstr.c +$ gcc 'c_flags'/define=('C_DEFS') bignum-copy.c +$ gcc 'c_flags'/define=('C_DEFS') listing.c +$ gcc 'c_flags'/define=('C_DEFS') atof-targ.c +$ gcc 'c_flags'/define=("error=as_fatal",'C_DEFS') targ-cpu.c +$ gcc 'c_flags'/define=("error=as_fatal",'C_DEFS') obj-format.c +$ Link: +$ link/nomap/exec=gcc-as version.opt/opt+sys$input:/opt +! +! Linker options file for GNU assembler +! +as,xrealloc,xmalloc,hash,hex-value,atof-generic,messages,expr,app,cond,- +frags,input-file,input-scrub,output-file,read,subsegs,symbols,write,- +version,flonum-const,flonum-copy,flonum-mult,strstr,bignum-copy,listing,- +obstack,targ-cpu,atof-targ,obj-format,- +gnu_cc:[000000]gcclib/lib,sys$share:vaxcrtl/lib diff --git a/gnu/usr.bin/as/makefile.dos b/gnu/usr.bin/as/makefile.dos new file mode 100644 index 000000000000..b9f7197c5fd6 --- /dev/null +++ b/gnu/usr.bin/as/makefile.dos @@ -0,0 +1,593 @@ +# Makefile for GNU Assembler +# Copyright (C) 1987, 1988, 1990, 1991 Free Software Foundation, Inc. + +#This file is part of GNU GAS. + +#GNU GAS is free software; you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation; either version 1, or (at your option) +#any later version. + +#GNU GAS is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with GNU GAS; see the file COPYING. If not, write to +#the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# $Id: makefile.dos,v 1.1 1993/11/03 00:51:59 paul Exp $ + +# The targets for external use include: +# all, doc, proto, install, uninstall, includes, TAGS, +# clean, cleanconfig, realclean, stage1, stage2, stage3, stage4. + +# Variables that exist for you to override. +# See below for how to change them for certain systems. + +LIBDEPS= +CROSS= +HDEFINES= +CPPFLAGS= + +ALLOCA = +CFLAGS = -g -D__MSDOS__ -D__GO32__ -I../include +INTERNAL_CFLAGS = $(CROSS) +OLDCC = cc +BISON = bison +BISONFLAGS = -v +AR = ar +OLDAR_FLAGS = qc +AR_FLAGS = rc +SHELL = /bin/sh +# on sysV, define this as cp. +INSTALL = install -c +# These permit overriding just for certain files. +INSTALL_PROGRAM = $(INSTALL) +INSTALL_FILE = $(INSTALL) + +# Define this as & to perform parallel make on a Sequent. +# Note that this has some bugs, and it seems currently necessary +# to compile all the gen* files first by hand to avoid erroneous results. +P = + +# How to invoke ranlib. +RANLIB = ranlib +# Test to use to see whether ranlib exists on the system. +RANLIB_TEST = [ -f /usr/bin/ranlib -o -f /bin/ranlib ] + +# CFLAGS for use with OLDCC, for compiling gnulib. +# NOTE: -O does not work on some Unix systems! +CCLIBFLAGS = -O + +# Version of ar to use when compiling gnulib. +OLDAR = ar + +version=`$(unsubdir)/../gcc$(subdir)/gcc -dumpversion` + +# Directory where sources are, from where we are. +srcdir = . +# Common prefix for installation directories. +# NOTE: This directory must exist when you start installation. +ddestdir = /usr/local +# Directory in which to put the executable for the command `gcc' +bindir = $(ddestdir)/bin +# Directory in which to put the directories used by the compiler. +libdir = $(ddestdir)/lib +# Directory in which the compiler finds executables, libraries, etc. +libsubdir = $(libdir)/gcc/$(target_alias)/$(version) +# Number to put in man-page filename. +manext = 1 +# Directory in which to put man pages. +mandir = $(destdir)/H-independent/man/man$(manext) + +# Additional system libraries to link with. +CLIB= + +# Specify the rule for actually making gnulib. +GNULIB = gnulib.portable + +# Specify the rule for actually making gnulib2. +GNULIB2 = gnulib2.portable + +# List of extra C and assembler files to add to gnulib. +# Assembler files should have names ending in `.asm'. +LIBFUNCS_EXTRA = + +# Program to convert libraries. +LIBCONVERT = + +# Control whether header files are installed. +INSTALL_HEADERS=install-headers + +# Change this to empty to prevent installing limits.h +LIMITS_H = limits.h + +# Directory to link to, when using the target `maketest'. +DIR = ../gcc + +# For better debugging under COFF, define SEPARATE_AUX_OUTPUT in config.h +# and define the following variable as `aux-output2.c' in make-... +AUX_OUTPUT2 = + +# Flags to use when cross-building GCC. +# Prefix to apply to names of object files when using them +# to run on the machine we are compiling on. +HOST_PREFIX= +# Prefix to apply to names of object files when compiling them +# to run on the machine we are compiling on. +# The default for this variable is chosen to keep these rules +# out of the way of the other rules for compiling the same source files. +HOST_PREFIX_1=loser- +HOST_CC=$(CC) +HOST_CFLAGS=$(ALL_CFLAGS) +HOST_LDFLAGS=$(LDFLAGS) +HOST_CPPFLAGS=$(CPPFLAGS) + +# Choose the real default target. +ALL=as.new + +# End of variables for you to override. + +# Lists of files for various purposes. + +REAL_SOURCES = \ + app.c \ + as.c \ + atof-generic.c \ + bignum-copy.c \ + cond.c \ + expr.c \ + fn-const.c \ + fn-copy.c \ + flonum-mult.c \ + frags.c \ + hash.c \ + hex-value.c \ + input-file.c \ + input-scrub.c \ + messages.c \ + output-file.c \ + read.c \ + strstr.c \ + subsegs.c \ + symbols.c \ + version.c \ + write.c \ + xmalloc.c \ + xrealloc.c + +# in an expedient order +LINKED_SOURCES = \ + targ-cpu.c \ + obj-format.c \ + atof-targ.c + +SOURCES = $(LINKED_SOURCES) $(REAL_SOURCES) + +REAL_HEADERS = \ + as.h \ + bignum.h \ + expr.h \ + flonum.h \ + frags.h \ + hash.h \ + input-file.h \ + tc.h \ + obj.h \ + read.h \ + struc-symbol.h \ + subsegs.h \ + symbols.h \ + syscalls.h \ + write.h + +LINKED_HEADERS = \ + a.out.gnu.h \ + a.out.h \ + host.h \ + targ-env.h \ + targ-cpu.h \ + obj-format.h \ + atof-targ.h + +HEADERS = $(LINKED_HEADERS) $(REAL_HEADERS) + +OBJS = \ + targ-cpu.o \ + obj-format.o \ + atof-targ.o \ + app.o \ + as.o \ + atof-generic.o \ + bignum-copy.o \ + cond.o \ + expr.o \ + fn-const.o \ + fn-copy.o \ + flonum-mult.o \ + frags.o \ + hash.o \ + hex-value.o \ + input-file.o \ + input-scrub.o \ + messages.o \ + output-file.o \ + read.o \ + strstr.o \ + subsegs.o \ + symbols.o \ + version.o \ + write.o \ + xmalloc.o \ + xrealloc.o + +#### host, target, and site specific Makefile frags come in here. +TARG_CPU_DEPENDENTS=../include/h8300-opcode.h +LOCAL_LOADLIBES=../bfd/libbfd.a +TDEFINES=-DBFD -DBFD_HEADERS -DMANY_SEGMENTS + + +# Definition of `all' is here so that new rules inserted by sed +# do not specify the default target. +# The real definition is under `all.internal'. + +all: $(ALL) +all-info: +install-info: + +fake-as: force + - rm -f ./as.new + cp /bin/as ./fake-as + +# Now figure out from those variables how to compile and link. + +# This is the variable actually used when we compile. +ALL_CFLAGS = $(INTERNAL_CFLAGS) $(CFLAGS) $(HDEFINES) $(TDEFINES) + +# Even if ALLOCA is set, don't use it if compiling with GCC. +USE_ALLOCA= `if [ x"${CC}" = x"${OLDCC}" ] ; then echo ${ALLOCA}; else true; fi` +USE_HOST_ALLOCA= `if [ x"${CC}" = x"${OLDCC}" ] ; then echo ${HOST_PREFIX}${ALLOCA}; else true; fi` + +# Likewise, for use in the tools that must run on this machine +# even if we are cross-building GCC. +# We don't use USE_ALLOCA because backquote expansion doesn't work in deps. +HOST_LIBDEPS= $(HOST_PREFIX)$(OBSTACK) $(HOST_PREFIX)$(ALLOCA) $(HOST_PREFIX)$(MALLOC) + +# How to link with both our special library facilities +# and the system's installed libraries. + +LIBS = $(LOCAL_LOADLIBES) $(CLIB) $(unsubdir)/../libiberty$(subdir)/libiberty.a + +# Likewise, for use in the tools that must run on this machine +# even if we are cross-building GCC. +HOST_LIBS = $(HOST_PREFIX)$(OBSTACK) $(USE_HOST_ALLOCA) $(HOST_PREFIX)$(MALLOC) $(CLIB) + +# Specify the directories to be searched for header files. +# Both . and srcdir are used, in that order, +# so that tm.h and config.h will be found in the compilation +# subdirectory rather than in the source directory. +INCLUDES = -I. -I$(srcdir) -Iconfig +SUBDIR_INCLUDES = -I.. -I../$(srcdir) -I../config + +# Always use -Iconfig when compiling. +.c.o: + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $< + +# This tells GNU make version 3 not to export all the variables +# defined in this file into the environment. +.NOEXPORT: + +# Files to be copied away after each stage in building. +STAGE_GCC=gcc +STAGESTUFF = *.o as.new + +# The files that "belong" in CONFIG_H are deliberately omitted +# because having them there would not be useful in actual practice. +# All they would do is cause complete recompilation every time +# one of the machine description files is edited. +# That may or may not be what one wants to do. +# If it is, rm *.o is an easy way to do it. +# CONFIG_H = config.h tm.h +CONFIG_H = + +as.new: $(OBJS) $(LIBDEPS) + -mv -f as.new as.old + >as.rf $(ALL_CFLAGS) $(LDFLAGS) -o as.new $(OBJS) $(LIBS) $(LOADLIBES) + $(CC) @as.rf + +objdump: + +all.internal: native +# This is what is made with the host's compiler if making a cross assembler. +native: config.status as + +config.status: + @echo You must configure gas. Look at the INSTALL file for details. + @false + +compilations: ${OBJS} + +# Compiling object files from source files. + +app.o : app.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h +as.o : as.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h +atof-generic.o : atof-generic.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h +bignum-copy.o : bignum-copy.c as.h host.h \ + targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h +cond.o : cond.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + +debug.o : debug.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + subsegs.h +expr.o : expr.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + +fn-const.o : fn-const.c flonum.h bignum.h +fn-copy.o : fn-copy.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h +flonum-mult.o : flonum-mult.c flonum.h bignum.h +frags.o : frags.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + subsegs.h +hash.o : hash.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h +hex-value.o : hex-value.c +input-file.o : input-file.c as.h host.h \ + targ-env.h obj-format.h targ-cpu.h \ + struc-symbol.h write.h flonum.h bignum.h expr.h \ + frags.h hash.h read.h symbols.h tc.h obj.h input-file.h +input-scrub.o : input-scrub.c \ + as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + input-file.h +messages.o : messages.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h +obstack.o : obstack.c +output-file.o : output-file.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + output-file.h +read.o : read.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + +strstr.o : strstr.c +subsegs.o : subsegs.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + subsegs.h +symbols.o : symbols.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + subsegs.h +version.o : version.c +write.o : write.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \ + subsegs.h output-file.h +xmalloc.o : xmalloc.c +xrealloc.o : xrealloc.c +atof-targ.o : atof-targ.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h \ + symbols.h tc.h obj.h +obj-format.o : obj-format.c as.h host.h targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h \ + symbols.h tc.h obj.h +targ-cpu.o : targ-cpu.c targ-env.h obj-format.h \ + targ-cpu.h struc-symbol.h \ + write.h flonum.h bignum.h expr.h frags.h hash.h read.h \ + symbols.h tc.h obj.h $(TARG_CPU_DEPENDENTS) + + +# Compile the libraries to be used by gen*. +# If we are not cross-building, gen* use the same .o's that cc1 will use, +# and HOST_PREFIX_1 is `foobar', just to ensure these rules don't conflict +# with the rules for rtl.o, alloca.o, etc. +$(HOST_PREFIX_1)alloca.o: alloca.c + rm -f $(HOST_PREFIX)alloca.c + cp alloca.c $(HOST_PREFIX)alloca.c + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)alloca.c + +$(HOST_PREFIX_1)obstack.o: obstack.c + rm -f $(HOST_PREFIX)obstack.c + cp obstack.c $(HOST_PREFIX)obstack.c + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)obstack.c + +$(HOST_PREFIX_1)malloc.o: malloc.c + rm -f $(HOST_PREFIX)malloc.c + cp malloc.c $(HOST_PREFIX)malloc.c + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)malloc.c + +# Remake the info files. + +doc: as.info + +as.info: doc/as.texinfo + (cd doc; make as.info; mv as.info $srcdir) + + +# Deletion of files made during compilation. +# There are three levels of this: `clean', `cleanconfig' and `realclean'. +# `clean' deletes what you want to delete ordinarily to save space. +# This is most, but not all, of the files made by compilation. +# `cleanconfig' also deletes everything depending +# on the choice of config files. +# `realclean' also deletes everything that could be regenerated automatically. + +clean: + -rm -f $(STAGESTUFF) +# Delete the temporary source copies for cross compilation. + -rm -f $(HOST_PREFIX_1)alloca.c $(HOST_PREFIX_1)malloc.c + -rm -f $(HOST_PREFIX_1)obstack.c +# Delete the stamp files except stamp-gnulib2. + -rm -f core + +# Like clean but also delete the links made to configure gas. +cleanconfig: clean + -rm -f config.status Makefile host.h targ-env.h + -rm -f targ-cpu.h targ-cpu.c + -rm -f obj-format.h obj-format.c + -rm -f atof-targ.c + +# Get rid of every file that's generated from some other file (except INSTALL). +realclean: cleanconfig + -rm -f gas.aux gas.cps gas.fns gas.info gas.kys gas.pgs gas.tps gas.vrs + -rm -f TAGS + -rm -f gas.info* gas.?? gas.??s gas.log gas.toc gas.*aux + -rm -f *.dvi + +# Entry points `install', `includes' and `uninstall'. + +# Copy the files into directories where they will be run. +install: $(ALL) + $(INSTALL_PROGRAM) $(ALL) $(libsubdir)/as +# cp $(ALL) $(bindir)/as.new +# mv -f $(bindir)/as.new $(bindir)/as + +# Create the installation directory. +install-dir: + -mkdir $(libdir) + -mkdir $(libdir)/gcc + -mkdir $(libdir)/gcc/$(target) + -mkdir $(libdir)/gcc/$(target)/$(version) + +# Install the compiler executables built during cross compilation. +install-cross: native install-dir + -if [ -f cc1 ] ; then $(INSTALL_PROGRAM) cc1 $(libsubdir)/cc1; else true; fi + -if [ -f cc1plus ] ; then $(INSTALL_PROGRAM) cc1plus $(libsubdir)/cc1plus; else true; fi + $(INSTALL_PROGRAM) cpp $(libsubdir)/cpp + ./gcc -dumpspecs > $(libsubdir)/specs + $(INSTALL_PROGRAM) gcc $(bindir)/gcc + +# Install the man pages. +install-man: install-dir gcc.1 protoize.1 unprotoize.1 + $(INSTALL_FILE) gcc.1 $(mandir)/gcc.$(manext) + chmod a-x $(mandir)/gcc.$(manext) + $(INSTALL_FILE) protoize.1 $(mandir)/protoize.$(manext) + chmod a-x $(mandir)/protoize.$(manext) + $(INSTALL_FILE) unprotoize.1 $(mandir)/unprotoize.$(manext) + chmod a-x $(mandir)/unprotoize.$(manext) + +# Cancel installation by deleting the installed files. +uninstall: + -rm -rf $(libsubdir) + -rm -rf $(bindir)/as + -rm -rf $(mandir)/gas.$(manext) + + +# These exist for maintenance purposes. + +tags TAGS: force + etags $(REAL_SOURCES) $(REAL_HEADERS) README Makefile config/*.[hc] + +bootstrap: $(ALL) force + $(MAKE) stage1 + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage1/ $(CFLAGS)" libdir=$(libdir) ALLOCA= $(ALL) + $(MAKE) stage2 + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= $(ALL) + $(MAKE) comparison against=stage2 + +bootstrap2: force + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage1/ $(CFLAGS)" libdir=$(libdir) ALLOCA= $(ALL) + $(MAKE) stage2 + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= $(ALL) + $(MAKE) comparison against=stage2 + +bootstrap3: force + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= $(ALL) + $(MAKE) comparison against=stage2 + +# Copy the object files from a particular stage into a subdirectory. +stage1: force + -mkdir stage1 + -mv $(STAGESTUFF) stage1 + if [ -f stage1/as.new -a ! -f stage1/as ] ; then (cd stage1 ; ln -s as.new as) ; fi + +stage2: force + -mkdir stage2 + -mv $(STAGESTUFF) stage2 + if [ -f stage2/as.new -a ! -f stage2/as ] ; then (cd stage2 ; ln -s as.new as) ; fi + +stage3: force + -mkdir stage3 + -mv $(STAGESTUFF) stage3 + if [ -f stage3/as.new -a ! -f stage3/as ] ; then (cd stage3 ; ln -s as.new as) ; fi + +against=stage2 + +comparison: force + for i in $(STAGESTUFF) ; do cmp $$i $(against)/$$i ; done + +de-stage1: force + - (cd stage1 ; rm as ; mv -f * ..) + - rmdir stage1 + +de-stage2: force + - (cd stage2 ; rm as ; mv -f * ..) + - rmdir stage2 + +de-stage3: force + - (cd stage3 ; rm as ; mv -f * ..) + - rmdir stage3 + +# Copy just the executable files from a particular stage into a subdirectory, +# and delete the object files. Use this if you're just verifying a version +# that is pretty sure to work, and you are short of disk space. +risky-stage1: force + -mkdir stage1 + -mv cc1 cpp cccp gcc stage1 + -rm -f stage1/gnulib + -cp gnulib stage1 && $(RANLIB) stage1/gnulib + -make clean + +risky-stage2: force + -mkdir stage2 + -mv cc1 cpp cccp gcc stage2 + -rm -f stage2/gnulib + -cp gnulib stage2 && $(RANLIB) stage2/gnulib + -make clean + +risky-stage3: force + -mkdir stage3 + -mv cc1 cpp cccp gcc stage3 + -rm -f stage3/gnulib + -cp gnulib stage3 && $(RANLIB) stage3/gnulib + -make clean + +risky-stage4: force + -mkdir stage4 + -mv cc1 cpp cccp gcc stage4 + -rm -f stage4/gnulib + -cp gnulib stage4 && $(RANLIB) stage4/gnulib + -make clean + +#In GNU Make, ignore whether `stage*' exists. +.PHONY: stage1 stage2 stage3 stage4 clean realclean TAGS bootstrap +.PHONY: risky-stage1 risky-stage2 risky-stage3 risky-stage4 + +force: + +Makefile: Makefile.in $(host_makefile_frag) $(target_makefile_frag) + $(SHELL) ./config.status + diff --git a/gnu/usr.bin/as/messages.c b/gnu/usr.bin/as/messages.c new file mode 100644 index 000000000000..2f7f94e7dc33 --- /dev/null +++ b/gnu/usr.bin/as/messages.c @@ -0,0 +1,417 @@ +/* messages.c - error reporter - + Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef lint +static char rcsid[] = "$Id: messages.c,v 1.2 1993/11/03 00:52:01 paul Exp $"; +#endif + +#include <stdio.h> /* define stderr */ +#include <errno.h> + +#include "as.h" + +#ifndef NO_STDARG +#include <stdarg.h> +#else +#ifndef NO_VARARGS +#include <varargs.h> +#endif /* NO_VARARGS */ +#endif /* NO_STDARG */ + +/* + * Despite the rest of the comments in this file, (FIXME-SOON), + * here is the current scheme for error messages etc: + * + * as_fatal() is used when gas is quite confused and + * continuing the assembly is pointless. In this case we + * exit immediately with error status. + * + * as_bad() is used to mark errors that result in what we + * presume to be a useless object file. Say, we ignored + * something that might have been vital. If we see any of + * these, assembly will continue to the end of the source, + * no object file will be produced, and we will terminate + * with error status. The new option, -Z, tells us to + * produce an object file anyway but we still exit with + * error status. The assumption here is that you don't want + * this object file but we could be wrong. + * + * as_warn() is used when we have an error from which we + * have a plausible error recovery. eg, masking the top + * bits of a constant that is longer than will fit in the + * destination. In this case we will continue to assemble + * the source, although we may have made a bad assumption, + * and we will produce an object file and return normal exit + * status (ie, no error). The new option -X tells us to + * treat all as_warn() errors as as_bad() errors. That is, + * no object file will be produced and we will exit with + * error status. The idea here is that we don't kill an + * entire make because of an error that we knew how to + * correct. On the other hand, sometimes you might want to + * stop the make at these points. + * + * as_tsktsk() is used when we see a minor error for which + * our error recovery action is almost certainly correct. + * In this case, we print a message and then assembly + * continues as though no error occurred. + */ + +/* + ERRORS + + JF: this is now bogus. We now print more standard error messages + that try to look like everyone else's. + + We print the error message 1st, beginning in column 1. + All ancillary info starts in column 2 on lines after the + key error text. + We try to print a location in logical and physical file + just after the main error text. + Caller then prints any appendices after that, begining all + lines with at least 1 space. + + Optionally, we may die. + There is no need for a trailing '\n' in your error text format + because we supply one. + + as_warn(fmt,args) Like fprintf(stderr,fmt,args) but also call errwhere(). + + as_fatal(fmt,args) Like as_warn() but exit with a fatal status. + + */ + +static int warning_count = 0; /* Count of number of warnings issued */ + +int had_warnings() { + return(warning_count); +} /* had_err() */ + +/* Nonzero if we've hit a 'bad error', and should not write an obj file, + and exit with a nonzero error code */ + +static int error_count = 0; + +int had_errors() { + return(error_count); +} /* had_errors() */ + + +/* + * a s _ p e r r o r + * + * Like perror(3), but with more info. + */ +void as_perror(gripe, filename) +char *gripe; /* Unpunctuated error theme. */ +char *filename; +{ +#ifndef HAVE_STRERROR + extern char *strerror(); +#endif /* HAVE_STRERROR */ + + as_where(); + fprintf(stderr, gripe, filename); + fprintf(stderr, "%s.\n", strerror(errno)); + errno = 0; /* After reporting, clear it. */ +} /* as_perror() */ + +/* + * a s _ t s k t s k () + * + * Send to stderr a string (with bell) (JF: Bell is obnoxious!) as a warning, and locate warning + * in input file(s). + * Please only use this for when we have some recovery action. + * Please explain in string (which may have '\n's) what recovery was done. + */ + +#ifndef NO_STDARG +void as_tsktsk(Format) +const char *Format; +{ + va_list args; + + as_where(); + va_start(args, Format); + vfprintf(stderr, Format, args); + va_end(args); + (void) putc('\n', stderr); +} /* as_tsktsk() */ +#else +#ifndef NO_VARARGS +void as_tsktsk(Format,va_alist) +char *Format; +va_dcl +{ + va_list args; + + as_where(); + va_start(args); + vfprintf(stderr, Format, args); + va_end(args); + (void) putc('\n', stderr); +} /* as_tsktsk() */ +#else +/*VARARGS1 */ +as_tsktsk(Format,args) +char *Format; +{ + as_where(); + _doprnt (Format, &args, stderr); + (void)putc ('\n', stderr); + /* as_where(); */ +} /* as_tsktsk */ +#endif /* not NO_VARARGS */ +#endif /* not NO_STDARG */ + +#ifdef DONTDEF +void as_tsktsk(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) +char *format; +{ + as_where(); + fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an); + (void)putc('\n',stderr); +} /* as_tsktsk() */ +#endif +/* + * a s _ w a r n () + * + * Send to stderr a string (with bell) (JF: Bell is obnoxious!) as a warning, and locate warning + * in input file(s). + * Please only use this for when we have some recovery action. + * Please explain in string (which may have '\n's) what recovery was done. + */ + +#ifndef NO_STDARG +void as_warn(Format) +const char *Format; +{ + va_list args; + char buffer[200]; + + if (!flagseen['W']) { + ++warning_count; + as_where(); + va_start(args, Format); + fprintf(stderr,"Warning: "); + vsprintf(buffer, Format, args); + fprintf(stderr, buffer); +#ifndef NO_LISTING + listing_warning(buffer); +#endif + va_end(args); + (void) putc('\n', stderr); + } +} /* as_warn() */ +#else +#ifndef NO_VARARGS +void as_warn(Format,va_alist) +char *Format; +va_dcl +{ + va_list args; + char buffer[200]; + + if (!flagseen['W']) { + ++warning_count; + as_where(); + va_start(args); + fprintf(stderr,"Warning: "); + vsprintf(buffer, Format, args); + fprintf(stderr,buffer); +#ifndef NO_LISTING + listing_warning(buffer); +#endif + va_end(args); + (void) putc('\n', stderr); + } +} /* as_warn() */ +#else +/*VARARGS1 */ +as_warn(Format,args) +char *Format; +{ + /* -W supresses warning messages. */ + if (! flagseen['W']) { + ++warning_count; + as_where(); + _doprnt (Format, &args, stderr); + (void)putc ('\n', stderr); + /* as_where(); */ + } +} /* as_warn() */ +#endif /* not NO_VARARGS */ +#endif /* not NO_STDARG */ + +#ifdef DONTDEF +void as_warn(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) +char *format; +{ + if (!flagseen['W']) { + ++warning_count; + as_where(); + fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an); + (void)putc('\n',stderr); + } +} /* as_warn() */ +#endif +/* + * a s _ b a d () + * + * Send to stderr a string (with bell) (JF: Bell is obnoxious!) as a warning, + * and locate warning in input file(s). + * Please us when there is no recovery, but we want to continue processing + * but not produce an object file. + * Please explain in string (which may have '\n's) what recovery was done. + */ + +#ifndef NO_STDARG +void as_bad(Format) +const char *Format; +{ + va_list args; + char buffer[200]; + + ++error_count; + as_where(); + va_start(args, Format); + fprintf(stderr,"Error: "); + + vsprintf(buffer, Format, args); + fprintf(stderr,buffer); +#ifndef NO_LISTING + listing_error(buffer); +#endif + va_end(args); + (void) putc('\n', stderr); +} /* as_bad() */ +#else +#ifndef NO_VARARGS +void as_bad(Format,va_alist) +char *Format; +va_dcl +{ + va_list args; + char buffer[200]; + + ++error_count; + as_where(); + va_start(args); + vsprintf(buffer, Format, args); + fprintf(stderr,buffer); +#ifndef NO_LISTING + listing_error(buffer); +#endif + + va_end(args); + (void) putc('\n', stderr); +} /* as_bad() */ +#else +/*VARARGS1 */ +as_bad(Format,args) +char *Format; +{ + ++error_count; + + as_where(); + fprintf(stderr,"Error: "); + _doprnt (Format, &args, stderr); + (void)putc ('\n', stderr); + /* as_where(); */ +} /* as_bad() */ +#endif /* not NO_VARARGS */ +#endif /* not NO_STDARG */ + +#ifdef DONTDEF +void as_bad(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) +char *format; +{ + ++error_count; + as_where(); + fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an); + (void)putc('\n',stderr); +} /* as_bad() */ +#endif + +/* + * a s _ f a t a l () + * + * Send to stderr a string (with bell) (JF: Bell is obnoxious!) as a fatal + * message, and locate stdsource in input file(s). + * Please only use this for when we DON'T have some recovery action. + * It exit()s with a warning status. + */ + +#ifndef NO_STDARG +void as_fatal(Format) +const char *Format; +{ + va_list args; + + as_where(); + va_start(args, Format); + fprintf (stderr, "FATAL:"); + vfprintf(stderr, Format, args); + (void) putc('\n', stderr); + va_end(args); + exit(33); +} /* as_fatal() */ +#else +#ifndef NO_VARARGS +void as_fatal(Format,va_alist) +char *Format; +va_dcl +{ + va_list args; + + as_where(); + va_start(args); + fprintf (stderr, "FATAL:"); + vfprintf(stderr, Format, args); + (void) putc('\n', stderr); + va_end(args); + exit(33); +} /* as_fatal() */ +#else +/*VARARGS1 */ +as_fatal(Format, args) +char *Format; +{ + as_where(); + fprintf(stderr,"FATAL:"); + _doprnt (Format, &args, stderr); + (void)putc ('\n', stderr); + /* as_where(); */ + exit(33); /* What is a good exit status? */ +} /* as_fatal() */ +#endif /* not NO_VARARGS */ +#endif /* not NO_STDARG */ + +#ifdef DONTDEF +void as_fatal(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) +char *Format; +{ + as_where(); + fprintf (stderr, "FATAL:"); + fprintf(stderr, Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an); + (void) putc('\n', stderr); + exit(33); +} /* as_fatal() */ +#endif + +/* end of messages.c */ diff --git a/gnu/usr.bin/as/obj.h b/gnu/usr.bin/as/obj.h new file mode 100644 index 000000000000..877d270eaa6a --- /dev/null +++ b/gnu/usr.bin/as/obj.h @@ -0,0 +1,77 @@ +/* obj.h - defines the object dependent hooks for all object + format backends. + + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: obj.h,v 1.1 1993/11/03 00:52:03 paul Exp $ + */ + + +#if __STDC__ == 1 + +char *obj_default_output_file_name(void); +void obj_crawl_symbol_chain(object_headers *headers); +void obj_emit_relocations(char **where, fixS *fixP, relax_addressT segment_address_in_file); +void obj_emit_strings(char **where); +void obj_emit_symbols(char **where, symbolS *symbol_rootP); +void obj_header_append(char **where, object_headers *headers); +void obj_read_begin_hook(void); + +#ifndef obj_symbol_new_hook +void obj_symbol_new_hook(symbolS *symbolP); +#endif /* obj_symbol_new_hook */ + +void obj_symbol_to_chars(char **where, symbolS *symbolP); + +#ifndef obj_pre_write_hook +void obj_pre_write_hook(object_headers *headers); +#endif /* obj_pre_write_hook */ + +#else /* not __STDC__ */ + +char *obj_default_output_file_name(); +void obj_crawl_symbol_chain(); +void obj_emit_relocations(); +void obj_emit_strings(); +void obj_emit_symbols(); +void obj_header_append(); +void obj_read_begin_hook(); + +#ifndef obj_symbol_new_hook +void obj_symbol_new_hook(); +#endif /* obj_symbol_new_hook */ + +void obj_symbol_to_chars(); + +#ifndef obj_pre_write_hook +void obj_pre_write_hook(); +#endif /* obj_pre_write_hook */ + +#endif /* not __STDC__ */ + +extern const pseudo_typeS obj_pseudo_table[]; + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj.h */ diff --git a/gnu/usr.bin/as/obstack.c b/gnu/usr.bin/as/obstack.c new file mode 100644 index 000000000000..b36bdada55ea --- /dev/null +++ b/gnu/usr.bin/as/obstack.c @@ -0,0 +1,374 @@ +/* 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 2, 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. */ + +#ifndef lint +static char rcsid[] = "$Id: obstack.c,v 1.2 1993/11/03 00:52:04 paul Exp $"; +#endif + +#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; + /* The initial chunk now contains no empty object. */ + h->maybe_empty_object = 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. + But not if that chunk might contain an empty object. */ + if (h->object_base == old_chunk->contents && ! h->maybe_empty_object) + { + new_chunk->prev = old_chunk->prev; + (*h->freefun) (old_chunk); + } + + h->object_base = new_chunk->contents; + h->next_free = h->object_base + obj_size; + /* The new chunk certainly contains no empty object yet. */ + h->maybe_empty_object = 0; +} + +/* 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; + /* We use >= rather than > since the object cannot be exactly at + the beginning of the chunk but might be an empty object exactly + at the end of an adjacent 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. */ + +#undef obstack_free + +/* This function has two names with identical definitions. + This is the first one, called from non-ANSI code. */ + +void +_obstack_free (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; + /* 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 we switch chunks, we can't tell whether the new current + chunk contains an empty object, so assume that it may. */ + h->maybe_empty_object = 1; + } + 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 (); +} + +/* This function is used from ANSI code. */ + +void +obstack_free (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; + /* 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 we switch chunks, we can't tell whether the new current + chunk contains an empty object, so assume that it may. */ + h->maybe_empty_object = 1; + } + 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 (); +} + +#if 0 +/* These are now turned off because the applications do not use it + and it uses bcopy via obstack_grow, which causes trouble on sysV. */ + +/* Now define the functional versions of the obstack macros. + Define them to simply use the corresponding macros to do the job. */ + +#ifdef __STDC__ +/* These function definitions do not work with non-ANSI preprocessors; + they won't pass through the macro names in parentheses. */ + +/* The function names appear in parentheses in order to prevent + the macro-definitions of the names from being expanded there. */ + +POINTER (obstack_base) (obstack) + struct obstack *obstack; +{ + return obstack_base (obstack); +} + +POINTER (obstack_next_free) (obstack) + struct obstack *obstack; +{ + return obstack_next_free (obstack); +} + +int (obstack_object_size) (obstack) + struct obstack *obstack; +{ + return obstack_object_size (obstack); +} + +int (obstack_room) (obstack) + struct obstack *obstack; +{ + return obstack_room (obstack); +} + +void (obstack_grow) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + obstack_grow (obstack, pointer, length); +} + +void (obstack_grow0) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + obstack_grow0 (obstack, pointer, length); +} + +void (obstack_1grow) (obstack, character) + struct obstack *obstack; + int character; +{ + obstack_1grow (obstack, character); +} + +void (obstack_blank) (obstack, length) + struct obstack *obstack; + int length; +{ + obstack_blank (obstack, length); +} + +void (obstack_1grow_fast) (obstack, character) + struct obstack *obstack; + int character; +{ + obstack_1grow_fast (obstack, character); +} + +void (obstack_blank_fast) (obstack, length) + struct obstack *obstack; + int length; +{ + obstack_blank_fast (obstack, length); +} + +POINTER (obstack_finish) (obstack) + struct obstack *obstack; +{ + return obstack_finish (obstack); +} + +POINTER (obstack_alloc) (obstack, length) + struct obstack *obstack; + int length; +{ + return obstack_alloc (obstack, length); +} + +POINTER (obstack_copy) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + return obstack_copy (obstack, pointer, length); +} + +POINTER (obstack_copy0) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + return obstack_copy0 (obstack, pointer, length); +} + +#endif /* __STDC__ */ + +#endif /* 0 */ diff --git a/gnu/usr.bin/as/obstack.h b/gnu/usr.bin/as/obstack.h new file mode 100644 index 000000000000..74d36e0c61cd --- /dev/null +++ b/gnu/usr.bin/as/obstack.h @@ -0,0 +1,448 @@ +/* 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 2, 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. */ +/* + * $Id: obstack.h,v 1.2 1993/11/03 00:52:06 paul Exp $ + */ + + +/* 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. */ + /* Nonzero means there is a possibility the current chunk contains + a zero-length object. This prevents freeing the chunk + if we allocate a bigger chunk to replace it. */ + char maybe_empty_object; +}; + +/* 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, (void (*) ())obstack_chunk_free) + +#define obstack_begin(h, size) \ + _obstack_begin ((h), (size), 0, \ + (void *(*) ()) obstack_chunk_alloc, (void (*) ())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__) +#if __GNUC__ < 2 +#define __extension__ +#endif + +/* 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) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + (unsigned) (__o->next_free - __o->object_base); }) + +#define obstack_room(OBSTACK) \ + __extension__ \ + ({ 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) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + ((__o->next_free + __len > __o->chunk_limit) \ + ? (_obstack_newchunk (__o, __len), 0) : 0); \ + memcpy (__o->next_free, where, __len); \ + __o->next_free += __len; \ + (void) 0; }) + +#define obstack_grow0(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + ((__o->next_free + __len + 1 > __o->chunk_limit) \ + ? (_obstack_newchunk (__o, __len + 1), 0) : 0), \ + memcpy (__o->next_free, where, __len), \ + __o->next_free += __len, \ + *(__o->next_free)++ = 0; \ + (void) 0; }) + +#define obstack_1grow(OBSTACK,datum) \ +__extension__ \ +({ 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) \ +__extension__ \ +({ 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) \ +__extension__ \ +({ 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) \ +__extension__ \ +({ 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) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_blank (__h, (length)); \ + obstack_finish (__h); }) + +#define obstack_copy(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow (__h, (where), (length)); \ + obstack_finish (__h); }) + +#define obstack_copy0(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow0 (__h, (where), (length)); \ + obstack_finish (__h); }) + +/* The local variable is named __o1 to avoid a name conflict + when obstack_blank is called. */ +#define obstack_finish(OBSTACK) \ +__extension__ \ +({ struct obstack *__o1 = (OBSTACK); \ + void *value = (void *) __o1->object_base; \ + if (__o1->next_free == value) \ + __o1->maybe_empty_object = 1; \ + __o1->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT (__o1->next_free)+__o1->alignment_mask)\ + & ~ (__o1->alignment_mask)); \ + ((__o1->next_free - (char *)__o1->chunk \ + > __o1->chunk_limit - (char *)__o1->chunk) \ + ? (__o1->next_free = __o1->chunk_limit) : 0); \ + __o1->object_base = __o1->next_free; \ + value; }) + +#define obstack_free(OBSTACK, OBJ) \ +__extension__ \ +({ 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), \ + memcpy ((h)->next_free, where, (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), \ + memcpy ((h)->next_free, where, (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)++ = ((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)++ = ((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)->next_free == (h)->object_base \ + ? (((h)->maybe_empty_object = 1), 0) \ + : 0), \ + (h)->temp = __PTR_TO_INT ((h)->object_base), \ + (h)->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \ + & ~ ((h)->alignment_mask)), \ + (((h)->next_free - (char *)(h)->chunk \ + > (h)->chunk_limit - (char *)(h)->chunk) \ + ? ((h)->next_free = (h)->chunk_limit) : 0), \ + (h)->object_base = (h)->next_free, \ + __INT_TO_PTR ((h)->temp)) + +#ifdef __STDC__ +#define obstack_free(h,obj) \ +( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \ + (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0))) +#else +#define obstack_free(h,obj) \ +( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \ + (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0))) +#endif + +#endif /* not __GNUC__ or not __STDC__ */ + +#endif /* not __OBSTACKS__ */ diff --git a/gnu/usr.bin/as/opcode/ChangeLog b/gnu/usr.bin/as/opcode/ChangeLog new file mode 100644 index 000000000000..dcb04987b907 --- /dev/null +++ b/gnu/usr.bin/as/opcode/ChangeLog @@ -0,0 +1,56 @@ +Mon Feb 24 02:02:04 1992 K. Richard Pixley (rich@cygnus.com) + + * ns32k.h: SEQUENT_COMPATIBILITY -> TE_SEQUENT. + + * i860.h: added "fst.q". + +Fri Feb 21 01:29:51 1992 K. Richard Pixley (rich@cygnus.com) + + * i386.h: added inb, inw, outb, outw opcodes, added att syntax for + scmp, slod, smov, ssca, ssto. Curtesy Minh Tran-Le + <TRANLE@INTELLICORP.COM>. + +Thu Jan 30 07:31:44 1992 Steve Chamberlain (sac at rtl.cygnus.com) + + * h8300.h: turned op_type enum into #define list + +Thu Jan 30 01:07:24 1992 John Gilmore (gnu at cygnus.com) + + * sparc.h: Remove "cypress" architecture. Remove "fitox" and + similar instructions -- they've been renamed to "fitoq", etc. + REALLY fix tsubcctv. Fix "fcmpeq" and "fcmpq" which had wrong + number of arguments. + * h8300.h: Remove extra ; which produces compiler warning. + +Tue Jan 28 22:59:22 1992 Stu Grossman (grossman at cygnus.com) + + * sparc.h: fix opcode for tsubcctv. + +Tue Jan 7 17:19:39 1992 K. Richard Pixley (rich at cygnus.com) + + * sparc.h: fba and cba are now aliases for fb and cb respectively. + +Fri Dec 27 10:55:50 1991 Per Bothner (bothner at cygnus.com) + + * sparc.h (nop): Made the 'lose' field be even tighter, + so only a standard 'nop' is disassembled as a nop. + +Sun Dec 22 12:18:18 1991 Michael Tiemann (tiemann at cygnus.com) + + * sparc.h (nop): Add RD_GO to `lose' so that only %g0 in dest is + disassembled as a nop. + +Tue Dec 10 00:22:20 1991 K. Richard Pixley (rich at rtl.cygnus.com) + + * sparc.h: fix a typo. + +Sat Nov 30 20:40:51 1991 Steve Chamberlain (sac at rtl.cygnus.com) + + * a29k.h, arm.h, h8300.h, i386.h, i860.h, i960.h , m68k.h, + m88k.h, mips.h , np1.h, ns32k.h, pn.h, pyr.h, sparc.h, tahoe.h, + vax.h, ChangeLog: renamed from ../<foo>-opcode.h + + + + + diff --git a/gnu/usr.bin/as/opcode/a29k.h b/gnu/usr.bin/as/opcode/a29k.h new file mode 100644 index 000000000000..675f053d50e3 --- /dev/null +++ b/gnu/usr.bin/as/opcode/a29k.h @@ -0,0 +1,330 @@ +/* Table of opcodes for the AMD 29000 + Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of GDB and GAS. + +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; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct a29k_opcode { + /* Name of the instruction. */ + char *name; + + /* Opcode word */ + unsigned long opcode; + + /* A string of characters which describe the operands. + Valid characters are: + , Itself. The character appears in the assembly code. + a RA. The register number is in bits 8-15 of the instruction. + b RB. The register number is in bits 0-7 of the instruction. + c RC. The register number is in bits 16-23 of the instruction. + i An immediate operand is in bits 0-7 of the instruction. + x Bits 0-7 and 16-23 of the instruction are bits 0-7 and 8-15 + (respectively) of the immediate operand. + h Same as x but the instruction contains bits 16-31 of the + immediate operand. + X Same as x but bits 16-31 of the signed immediate operand + are set to 1 (thus the operand is always negative). + P,A Bits 0-7 and 16-23 of the instruction are bits 2-9 and 10-17 + (respectively) of the immediate operand. + P=PC-relative, sign-extended to 32 bits. + A=Absolute, zero-extended to 32 bits. + e CE bit (bit 23) for a load/store instruction. + n Control field (bits 16-22) for a load/store instruction. + v Immediate operand in bits 16-23 of the instruction. + (used for trap numbers). + s SA. Special-purpose register number in bits 8-15 + of the instruction. + u UI--bit 7 of the instruction. + r RND--bits 4-6 of the instruction. + d FD--bits 2-3 of the instruction. + f FS--bits 0-1 of the instruction. + + Extensions for 29050: + + d FMT--bits 2-3 of the instruction (not really new). + f ACN--bits 0-1 of the instruction (not really new). + F FUNC--Special function in bits 18-21 of the instruction. + C ACN--bits 16-17 specifying the accumlator register. */ + char *args; +}; + +#ifndef CONST +#define CONST +#endif /* CONST */ + +static CONST struct a29k_opcode a29k_opcodes[] = +{ + +{ "add", 0x14000000, "c,a,b" }, +{ "add", 0x15000000, "c,a,i" }, +{ "addc", 0x1c000000, "c,a,b" }, +{ "addc", 0x1d000000, "c,a,i" }, +{ "addcs", 0x18000000, "c,a,b" }, +{ "addcs", 0x19000000, "c,a,i" }, +{ "addcu", 0x1a000000, "c,a,b" }, +{ "addcu", 0x1b000000, "c,a,i" }, +{ "adds", 0x10000000, "c,a,b" }, +{ "adds", 0x11000000, "c,a,i" }, +{ "addu", 0x12000000, "c,a,b" }, +{ "addu", 0x13000000, "c,a,i" }, +{ "and", 0x90000000, "c,a,b" }, +{ "and", 0x91000000, "c,a,i" }, +{ "andn", 0x9c000000, "c,a,b" }, +{ "andn", 0x9d000000, "c,a,i" }, +{ "aseq", 0x70000000, "v,a,b" }, +{ "aseq", 0x71000000, "v,a,i" }, +{ "asge", 0x5c000000, "v,a,b" }, +{ "asge", 0x5d000000, "v,a,i" }, +{ "asgeu", 0x5e000000, "v,a,b" }, +{ "asgeu", 0x5f000000, "v,a,i" }, +{ "asgt", 0x58000000, "v,a,b" }, +{ "asgt", 0x59000000, "v,a,i" }, +{ "asgtu", 0x5a000000, "v,a,b" }, +{ "asgtu", 0x5b000000, "v,a,i" }, +{ "asle", 0x54000000, "v,a,b" }, +{ "asle", 0x55000000, "v,a,i" }, +{ "asleu", 0x56000000, "v,a,b" }, +{ "asleu", 0x57000000, "v,a,i" }, +{ "aslt", 0x50000000, "v,a,b" }, +{ "aslt", 0x51000000, "v,a,i" }, +{ "asltu", 0x52000000, "v,a,b" }, +{ "asltu", 0x53000000, "v,a,i" }, +{ "asneq", 0x72000000, "v,a,b" }, +{ "asneq", 0x73000000, "v,a,i" }, +{ "call", 0xa8000000, "a,P" }, +{ "call", 0xa9000000, "a,A" }, +{ "calli", 0xc8000000, "a,b" }, +{ "class", 0xe6000000, "c,a,f" }, +{ "clz", 0x08000000, "c,b" }, +{ "clz", 0x09000000, "c,i" }, +{ "const", 0x03000000, "a,x" }, +{ "consth", 0x02000000, "a,h" }, +{ "consthz", 0x05000000, "a,h" }, +{ "constn", 0x01000000, "a,X" }, +{ "convert", 0xe4000000, "c,a,u,r,d,f" }, +{ "cpbyte", 0x2e000000, "c,a,b" }, +{ "cpbyte", 0x2f000000, "c,a,i" }, +{ "cpeq", 0x60000000, "c,a,b" }, +{ "cpeq", 0x61000000, "c,a,i" }, +{ "cpge", 0x4c000000, "c,a,b" }, +{ "cpge", 0x4d000000, "c,a,i" }, +{ "cpgeu", 0x4e000000, "c,a,b" }, +{ "cpgeu", 0x4f000000, "c,a,i" }, +{ "cpgt", 0x48000000, "c,a,b" }, +{ "cpgt", 0x49000000, "c,a,i" }, +{ "cpgtu", 0x4a000000, "c,a,b" }, +{ "cpgtu", 0x4b000000, "c,a,i" }, +{ "cple", 0x44000000, "c,a,b" }, +{ "cple", 0x45000000, "c,a,i" }, +{ "cpleu", 0x46000000, "c,a,b" }, +{ "cpleu", 0x47000000, "c,a,i" }, +{ "cplt", 0x40000000, "c,a,b" }, +{ "cplt", 0x41000000, "c,a,i" }, +{ "cpltu", 0x42000000, "c,a,b" }, +{ "cpltu", 0x43000000, "c,a,i" }, +{ "cpneq", 0x62000000, "c,a,b" }, +{ "cpneq", 0x63000000, "c,a,i" }, +{ "dadd", 0xf1000000, "c,a,b" }, +{ "ddiv", 0xf7000000, "c,a,b" }, +{ "deq", 0xeb000000, "c,a,b" }, +{ "dge", 0xef000000, "c,a,b" }, +{ "dgt", 0xed000000, "c,a,b" }, +{ "div", 0x6a000000, "c,a,b" }, +{ "div", 0x6b000000, "c,a,i" }, +{ "div0", 0x68000000, "c,b" }, +{ "div0", 0x69000000, "c,i" }, +{ "divide", 0xe1000000, "c,a,b" }, +{ "dividu", 0xe3000000, "c,a,b" }, +{ "divl", 0x6c000000, "c,a,b" }, +{ "divl", 0x6d000000, "c,a,i" }, +{ "divrem", 0x6e000000, "c,a,b" }, +{ "divrem", 0x6f000000, "c,a,i" }, +{ "dmac", 0xd9000000, "F,C,a,b" }, +{ "dmsm", 0xdb000000, "c,a,b" }, +{ "dmul", 0xf5000000, "c,a,b" }, +{ "dsub", 0xf3000000, "c,a,b" }, +{ "emulate", 0xd7000000, "v,a,b" }, +{ "exbyte", 0x0a000000, "c,a,b" }, +{ "exbyte", 0x0b000000, "c,a,i" }, +{ "exhw", 0x7c000000, "c,a,b" }, +{ "exhw", 0x7d000000, "c,a,i" }, +{ "exhws", 0x7e000000, "c,a" }, +{ "extract", 0x7a000000, "c,a,b" }, +{ "extract", 0x7b000000, "c,a,i" }, +{ "fadd", 0xf0000000, "c,a,b" }, +{ "fdiv", 0xf6000000, "c,a,b" }, +{ "fdmul", 0xf9000000, "c,a,b" }, +{ "feq", 0xea000000, "c,a,b" }, +{ "fge", 0xee000000, "c,a,b" }, +{ "fgt", 0xec000000, "c,a,b" }, +{ "fmac", 0xd8000000, "F,C,a,b" }, +{ "fmsm", 0xda000000, "c,a,b" }, +{ "fmul", 0xf4000000, "c,a,b" }, +{ "fsub", 0xf2000000, "c,a,b" }, +{ "halt", 0x89000000, "" }, +{ "inbyte", 0x0c000000, "c,a,b" }, +{ "inbyte", 0x0d000000, "c,a,i" }, +{ "inhw", 0x78000000, "c,a,b" }, +{ "inhw", 0x79000000, "c,a,i" }, +{ "inv", 0x9f000000, "" }, +{ "iret", 0x88000000, "" }, +{ "iretinv", 0x8c000000, "" }, +{ "jmp", 0xa0000000, "P" }, +{ "jmp", 0xa1000000, "A" }, +{ "jmpf", 0xa4000000, "a,P" }, +{ "jmpf", 0xa5000000, "a,A" }, +{ "jmpfdec", 0xb4000000, "a,P" }, +{ "jmpfdec", 0xb5000000, "a,A" }, +{ "jmpfi", 0xc4000000, "a,b" }, +{ "jmpi", 0xc0000000, "b" }, +{ "jmpt", 0xac000000, "a,P" }, +{ "jmpt", 0xad000000, "a,A" }, +{ "jmpti", 0xcc000000, "a,b" }, +{ "load", 0x16000000, "e,n,a,b" }, +{ "load", 0x17000000, "e,n,a,i" }, +{ "loadl", 0x06000000, "e,n,a,b" }, +{ "loadl", 0x07000000, "e,n,a,i" }, +{ "loadm", 0x36000000, "e,n,a,b" }, +{ "loadm", 0x37000000, "e,n,a,i" }, +{ "loadset", 0x26000000, "e,n,a,b" }, +{ "loadset", 0x27000000, "e,n,a,i" }, +{ "mfacc", 0xe9000100, "c,d,f" }, +{ "mfsr", 0xc6000000, "c,s" }, +{ "mftlb", 0xb6000000, "c,a" }, +{ "mtacc", 0xe8010000, "a,d,f" }, +{ "mtsr", 0xce000000, "s,b" }, +{ "mtsrim", 0x04000000, "s,x" }, +{ "mttlb", 0xbe000000, "a,b" }, +{ "mul", 0x64000000, "c,a,b" }, +{ "mul", 0x65000000, "c,a,i" }, +{ "mull", 0x66000000, "c,a,b" }, +{ "mull", 0x67000000, "c,a,i" }, +{ "multiplu", 0xe2000000, "c,a,b" }, +{ "multiply", 0xe0000000, "c,a,b" }, +{ "multm", 0xde000000, "c,a,b" }, +{ "multmu", 0xdf000000, "c,a,b" }, +{ "mulu", 0x74000000, "c,a,b" }, +{ "mulu", 0x75000000, "c,a,i" }, +{ "nand", 0x9a000000, "c,a,b" }, +{ "nand", 0x9b000000, "c,a,i" }, +{ "nop", 0x70400101, "" }, +{ "nor", 0x98000000, "c,a,b" }, +{ "nor", 0x99000000, "c,a,i" }, +{ "or", 0x92000000, "c,a,b" }, +{ "or", 0x93000000, "c,a,i" }, +{ "orn", 0xaa000000, "c,a,b" }, +{ "orn", 0xab000000, "c,a,i" }, + +/* The description of "setip" in Chapter 8 ("instruction set") of the user's + manual claims that these are absolute register numbers. But section + 7.2.1 explains that they are not. The latter is correct, so print + these normally ("lr0", "lr5", etc.). */ +{ "setip", 0x9e000000, "c,a,b" }, + +{ "sll", 0x80000000, "c,a,b" }, +{ "sll", 0x81000000, "c,a,i" }, +{ "sqrt", 0xe5000000, "c,a,f" }, +{ "sra", 0x86000000, "c,a,b" }, +{ "sra", 0x87000000, "c,a,i" }, +{ "srl", 0x82000000, "c,a,b" }, +{ "srl", 0x83000000, "c,a,i" }, +{ "store", 0x1e000000, "e,n,a,b" }, +{ "store", 0x1f000000, "e,n,a,i" }, +{ "storel", 0x0e000000, "e,n,a,b" }, +{ "storel", 0x0f000000, "e,n,a,i" }, +{ "storem", 0x3e000000, "e,n,a,b" }, +{ "storem", 0x3f000000, "e,n,a,i" }, +{ "sub", 0x24000000, "c,a,b" }, +{ "sub", 0x25000000, "c,a,i" }, +{ "subc", 0x2c000000, "c,a,b" }, +{ "subc", 0x2d000000, "c,a,i" }, +{ "subcs", 0x28000000, "c,a,b" }, +{ "subcs", 0x29000000, "c,a,i" }, +{ "subcu", 0x2a000000, "c,a,b" }, +{ "subcu", 0x2b000000, "c,a,i" }, +{ "subr", 0x34000000, "c,a,b" }, +{ "subr", 0x35000000, "c,a,i" }, +{ "subrc", 0x3c000000, "c,a,b" }, +{ "subrc", 0x3d000000, "c,a,i" }, +{ "subrcs", 0x38000000, "c,a,b" }, +{ "subrcs", 0x39000000, "c,a,i" }, +{ "subrcu", 0x3a000000, "c,a,b" }, +{ "subrcu", 0x3b000000, "c,a,i" }, +{ "subrs", 0x30000000, "c,a,b" }, +{ "subrs", 0x31000000, "c,a,i" }, +{ "subru", 0x32000000, "c,a,b" }, +{ "subru", 0x33000000, "c,a,i" }, +{ "subs", 0x20000000, "c,a,b" }, +{ "subs", 0x21000000, "c,a,i" }, +{ "subu", 0x22000000, "c,a,b" }, +{ "subu", 0x23000000, "c,a,i" }, +{ "xnor", 0x96000000, "c,a,b" }, +{ "xnor", 0x97000000, "c,a,i" }, +{ "xor", 0x94000000, "c,a,b" }, +{ "xor", 0x95000000, "c,a,i" }, + +{ "", 0x0, "" } /* Dummy entry, not included in NUM_OPCODES. This + lets code examine entry i+1 without checking + if we've run off the end of the table. */ +}; + +CONST unsigned int num_opcodes = (((sizeof a29k_opcodes) / (sizeof a29k_opcodes[0])) - 1); + +/* + * $Log: a29k.h,v $ + * Revision 1.1 1993/11/03 00:55:48 paul + * Brought over NetBSD's gas ready for pk's shared libs. + * + * Revision 1.1 1993/10/02 21:00:40 pk + * GNU gas 1.92.3 based assembler supporting PIC code (for i386 and sparc). + * + * Revision 1.2 1992/02/29 17:10:43 rich + * various smallish fixes from mail archives + * + * Revision 1.1.1.1 1992/02/24 02:34:30 rich + * devo fork + * + * Revision 1.1 1991/12/01 02:22:19 sac + * Initial revision + * + * Revision 1.5 1991/11/07 16:59:19 sac + * Fixed encoding of mtacc instruction. + * + * Revision 1.4 1991/08/06 07:20:27 rich + * Fixing CONST declarations. + * + * Revision 1.3 1991/08/05 22:31:05 rich + * *** empty log message *** + * + * Revision 1.2 1991/07/15 23:34:04 steve + * *** empty log message *** + * + * Revision 1.1 1991/05/19 00:19:33 rich + * Initial revision + * + * Revision 1.1.1.1 1991/04/04 18:15:23 rich + * new gas main line + * + * Revision 1.1 1991/04/04 18:15:23 rich + * Initial revision + * + * Revision 1.2 1991/03/30 17:13:19 rich + * num_opcodes now unsigned. Also, added rcsid and log. + * + * + */ + +/* end of a29k-opcode.h */ diff --git a/gnu/usr.bin/as/opcode/h8300.h b/gnu/usr.bin/as/opcode/h8300.h new file mode 100644 index 000000000000..f4702a8f2f16 --- /dev/null +++ b/gnu/usr.bin/as/opcode/h8300.h @@ -0,0 +1,266 @@ +/* Opcode table for the H8-300 + Copyright (C) 1991,1992 Free Software Foundation. + Written by Steve Chamberlain, sac@cygnus.com. + +This file is part of GDB, the GNU Debugger and GAS, the GNU Assembler. + +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 2 of the License, 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. */ + +typedef int op_type; + +#define Hex0 0 +#define Hex1 1 +#define Hex2 2 +#define Hex3 3 +#define Hex4 4 +#define Hex5 5 +#define Hex6 6 +#define Hex7 7 +#define Hex8 8 +#define Hex9 9 +#define HexA 10 +#define HexB 11 +#define HexC 12 +#define HexD 13 +#define HexE 14 +#define HexF 15 +#define START 0x20 +#define KBIT 0x21 /* K is #1, or #2, yielding 0x0 or 0x8 */ +#define IMM3 0x22 /* bit number */ +#define RD8 0x23 /* 8 bit reg as 2nd op */ +#define RD16 0x24 /* 16 bit reg as 2nd op */ +#define RS8 0x25 /* 8 bit reg as 1st op */ +#define RS16 0x26 /* 16 bit reg 1st op */ +#define IMM8 0x27 /* constant which fits into 8 bits */ +#define IMM16 0x28 /* constant which fits into 16 bits */ +#define CCR 0x29 /* CCR reg */ +#define ABS8SRC 0x2a /* abs 8 address mode */ +#define ABS8DST 0x2b /* abs 8 address mode */ +#define DISP8 0x2c /* pc rel displacement */ +#define ABS16SRC 0x2d /* abs 16 address mode */ +#define ABS16OR8SRC 0x2e /* abs 16 address mode, but could be abs 8 */ +#define ABS16DST 0x2f /* abs 16 address mode */ +#define ABS16OR8DST 0x30 /* abs 16 address mode */ +#define DISPSRC 0x31 /* @(r:16) address mode src */ +#define DISPDST 0x32 /* @(r:16) address mode dst*/ +#define DISPREG 0x33 /* register from DISP address mode */ +#define RDDEC 0x34 /* @-rn mode */ +#define RSINC 0x35 /* @rn+ mode */ +#define RDIND 0x36 /* @R mode dst */ +#define RSIND 0x37 /* @R mode src */ +#define MEMIND 0x38 /* @@abs8 mode */ +#define ABS16ORREL8SRC 0x39 /* abs 16bit or pcrel */ +#define IGNORE 0x3a +#define B30 0x40 /* bit 3 must be low */ +#define B31 0x80 /* bit 3 must be high */ +#define E 0x81 /* End of list */ + + + +struct code +{ + op_type nib[9]; +} ; + +struct arg +{ + op_type nib[3]; +} ; + +struct h8_opcode +{ + char *name; + struct arg args; + struct code data; + char length; + char noperands; + char idx; + char size; + +}; + + + + + +#ifdef DEFINE_TABLE + +#define BITOP(imm, name, op00, op01,op10,op11, op20,op21)\ +{ name, {imm,RD8,E}, {op00, op01, imm, RD8,E}},\ +{ name, {imm,RDIND,E}, {op10, op11, RDIND, 0, op00,op01, imm, 0,E}},\ +{ name, {imm,ABS8DST,E},{op20, op21, ABS8DST, IGNORE, op00,op01, imm, 0,E}} + +#define EBITOP(imm, name, op00, op01,op10,op11, op20,op21)\ + BITOP(imm, name, op00+1, op01, op10,op11, op20,op21),\ + BITOP(RS8, name, op00, op01, op10,op11, op20,op21) + +#define WTWOP(name, op1, op2) \ +{ name, {RS16, RD16, E}, { op1, op2, RS16, RD16, E}} + +#define BRANCH(name, op) \ +{ name,{DISP8,E}, { Hex4, op, DISP8,IGNORE,E }} + +#define SOP(name) \ +{ name +#define EOP } + + +#define TWOOP(name, op1, op2,op3) \ +{ name, {IMM8, RD8,E}, { op1, RD8, IMM8,IGNORE,E}},\ +{ name, {RS8, RD8, E}, { op2, op3, RS8, RD8 ,E}} + +#define UNOP(name, op1, op2) \ +{ name, {RS8, E}, { op1, op2, 0, RS8, E}} + +#define UNOP3(name, op1, op2, op3) \ +{ name , {RS8, E}, {op1, op2, op3, RS8, E}} + +struct h8_opcode h8_opcodes[] += +{ + TWOOP("add.b", Hex8, Hex0,Hex8), + WTWOP("add.w", Hex0, Hex9), + SOP("adds"), {KBIT,RD16|B30, E}, {Hex0, HexB, KBIT, RD16|B30, E} EOP, + TWOOP("addx", Hex9,Hex0,HexE), + TWOOP("and", HexE,Hex1,Hex6), + SOP("andc"), {IMM8, CCR, E}, { Hex0, Hex6, IMM8,IGNORE, E} EOP, + BITOP(IMM3|B30, "band", Hex7, Hex6, Hex7, HexC, Hex7, HexE), + BRANCH("bra", Hex0), + BRANCH("bt", Hex0), + BRANCH("brn", Hex1), + BRANCH("bf", Hex1), + BRANCH("bhi", Hex2), + BRANCH("bls", Hex3), + BRANCH("bcc", Hex4), + BRANCH("bhs", Hex4), + BRANCH("bcs", Hex5), + BRANCH("blo", Hex5), + BRANCH("bne", Hex6), + BRANCH("beq", Hex7), + BRANCH("bvc", Hex8), + BRANCH("bvs", Hex9), + BRANCH("bpl", HexA), + BRANCH("bmi", HexB), + BRANCH("bge", HexC), + BRANCH("blt", HexD), + BRANCH("bgt", HexE), + BRANCH("ble", HexF), + EBITOP(IMM3|B30,"bclr", Hex6, Hex2, Hex7, HexD, Hex7, HexF), + BITOP(IMM3|B31,"biand", Hex7, Hex6, Hex7, HexC, Hex7, HexE), + BITOP(IMM3|B31, "bild", Hex7, Hex7,Hex7, HexC, Hex7, HexE), + BITOP(IMM3|B31, "bior", Hex7, Hex4,Hex7, HexC, Hex7, HexE), + BITOP(IMM3|B31, "bist", Hex6, Hex7,Hex7, HexD, Hex7, HexE), + BITOP(IMM3|B31, "bixor", Hex7, Hex5,Hex7, HexC, Hex7, HexE), + BITOP(IMM3|B30, "bld", Hex7, Hex7,Hex7, HexC, Hex7, HexE), + EBITOP(IMM3|B30,"bnot", Hex6, Hex1, Hex7, HexD, Hex7, HexF), + BITOP(IMM3|B30,"bor", Hex7, Hex4,Hex7, HexC, Hex7, HexE), + EBITOP(IMM3|B30,"bset", Hex6, Hex0,Hex7, HexD, Hex7, HexF), + SOP("bsr"),{DISP8, E},{ Hex5, Hex5, DISP8,IGNORE, E}, EOP, + BITOP(IMM3|B30, "bst", Hex6, Hex7,Hex7, HexD, Hex7, HexF), + EBITOP(IMM3|B30, "btst", Hex6, Hex3,Hex7, HexC, Hex7, HexE), + BITOP(IMM3|B30, "bxor", Hex7,Hex5,Hex7, HexC, Hex7, HexE), + TWOOP( "cmp.b",HexA, Hex1, HexC), + WTWOP( "cmp.w",Hex1,HexD), + UNOP( "daa",Hex0, HexF), + UNOP( "das",Hex1, HexF), + UNOP( "dec",Hex1, HexA), + SOP("divxu"),{RS8, RD16|B30, E}, { Hex5, Hex1, RS8, RD16|B30, E} EOP, + SOP("eepmov"),{ E}, {Hex7, HexB, Hex5, HexC, Hex5, Hex9, Hex8, HexF,E} EOP, + UNOP( "inc", Hex0, HexA), + SOP("jmp"),{RSIND|B30, E}, {Hex5, Hex9, RSIND|B30, Hex0, E} EOP, + SOP("jmp"),{ABS16ORREL8SRC, E}, {Hex5, HexA, Hex0, Hex0, ABS16ORREL8SRC, IGNORE,IGNORE,IGNORE,E} EOP, + SOP("jmp"),{MEMIND, E}, {Hex5, HexB, MEMIND,IGNORE, E} EOP, + SOP("jsr"),{RSIND|B30, E}, {Hex5, HexD, RSIND|B30, Hex0, E} EOP, + SOP("jsr"),{ABS16ORREL8SRC, E}, {Hex5, HexE, Hex0, Hex0, + ABS16ORREL8SRC,IGNORE,IGNORE,IGNORE, E} EOP, + SOP("jsr"),{MEMIND, E}, {Hex5, HexF, MEMIND, IGNORE,E} EOP, + SOP("ldc"),{IMM8, CCR, E}, { Hex0, Hex7, IMM8,IGNORE, E} EOP, + SOP("ldc"),{RS8, CCR, E}, { Hex0, Hex3, Hex0, RS8, E} EOP, + SOP("mov.b"),{RS8, RD8, E}, { Hex0, HexC, RS8, RD8, E} EOP, + SOP("mov.b"),{IMM8, RD8, E}, { HexF, RD8, IMM8,IGNORE, E} EOP, + SOP("mov.b"),{RSIND|B30,RD8, E}, { Hex6, Hex8, RSIND|B30, RD8, E} EOP, + SOP("mov.b"),{DISPSRC,RD8, E}, { Hex6, HexE, DISPREG|B30, RD8, + DISPSRC, IGNORE, IGNORE, IGNORE, E} EOP, + SOP("mov.b"),{RSINC|B30, RD8, E}, { Hex6, HexC, RSINC|B30, RD8, E} EOP, + SOP("mov.b"),{ABS16OR8SRC, RD8, E}, { Hex6, HexA, Hex0, RD8,ABS16OR8SRC, + IGNORE,IGNORE,IGNORE,E} EOP, + SOP("mov.b"),{ABS8SRC, RD8, E}, { Hex2, RD8, ABS8SRC,IGNORE, E} EOP, + SOP("mov.b"),{RS8, RDIND|B30, E}, { Hex6, Hex8, RDIND|B31, RS8, E} EOP, + SOP("mov.b"),{RS8, DISPDST, E}, { Hex6, HexE, DISPREG|B31, + RS8,DISPDST, IGNORE, IGNORE, IGNORE, E} EOP, + SOP("mov.b"),{RS8, RDDEC|B31, E}, { Hex6, HexC, RDDEC|B31, RS8, E} EOP, + SOP( "mov.b"),{RS8, ABS16OR8DST, E}, { Hex6, HexA, Hex8, RS8, + ABS16OR8DST,IGNORE,IGNORE,IGNORE, E} EOP, + SOP( "mov.b"),{RS8, ABS8DST, E}, { Hex3, RS8, ABS8DST,IGNORE, E} EOP, + SOP( "mov.w"),{RS16|B30, RD16|B30, E},{ Hex0, HexD, RS16|B30, + RD16|B30, E} EOP, + SOP("mov.w"),{IMM16, RD16|B30, E}, { Hex7, Hex9, Hex0, RD16|B30, + IMM16,IGNORE,IGNORE,IGNORE, E} EOP, + SOP("mov.w"),{RSIND|B30,RD16|B30, E},{ Hex6, Hex9, RSIND|B30, + RD16|B30, E} EOP, + SOP("mov.w"),{DISPSRC,RD16|B30, E}, { Hex6, HexF, DISPREG|B30, + RD16|B30, DISPSRC, IGNORE, IGNORE, IGNORE,E} EOP, + SOP("mov.w"),{RSINC|B30, RD16|B30, E}, { Hex6, HexD, RSINC|B30, + RD16|B30, E}EOP, + SOP("mov.w"), {ABS16SRC, RD16|B30, E}, { Hex6, HexB, Hex0, + RD16|B30,ABS16SRC,IGNORE,IGNORE,IGNORE, E} EOP, +SOP("mov.w"), {RS16|B30, RDIND|B30, E},{ Hex6, Hex9, RDIND|B31, + RS16|B30, E} EOP, +SOP("mov.w"), {RS16|B30, DISPDST, E}, { Hex6, HexF, DISPREG|B31, + RS16|B30,DISPDST, IGNORE,IGNORE,IGNORE,E} EOP, +SOP("mov.w"), {RS16|B30, RDDEC|B30, E},{ Hex6, HexD, RDDEC|B31, + RS16|B30, E} EOP, +SOP("mov.w"), {RS16|B30, ABS16DST, E}, { Hex6, HexB, Hex8, RS16|B30, + ABS16DST, IGNORE, IGNORE, IGNORE, E} EOP, +SOP("movfpe"), {ABS16SRC, RD8, E}, { Hex6, HexA, Hex4, RD8, + ABS16SRC,IGNORE,IGNORE,IGNORE, E} EOP, +SOP("movtpe"), {RS8, ABS16DST, E}, { Hex6, HexA, HexC, RS8, + ABS16DST,IGNORE,IGNORE,IGNORE, + E} EOP, +SOP("mulxu"), {RS8, RD16|B30, E}, { Hex5, Hex0, RS8, RD16|B30, E} EOP, +SOP( "neg"), {RS8, E}, { Hex1, Hex7, Hex8, RS8, E} EOP, +SOP( "nop"), {E}, { Hex0, Hex0, Hex0, Hex0,E} EOP, +SOP( "not"), {RS8,E}, { Hex1, Hex7, Hex0, RS8,E} EOP, +TWOOP("or", HexC, Hex1, Hex4), +SOP( "orc"), {IMM8, CCR,E}, { Hex0, Hex4, IMM8,IGNORE,E} EOP, +SOP( "pop"), {RS16|B30,E}, { Hex6, HexD, Hex7, RS16|B30,E} EOP, +SOP( "push"), {RS16|B30,E}, { Hex6, HexD, HexF, RS16|B30,E} EOP, + UNOP3( "rotl",Hex1, Hex2,Hex8), + UNOP3( "rotr",Hex1, Hex3, Hex8), + UNOP3( "rotxl",Hex1, Hex2, Hex0), + UNOP3( "rotxr",Hex1, Hex3, Hex0), +SOP("rte"), {E}, { Hex5, Hex6, Hex7, Hex0,E} EOP, +SOP("rts"), {E}, { Hex5, Hex4, Hex7, Hex0,E} EOP, + UNOP3( "shal", Hex1, Hex0, Hex8), + UNOP3( "shar", Hex1, Hex1, Hex8), + UNOP3( "shll", Hex1, Hex0, Hex0), + UNOP3( "shlr", Hex1, Hex1, Hex0), +SOP("sleep"), {E}, { Hex0, Hex1, Hex8, Hex0,E} EOP, +SOP("stc"), {CCR, RD8,E}, { Hex0, Hex2, Hex0, RD8,E} EOP, +SOP("sub.b"), {RS8,RD8,E}, { Hex1, Hex8, RS8, RD8,E} EOP, +SOP("sub.w"), {RS16|B30, RD16|B30,E}, {Hex1, Hex9, RS16|B30,RD16|B30,E} EOP, +SOP("subs"), {KBIT,RD16|B30,E}, { Hex1, HexB, KBIT, RD16|B30,E} EOP, + TWOOP("subx",HexB, Hex1, HexE), + TWOOP("xor", HexD, Hex1, Hex5), +SOP("xorc"), {IMM8, CCR,E}, { Hex0, Hex5, IMM8,IGNORE,E} EOP, + 0 +}; +#else +extern struct h8_opcode h8_opcodes[] ; +#endif + + + + diff --git a/gnu/usr.bin/as/opcode/i386.h b/gnu/usr.bin/as/opcode/i386.h new file mode 100644 index 000000000000..089ffdcf38dc --- /dev/null +++ b/gnu/usr.bin/as/opcode/i386.h @@ -0,0 +1,830 @@ +/* i386-opcode.h -- Intel 80386 opcode table + Copyright (C) 1989, 1991, Free Software Foundation. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id: i386.h,v 1.1 1993/11/03 00:55:51 paul Exp $ */ + +static const 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, Imm16|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 }, + +#if 0 +{"inb", 1, 0xe4, _, NoModrm, Imm8, 0, 0 }, +{"inb", 1, 0xec, _, NoModrm, WordMem, 0, 0 }, +{"inw", 1, 0x66e5, _, NoModrm, Imm8, 0, 0 }, +{"inw", 1, 0x66ed, _, NoModrm, WordMem, 0, 0 }, +{"outb", 1, 0xe6, _, NoModrm, Imm8, 0, 0 }, +{"outb", 1, 0xee, _, NoModrm, WordMem, 0, 0 }, +{"outw", 1, 0x66e7, _, NoModrm, Imm8, 0, 0 }, +{"outw", 1, 0x66ef, _, NoModrm, WordMem, 0, 0 }, +#endif + +/* load effective address */ +{"lea", 2, 0x8d, _, Modrm, WordMem, WordReg, 0 }, + +/* load segment registers from memory */ +{"lds", 2, 0xc5, _, Modrm, Mem, Reg32, 0}, +{"les", 2, 0xc4, _, Modrm, Mem, Reg32, 0}, +{"lfs", 2, 0x0fb4, _, Modrm, Mem, Reg32, 0}, +{"lgs", 2, 0x0fb5, _, Modrm, Mem, Reg32, 0}, +{"lss", 2, 0x0fb2, _, Modrm, Mem, Reg32, 0}, + +/* flags register instructions */ +{"clc", 0, 0xf8, _, NoModrm, 0, 0, 0}, +{"cld", 0, 0xfc, _, NoModrm, 0, 0, 0}, +{"cli", 0, 0xfa, _, NoModrm, 0, 0, 0}, +{"clts", 0, 0x0f06, _, NoModrm, 0, 0, 0}, +{"cmc", 0, 0xf5, _, NoModrm, 0, 0, 0}, +{"lahf", 0, 0x9f, _, NoModrm, 0, 0, 0}, +{"sahf", 0, 0x9e, _, NoModrm, 0, 0, 0}, +{"pushf", 0, 0x9c, _, NoModrm, 0, 0, 0}, +{"popf", 0, 0x9d, _, NoModrm, 0, 0, 0}, +{"stc", 0, 0xf9, _, NoModrm, 0, 0, 0}, +{"std", 0, 0xfd, _, NoModrm, 0, 0, 0}, +{"sti", 0, 0xfb, _, NoModrm, 0, 0, 0}, + +{"add", 2, 0x0, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"add", 2, 0x83, 0, Modrm, Imm8S, WordReg|WordMem, 0}, +{"add", 2, 0x4, _, W|NoModrm, Imm, Acc, 0}, +{"add", 2, 0x80, 0, W|Modrm, Imm, Reg|Mem, 0}, + +{"inc", 1, 0x40, _, ShortForm, WordReg, 0, 0}, +{"inc", 1, 0xfe, 0, W|Modrm, Reg|Mem, 0, 0}, + +{"sub", 2, 0x28, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"sub", 2, 0x83, 5, Modrm, Imm8S, WordReg|WordMem, 0}, +{"sub", 2, 0x2c, _, W|NoModrm, Imm, Acc, 0}, +{"sub", 2, 0x80, 5, W|Modrm, Imm, Reg|Mem, 0}, + +{"dec", 1, 0x48, _, ShortForm, WordReg, 0, 0}, +{"dec", 1, 0xfe, 1, W|Modrm, Reg|Mem, 0, 0}, + +{"sbb", 2, 0x18, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"sbb", 2, 0x83, 3, Modrm, Imm8S, WordReg|WordMem, 0}, +{"sbb", 2, 0x1c, _, W|NoModrm, Imm, Acc, 0}, +{"sbb", 2, 0x80, 3, W|Modrm, Imm, Reg|Mem, 0}, + +{"cmp", 2, 0x38, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"cmp", 2, 0x83, 7, Modrm, Imm8S, WordReg|WordMem, 0}, +{"cmp", 2, 0x3c, _, W|NoModrm, Imm, Acc, 0}, +{"cmp", 2, 0x80, 7, W|Modrm, Imm, Reg|Mem, 0}, + +{"test", 2, 0x84, _, W|Modrm, Reg|Mem, Reg, 0}, +{"test", 2, 0x84, _, W|Modrm, Reg, Reg|Mem, 0}, +{"test", 2, 0xa8, _, W|NoModrm, Imm, Acc, 0}, +{"test", 2, 0xf6, 0, W|Modrm, Imm, Reg|Mem, 0}, + +{"and", 2, 0x20, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"and", 2, 0x83, 4, Modrm, Imm8S, WordReg|WordMem, 0}, +{"and", 2, 0x24, _, W|NoModrm, Imm, Acc, 0}, +{"and", 2, 0x80, 4, W|Modrm, Imm, Reg|Mem, 0}, + +{"or", 2, 0x08, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"or", 2, 0x83, 1, Modrm, Imm8S, WordReg|WordMem, 0}, +{"or", 2, 0x0c, _, W|NoModrm, Imm, Acc, 0}, +{"or", 2, 0x80, 1, W|Modrm, Imm, Reg|Mem, 0}, + +{"xor", 2, 0x30, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"xor", 2, 0x83, 6, Modrm, Imm8S, WordReg|WordMem, 0}, +{"xor", 2, 0x34, _, W|NoModrm, Imm, Acc, 0}, +{"xor", 2, 0x80, 6, W|Modrm, Imm, Reg|Mem, 0}, + +{"adc", 2, 0x10, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"adc", 2, 0x83, 2, Modrm, Imm8S, WordReg|WordMem, 0}, +{"adc", 2, 0x14, _, W|NoModrm, Imm, Acc, 0}, +{"adc", 2, 0x80, 2, W|Modrm, Imm, Reg|Mem, 0}, + +{"neg", 1, 0xf6, 3, W|Modrm, Reg|Mem, 0, 0}, +{"not", 1, 0xf6, 2, W|Modrm, Reg|Mem, 0, 0}, + +{"aaa", 0, 0x37, _, NoModrm, 0, 0, 0}, +{"aas", 0, 0x3f, _, NoModrm, 0, 0, 0}, +{"daa", 0, 0x27, _, NoModrm, 0, 0, 0}, +{"das", 0, 0x2f, _, NoModrm, 0, 0, 0}, +{"aad", 0, 0xd50a, _, NoModrm, 0, 0, 0}, +{"aam", 0, 0xd40a, _, NoModrm, 0, 0, 0}, + +/* conversion insns */ +/* conversion: intel naming */ +{"cbw", 0, 0x6698, _, NoModrm, 0, 0, 0}, +{"cwd", 0, 0x6699, _, NoModrm, 0, 0, 0}, +{"cwde", 0, 0x98, _, NoModrm, 0, 0, 0}, +{"cdq", 0, 0x99, _, NoModrm, 0, 0, 0}, +/* att naming */ +{"cbtw", 0, 0x6698, _, NoModrm, 0, 0, 0}, +{"cwtl", 0, 0x98, _, NoModrm, 0, 0, 0}, +{"cwtd", 0, 0x6699, _, NoModrm, 0, 0, 0}, +{"cltd", 0, 0x99, _, NoModrm, 0, 0, 0}, + +/* Warning! the mul/imul (opcode 0xf6) must only have 1 operand! They are + expanding 64-bit multiplies, and *cannot* be selected to accomplish + 'imul %ebx, %eax' (opcode 0x0faf must be used in this case) + These multiplies can only be selected with single opearnd forms. */ +{"mul", 1, 0xf6, 4, W|Modrm, Reg|Mem, 0, 0}, +{"imul", 1, 0xf6, 5, W|Modrm, Reg|Mem, 0, 0}, + + + + +/* imulKludge here is needed to reverse the i.rm.reg & i.rm.regmem fields. + These instructions are exceptions: 'imul $2, %eax, %ecx' would put + '%eax' in the reg field and '%ecx' in the regmem field if we did not + switch them. */ +{"imul", 2, 0x0faf, _, Modrm|ReverseRegRegmem, WordReg|Mem, WordReg, 0}, +{"imul", 3, 0x6b, _, Modrm|ReverseRegRegmem, Imm8S, WordReg|Mem, WordReg}, +{"imul", 3, 0x69, _, Modrm|ReverseRegRegmem, Imm16|Imm32, WordReg|Mem, WordReg}, +/* + imul with 2 operands mimicks imul with 3 by puting register both + in i.rm.reg & i.rm.regmem fields +*/ +{"imul", 2, 0x6b, _, Modrm|imulKludge, Imm8S, WordReg, 0}, +{"imul", 2, 0x69, _, Modrm|imulKludge, Imm16|Imm32, WordReg, 0}, +{"div", 1, 0xf6, 6, W|Modrm, Reg|Mem, 0, 0}, +{"div", 2, 0xf6, 6, W|Modrm, Reg|Mem, Acc, 0}, +{"idiv", 1, 0xf6, 7, W|Modrm, Reg|Mem, 0, 0}, +{"idiv", 2, 0xf6, 7, W|Modrm, Reg|Mem, Acc, 0}, + +{"rol", 2, 0xd0, 0, W|Modrm, Imm1, Reg|Mem, 0}, +{"rol", 2, 0xc0, 0, W|Modrm, Imm8, Reg|Mem, 0}, +{"rol", 2, 0xd2, 0, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"rol", 1, 0xd0, 0, W|Modrm, Reg|Mem, 0, 0}, + +{"ror", 2, 0xd0, 1, W|Modrm, Imm1, Reg|Mem, 0}, +{"ror", 2, 0xc0, 1, W|Modrm, Imm8, Reg|Mem, 0}, +{"ror", 2, 0xd2, 1, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"ror", 1, 0xd0, 1, W|Modrm, Reg|Mem, 0, 0}, + +{"rcl", 2, 0xd0, 2, W|Modrm, Imm1, Reg|Mem, 0}, +{"rcl", 2, 0xc0, 2, W|Modrm, Imm8, Reg|Mem, 0}, +{"rcl", 2, 0xd2, 2, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"rcl", 1, 0xd0, 2, W|Modrm, Reg|Mem, 0, 0}, + +{"rcr", 2, 0xd0, 3, W|Modrm, Imm1, Reg|Mem, 0}, +{"rcr", 2, 0xc0, 3, W|Modrm, Imm8, Reg|Mem, 0}, +{"rcr", 2, 0xd2, 3, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"rcr", 1, 0xd0, 3, W|Modrm, Reg|Mem, 0, 0}, + +{"sal", 2, 0xd0, 4, W|Modrm, Imm1, Reg|Mem, 0}, +{"sal", 2, 0xc0, 4, W|Modrm, Imm8, Reg|Mem, 0}, +{"sal", 2, 0xd2, 4, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"sal", 1, 0xd0, 4, W|Modrm, Reg|Mem, 0, 0}, +{"shl", 2, 0xd0, 4, W|Modrm, Imm1, Reg|Mem, 0}, +{"shl", 2, 0xc0, 4, W|Modrm, Imm8, Reg|Mem, 0}, +{"shl", 2, 0xd2, 4, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"shl", 1, 0xd0, 4, W|Modrm, Reg|Mem, 0, 0}, + +{"shld", 3, 0x0fa4, _, Modrm, Imm8, WordReg, WordReg|Mem}, +{"shld", 3, 0x0fa5, _, Modrm, ShiftCount, WordReg, WordReg|Mem}, + +{"shr", 2, 0xd0, 5, W|Modrm, Imm1, Reg|Mem, 0}, +{"shr", 2, 0xc0, 5, W|Modrm, Imm8, Reg|Mem, 0}, +{"shr", 2, 0xd2, 5, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"shr", 1, 0xd0, 5, W|Modrm, Reg|Mem, 0, 0}, + +{"shrd", 3, 0x0fac, _, Modrm, Imm8, WordReg, WordReg|Mem}, +{"shrd", 3, 0x0fad, _, Modrm, ShiftCount, WordReg, WordReg|Mem}, + +{"sar", 2, 0xd0, 7, W|Modrm, Imm1, Reg|Mem, 0}, +{"sar", 2, 0xc0, 7, W|Modrm, Imm8, Reg|Mem, 0}, +{"sar", 2, 0xd2, 7, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"sar", 1, 0xd0, 7, W|Modrm, Reg|Mem, 0, 0}, + +/* control transfer instructions */ +#define CALL_PC_RELATIVE 0xe8 +{"call", 1, 0xe8, _, JumpDword, Disp32, 0, 0}, +{"call", 1, 0xff, 2, Modrm, Reg|Mem|JumpAbsolute, 0, 0}, +#define CALL_FAR_IMMEDIATE 0x9a +{"lcall", 2, 0x9a, _, JumpInterSegment, Imm16, Abs32, 0}, +{"lcall", 1, 0xff, 3, Modrm, Mem, 0, 0}, + +#define JUMP_PC_RELATIVE 0xeb +{"jmp", 1, 0xeb, _, Jump, Disp, 0, 0}, +{"jmp", 1, 0xff, 4, Modrm, Reg32|Mem|JumpAbsolute, 0, 0}, +#define JUMP_FAR_IMMEDIATE 0xea +{"ljmp", 2, 0xea, _, JumpInterSegment, Imm16, Imm32, 0}, +{"ljmp", 1, 0xff, 5, Modrm, Mem, 0, 0}, + +{"ret", 0, 0xc3, _, NoModrm, 0, 0, 0}, +{"ret", 1, 0xc2, _, NoModrm, Imm16, 0, 0}, +{"lret", 0, 0xcb, _, NoModrm, 0, 0, 0}, +{"lret", 1, 0xca, _, NoModrm, Imm16, 0, 0}, +{"enter", 2, 0xc8, _, NoModrm, Imm16, Imm8, 0}, +{"leave", 0, 0xc9, _, NoModrm, 0, 0, 0}, + +/* conditional jumps */ +{"jo", 1, 0x70, _, Jump, Disp, 0, 0}, + +{"jno", 1, 0x71, _, Jump, Disp, 0, 0}, + +{"jb", 1, 0x72, _, Jump, Disp, 0, 0}, +{"jc", 1, 0x72, _, Jump, Disp, 0, 0}, +{"jnae", 1, 0x72, _, Jump, Disp, 0, 0}, + +{"jnb", 1, 0x73, _, Jump, Disp, 0, 0}, +{"jnc", 1, 0x73, _, Jump, Disp, 0, 0}, +{"jae", 1, 0x73, _, Jump, Disp, 0, 0}, + +{"je", 1, 0x74, _, Jump, Disp, 0, 0}, +{"jz", 1, 0x74, _, Jump, Disp, 0, 0}, + +{"jne", 1, 0x75, _, Jump, Disp, 0, 0}, +{"jnz", 1, 0x75, _, Jump, Disp, 0, 0}, + +{"jbe", 1, 0x76, _, Jump, Disp, 0, 0}, +{"jna", 1, 0x76, _, Jump, Disp, 0, 0}, + +{"jnbe", 1, 0x77, _, Jump, Disp, 0, 0}, +{"ja", 1, 0x77, _, Jump, Disp, 0, 0}, + +{"js", 1, 0x78, _, Jump, Disp, 0, 0}, + +{"jns", 1, 0x79, _, Jump, Disp, 0, 0}, + +{"jp", 1, 0x7a, _, Jump, Disp, 0, 0}, +{"jpe", 1, 0x7a, _, Jump, Disp, 0, 0}, + +{"jnp", 1, 0x7b, _, Jump, Disp, 0, 0}, +{"jpo", 1, 0x7b, _, Jump, Disp, 0, 0}, + +{"jl", 1, 0x7c, _, Jump, Disp, 0, 0}, +{"jnge", 1, 0x7c, _, Jump, Disp, 0, 0}, + +{"jnl", 1, 0x7d, _, Jump, Disp, 0, 0}, +{"jge", 1, 0x7d, _, Jump, Disp, 0, 0}, + +{"jle", 1, 0x7e, _, Jump, Disp, 0, 0}, +{"jng", 1, 0x7e, _, Jump, Disp, 0, 0}, + +{"jnle", 1, 0x7f, _, Jump, Disp, 0, 0}, +{"jg", 1, 0x7f, _, Jump, Disp, 0, 0}, + +/* these turn into pseudo operations when disp is larger than 8 bits */ +#define IS_JUMP_ON_CX_ZERO(o) \ + (o == 0x67e3) +#define IS_JUMP_ON_ECX_ZERO(o) \ + (o == 0xe3) + +{"jcxz", 1, 0x67e3, _, JumpByte, Disp, 0, 0}, +{"jecxz", 1, 0xe3, _, JumpByte, Disp, 0, 0}, + +#define IS_LOOP_ECX_TIMES(o) \ + (o == 0xe2 || o == 0xe1 || o == 0xe0) + +{"loop", 1, 0xe2, _, JumpByte, Disp, 0, 0}, + +{"loopz", 1, 0xe1, _, JumpByte, Disp, 0, 0}, +{"loope", 1, 0xe1, _, JumpByte, Disp, 0, 0}, + +{"loopnz", 1, 0xe0, _, JumpByte, Disp, 0, 0}, +{"loopne", 1, 0xe0, _, JumpByte, Disp, 0, 0}, + +/* set byte on flag instructions */ +{"seto", 1, 0x0f90, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setno", 1, 0x0f91, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setc", 1, 0x0f92, 0, Modrm, Reg8|Mem, 0, 0}, +{"setb", 1, 0x0f92, 0, Modrm, Reg8|Mem, 0, 0}, +{"setnae", 1, 0x0f92, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setnc", 1, 0x0f93, 0, Modrm, Reg8|Mem, 0, 0}, +{"setnb", 1, 0x0f93, 0, Modrm, Reg8|Mem, 0, 0}, +{"setae", 1, 0x0f93, 0, Modrm, Reg8|Mem, 0, 0}, + +{"sete", 1, 0x0f94, 0, Modrm, Reg8|Mem, 0, 0}, +{"setz", 1, 0x0f94, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setne", 1, 0x0f95, 0, Modrm, Reg8|Mem, 0, 0}, +{"setnz", 1, 0x0f95, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setbe", 1, 0x0f96, 0, Modrm, Reg8|Mem, 0, 0}, +{"setna", 1, 0x0f96, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setnbe", 1, 0x0f97, 0, Modrm, Reg8|Mem, 0, 0}, +{"seta", 1, 0x0f97, 0, Modrm, Reg8|Mem, 0, 0}, + +{"sets", 1, 0x0f98, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setns", 1, 0x0f99, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setp", 1, 0x0f9a, 0, Modrm, Reg8|Mem, 0, 0}, +{"setpe", 1, 0x0f9a, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setnp", 1, 0x0f9b, 0, Modrm, Reg8|Mem, 0, 0}, +{"setpo", 1, 0x0f9b, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setl", 1, 0x0f9c, 0, Modrm, Reg8|Mem, 0, 0}, +{"setnge", 1, 0x0f9c, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setnl", 1, 0x0f9d, 0, Modrm, Reg8|Mem, 0, 0}, +{"setge", 1, 0x0f9d, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setle", 1, 0x0f9e, 0, Modrm, Reg8|Mem, 0, 0}, +{"setng", 1, 0x0f9e, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setnle", 1, 0x0f9f, 0, Modrm, Reg8|Mem, 0, 0}, +{"setg", 1, 0x0f9f, 0, Modrm, Reg8|Mem, 0, 0}, + +#define IS_STRING_INSTRUCTION(o) \ + ((o) == 0xa6 || (o) == 0x6c || (o) == 0x6e || (o) == 0x6e || \ + (o) == 0xac || (o) == 0xa4 || (o) == 0xae || (o) == 0xaa || \ + (o) == 0xd7) + +/* string manipulation */ +{"cmps", 0, 0xa6, _, W|NoModrm, 0, 0, 0}, +{"scmp", 0, 0xa6, _, W|NoModrm, 0, 0, 0}, +{"ins", 0, 0x6c, _, W|NoModrm, 0, 0, 0}, +{"outs", 0, 0x6e, _, W|NoModrm, 0, 0, 0}, +{"lods", 0, 0xac, _, W|NoModrm, 0, 0, 0}, +{"slod", 0, 0xac, _, W|NoModrm, 0, 0, 0}, +{"movs", 0, 0xa4, _, W|NoModrm, 0, 0, 0}, +{"smov", 0, 0xa4, _, W|NoModrm, 0, 0, 0}, +{"scas", 0, 0xae, _, W|NoModrm, 0, 0, 0}, +{"ssca", 0, 0xae, _, W|NoModrm, 0, 0, 0}, +{"stos", 0, 0xaa, _, W|NoModrm, 0, 0, 0}, +{"ssto", 0, 0xaa, _, W|NoModrm, 0, 0, 0}, +{"xlat", 0, 0xd7, _, NoModrm, 0, 0, 0}, + +/* bit manipulation */ +{"bsf", 2, 0x0fbc, _, Modrm|ReverseRegRegmem, Reg|Mem, Reg, 0}, +{"bsr", 2, 0x0fbd, _, Modrm|ReverseRegRegmem, Reg|Mem, Reg, 0}, +{"bt", 2, 0x0fa3, _, Modrm, Reg, Reg|Mem, 0}, +{"bt", 2, 0x0fba, 4, Modrm, Imm8, Reg|Mem, 0}, +{"btc", 2, 0x0fbb, _, Modrm, Reg, Reg|Mem, 0}, +{"btc", 2, 0x0fba, 7, Modrm, Imm8, Reg|Mem, 0}, +{"btr", 2, 0x0fb3, _, Modrm, Reg, Reg|Mem, 0}, +{"btr", 2, 0x0fba, 6, Modrm, Imm8, Reg|Mem, 0}, +{"bts", 2, 0x0fab, _, Modrm, Reg, Reg|Mem, 0}, +{"bts", 2, 0x0fba, 5, Modrm, Imm8, Reg|Mem, 0}, + +/* interrupts & op. sys insns */ +/* See i386.c for conversion of 'int $3' into the special int 3 insn. */ +#define INT_OPCODE 0xcd +#define INT3_OPCODE 0xcc +{"int", 1, 0xcd, _, NoModrm, Imm8, 0, 0}, +{"int3", 0, 0xcc, _, NoModrm, 0, 0, 0}, +{"into", 0, 0xce, _, NoModrm, 0, 0, 0}, +{"iret", 0, 0xcf, _, NoModrm, 0, 0, 0}, + +{"boundl", 2, 0x62, _, Modrm, Reg32, Mem, 0}, +{"boundw", 2, 0x6662, _, Modrm, Reg16, Mem, 0}, + +{"hlt", 0, 0xf4, _, NoModrm, 0, 0, 0}, +{"wait", 0, 0x9b, _, NoModrm, 0, 0, 0}, +/* nop is actually 'xchgl %eax, %eax' */ +{"nop", 0, 0x90, _, NoModrm, 0, 0, 0}, + +/* protection control */ +{"arpl", 2, 0x63, _, Modrm, Reg16, Reg16|Mem, 0}, +{"lar", 2, 0x0f02, _, Modrm|ReverseRegRegmem, WordReg|Mem, WordReg, 0}, +{"lgdt", 1, 0x0f01, 2, Modrm, Mem, 0, 0}, +{"lidt", 1, 0x0f01, 3, Modrm, Mem, 0, 0}, +{"lldt", 1, 0x0f00, 2, Modrm, WordReg|Mem, 0, 0}, +{"lmsw", 1, 0x0f01, 6, Modrm, WordReg|Mem, 0, 0}, +{"lsl", 2, 0x0f03, _, Modrm|ReverseRegRegmem, WordReg|Mem, WordReg, 0}, +{"ltr", 1, 0x0f00, 3, Modrm, WordReg|Mem, 0, 0}, + +{"sgdt", 1, 0x0f01, 0, Modrm, Mem, 0, 0}, +{"sidt", 1, 0x0f01, 1, Modrm, Mem, 0, 0}, +{"sldt", 1, 0x0f00, 0, Modrm, WordReg|Mem, 0, 0}, +{"smsw", 1, 0x0f01, 4, Modrm, WordReg|Mem, 0, 0}, +{"str", 1, 0x0f00, 1, Modrm, Reg16|Mem, 0, 0}, + +{"verr", 1, 0x0f00, 4, Modrm, WordReg|Mem, 0, 0}, +{"verw", 1, 0x0f00, 5, Modrm, WordReg|Mem, 0, 0}, + +/* floating point instructions */ + +/* load */ +{"fld", 1, 0xd9c0, _, ShortForm, FloatReg, 0, 0}, /* register */ +{"flds", 1, 0xd9, 0, Modrm, Mem, 0, 0}, /* %st0 <-- mem float */ +{"fildl", 1, 0xdb, 0, Modrm, Mem, 0, 0}, /* %st0 <-- mem word */ +{"fldl", 1, 0xdd, 0, Modrm, Mem, 0, 0}, /* %st0 <-- mem double */ +{"fldl", 1, 0xd9c0, _, ShortForm, FloatReg, 0, 0}, /* register */ +{"filds", 1, 0xdf, 0, Modrm, Mem, 0, 0}, /* %st0 <-- mem dword */ +{"fildq", 1, 0xdf, 5, Modrm, Mem, 0, 0}, /* %st0 <-- mem qword */ +{"fldt", 1, 0xdb, 5, Modrm, Mem, 0, 0}, /* %st0 <-- mem efloat */ +{"fbld", 1, 0xdf, 4, Modrm, Mem, 0, 0}, /* %st0 <-- mem bcd */ + +/* store (no pop) */ +{"fst", 1, 0xddd0, _, ShortForm, FloatReg, 0, 0}, /* register */ +{"fsts", 1, 0xd9, 2, Modrm, Mem, 0, 0}, /* %st0 --> mem float */ +{"fistl", 1, 0xdb, 2, Modrm, Mem, 0, 0}, /* %st0 --> mem dword */ +{"fstl", 1, 0xdd, 2, Modrm, Mem, 0, 0}, /* %st0 --> mem double */ +{"fstl", 1, 0xddd0, _, ShortForm, FloatReg, 0, 0}, /* register */ +{"fists", 1, 0xdf, 2, Modrm, Mem, 0, 0}, /* %st0 --> mem word */ + +/* store (with pop) */ +{"fstp", 1, 0xddd8, _, ShortForm, FloatReg, 0, 0}, /* register */ +{"fstps", 1, 0xd9, 3, Modrm, Mem, 0, 0}, /* %st0 --> mem float */ +{"fistpl", 1, 0xdb, 3, Modrm, Mem, 0, 0}, /* %st0 --> mem word */ +{"fstpl", 1, 0xdd, 3, Modrm, Mem, 0, 0}, /* %st0 --> mem double */ +{"fstpl", 1, 0xddd8, _, ShortForm, FloatReg, 0, 0}, /* register */ +{"fistps", 1, 0xdf, 3, Modrm, Mem, 0, 0}, /* %st0 --> mem dword */ +{"fistpq", 1, 0xdf, 7, Modrm, Mem, 0, 0}, /* %st0 --> mem qword */ +{"fstpt", 1, 0xdb, 7, Modrm, Mem, 0, 0}, /* %st0 --> mem efloat */ +{"fbstp", 1, 0xdf, 6, Modrm, Mem, 0, 0}, /* %st0 --> mem bcd */ + +/* exchange %st<n> with %st0 */ +{"fxch", 1, 0xd9c8, _, ShortForm, FloatReg, 0, 0}, + +/* comparison (without pop) */ +{"fcom", 1, 0xd8d0, _, ShortForm, FloatReg, 0, 0}, +{"fcoms", 1, 0xd8, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem float */ +{"ficoml", 1, 0xda, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem word */ +{"fcoml", 1, 0xdc, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem double */ +{"fcoml", 1, 0xd8d0, _, ShortForm, FloatReg, 0, 0}, +{"ficoms", 1, 0xde, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem dword */ + +/* comparison (with pop) */ +{"fcomp", 1, 0xd8d8, _, ShortForm, FloatReg, 0, 0}, +{"fcomps", 1, 0xd8, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem float */ +{"ficompl", 1, 0xda, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem word */ +{"fcompl", 1, 0xdc, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem double */ +{"fcompl", 1, 0xd8d8, _, ShortForm, FloatReg, 0, 0}, +{"ficomps", 1, 0xde, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem dword */ +{"fcompp", 0, 0xded9, _, NoModrm, 0, 0, 0}, /* compare %st0, %st1 & pop twice */ + +/* unordered comparison (with pop) */ +{"fucom", 1, 0xdde0, _, ShortForm, FloatReg, 0, 0}, +{"fucomp", 1, 0xdde8, _, ShortForm, FloatReg, 0, 0}, +{"fucompp", 0, 0xdae9, _, NoModrm, 0, 0, 0}, /* ucompare %st0, %st1 & pop twice */ + +{"ftst", 0, 0xd9e4, _, NoModrm, 0, 0, 0}, /* test %st0 */ +{"fxam", 0, 0xd9e5, _, NoModrm, 0, 0, 0}, /* examine %st0 */ + +/* load constants into %st0 */ +{"fld1", 0, 0xd9e8, _, NoModrm, 0, 0, 0}, /* %st0 <-- 1.0 */ +{"fldl2t", 0, 0xd9e9, _, NoModrm, 0, 0, 0}, /* %st0 <-- log2(10) */ +{"fldl2e", 0, 0xd9ea, _, NoModrm, 0, 0, 0}, /* %st0 <-- log2(e) */ +{"fldpi", 0, 0xd9eb, _, NoModrm, 0, 0, 0}, /* %st0 <-- pi */ +{"fldlg2", 0, 0xd9ec, _, NoModrm, 0, 0, 0}, /* %st0 <-- log10(2) */ +{"fldln2", 0, 0xd9ed, _, NoModrm, 0, 0, 0}, /* %st0 <-- ln(2) */ +{"fldz", 0, 0xd9ee, _, NoModrm, 0, 0, 0}, /* %st0 <-- 0.0 */ + +/* arithmetic */ + +/* add */ +{"fadd", 1, 0xd8c0, _, ShortForm, FloatReg, 0, 0}, +{"fadd", 2, 0xd8c0, _, ShortForm|FloatD, FloatReg, FloatAcc, 0}, +{"fadd", 0, 0xdcc1, _, NoModrm, 0, 0, 0}, /* alias for fadd %st, %st(1) */ +{"faddp", 1, 0xdec0, _, ShortForm, FloatReg, 0, 0}, +{"faddp", 2, 0xdac0, _, ShortForm|FloatD, FloatReg, FloatAcc, 0}, +{"faddp", 0, 0xdec1, _, NoModrm, 0, 0, 0}, /* alias for faddp %st, %st(1) */ +{"fadds", 1, 0xd8, 0, Modrm, Mem, 0, 0}, +{"fiaddl", 1, 0xda, 0, Modrm, Mem, 0, 0}, +{"faddl", 1, 0xdc, 0, Modrm, Mem, 0, 0}, +{"fiadds", 1, 0xde, 0, Modrm, Mem, 0, 0}, + +/* sub */ +/* Note: intel has decided that certain of these operations are reversed + in assembler syntax. */ +{"fsub", 1, 0xd8e0, _, ShortForm, FloatReg, 0, 0}, +{"fsub", 2, 0xd8e0, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fsub", 2, 0xdce8, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fsub", 2, 0xdce0, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fsub", 0, 0xdce1, _, NoModrm, 0, 0, 0}, +{"fsubp", 1, 0xdee0, _, ShortForm, FloatReg, 0, 0}, +{"fsubp", 2, 0xdee0, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fsubp", 2, 0xdee8, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fsubp", 2, 0xdee0, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fsubp", 0, 0xdee1, _, NoModrm, 0, 0, 0}, +{"fsubs", 1, 0xd8, 4, Modrm, Mem, 0, 0}, +{"fisubl", 1, 0xda, 4, Modrm, Mem, 0, 0}, +{"fsubl", 1, 0xdc, 4, Modrm, Mem, 0, 0}, +{"fisubs", 1, 0xde, 4, Modrm, Mem, 0, 0}, + +/* sub reverse */ +{"fsubr", 1, 0xd8e8, _, ShortForm, FloatReg, 0, 0}, +{"fsubr", 2, 0xd8e8, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fsubr", 2, 0xdce0, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fsubr", 2, 0xdce8, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fsubr", 0, 0xdce9, _, NoModrm, 0, 0, 0}, +{"fsubrp", 1, 0xdee8, _, ShortForm, FloatReg, 0, 0}, +{"fsubrp", 2, 0xdee8, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fsubrp", 2, 0xdee0, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fsubrp", 2, 0xdee8, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fsubrp", 0, 0xdee9, _, NoModrm, 0, 0, 0}, +{"fsubrs", 1, 0xd8, 5, Modrm, Mem, 0, 0}, +{"fisubrl", 1, 0xda, 5, Modrm, Mem, 0, 0}, +{"fsubrl", 1, 0xdc, 5, Modrm, Mem, 0, 0}, +{"fisubrs", 1, 0xde, 5, Modrm, Mem, 0, 0}, + +/* mul */ +{"fmul", 1, 0xd8c8, _, ShortForm, FloatReg, 0, 0}, +{"fmul", 2, 0xd8c8, _, ShortForm|FloatD, FloatReg, FloatAcc, 0}, +{"fmul", 0, 0xdcc9, _, NoModrm, 0, 0, 0}, +{"fmulp", 1, 0xdec8, _, ShortForm, FloatReg, 0, 0}, +{"fmulp", 2, 0xdec8, _, ShortForm|FloatD, FloatReg, FloatAcc, 0}, +{"fmulp", 0, 0xdec9, _, NoModrm, 0, 0, 0}, +{"fmuls", 1, 0xd8, 1, Modrm, Mem, 0, 0}, +{"fimull", 1, 0xda, 1, Modrm, Mem, 0, 0}, +{"fmull", 1, 0xdc, 1, Modrm, Mem, 0, 0}, +{"fimuls", 1, 0xde, 1, Modrm, Mem, 0, 0}, + +/* div */ +/* Note: intel has decided that certain of these operations are reversed + in assembler syntax. */ +{"fdiv", 1, 0xd8f0, _, ShortForm, FloatReg, 0, 0}, +{"fdiv", 2, 0xd8f0, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fdiv", 2, 0xdcf8, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fdiv", 2, 0xdcf0, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fdiv", 0, 0xdcf1, _, NoModrm, 0, 0, 0}, +{"fdivp", 1, 0xdef0, _, ShortForm, FloatReg, 0, 0}, +{"fdivp", 2, 0xdef0, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fdivp", 2, 0xdef8, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fdivp", 2, 0xdef0, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fdivp", 0, 0xdef1, _, NoModrm, 0, 0, 0}, +{"fdivs", 1, 0xd8, 6, Modrm, Mem, 0, 0}, +{"fidivl", 1, 0xda, 6, Modrm, Mem, 0, 0}, +{"fdivl", 1, 0xdc, 6, Modrm, Mem, 0, 0}, +{"fidivs", 1, 0xde, 6, Modrm, Mem, 0, 0}, + +/* div reverse */ +{"fdivr", 1, 0xd8f8, _, ShortForm, FloatReg, 0, 0}, +{"fdivr", 2, 0xd8f8, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fdivr", 2, 0xdcf0, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fdivr", 2, 0xdcf8, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fdivr", 0, 0xdcf9, _, NoModrm, 0, 0, 0}, +{"fdivrp", 1, 0xdef8, _, ShortForm, FloatReg, 0, 0}, +{"fdivrp", 2, 0xdef8, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fdivrp", 2, 0xdef0, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fdivrp", 2, 0xdef8, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fdivrp", 0, 0xdef9, _, NoModrm, 0, 0, 0}, +{"fdivrs", 1, 0xd8, 7, Modrm, Mem, 0, 0}, +{"fidivrl", 1, 0xda, 7, Modrm, Mem, 0, 0}, +{"fdivrl", 1, 0xdc, 7, Modrm, Mem, 0, 0}, +{"fidivrs", 1, 0xde, 7, Modrm, Mem, 0, 0}, + +{"f2xm1", 0, 0xd9f0, _, NoModrm, 0, 0, 0}, +{"fyl2x", 0, 0xd9f1, _, NoModrm, 0, 0, 0}, +{"fptan", 0, 0xd9f2, _, NoModrm, 0, 0, 0}, +{"fpatan", 0, 0xd9f3, _, NoModrm, 0, 0, 0}, +{"fxtract", 0, 0xd9f4, _, NoModrm, 0, 0, 0}, +{"fprem1", 0, 0xd9f5, _, NoModrm, 0, 0, 0}, +{"fdecstp", 0, 0xd9f6, _, NoModrm, 0, 0, 0}, +{"fincstp", 0, 0xd9f7, _, NoModrm, 0, 0, 0}, +{"fprem", 0, 0xd9f8, _, NoModrm, 0, 0, 0}, +{"fyl2xp1", 0, 0xd9f9, _, NoModrm, 0, 0, 0}, +{"fsqrt", 0, 0xd9fa, _, NoModrm, 0, 0, 0}, +{"fsincos", 0, 0xd9fb, _, NoModrm, 0, 0, 0}, +{"frndint", 0, 0xd9fc, _, NoModrm, 0, 0, 0}, +{"fscale", 0, 0xd9fd, _, NoModrm, 0, 0, 0}, +{"fsin", 0, 0xd9fe, _, NoModrm, 0, 0, 0}, +{"fcos", 0, 0xd9ff, _, NoModrm, 0, 0, 0}, + +{"fchs", 0, 0xd9e0, _, NoModrm, 0, 0, 0}, +{"fabs", 0, 0xd9e1, _, NoModrm, 0, 0, 0}, + +/* processor control */ +{"fninit", 0, 0xdbe3, _, NoModrm, 0, 0, 0}, +{"finit", 0, 0xdbe3, _, NoModrm, 0, 0, 0}, +{"fldcw", 1, 0xd9, 5, Modrm, Mem, 0, 0}, +{"fnstcw", 1, 0xd9, 7, Modrm, Mem, 0, 0}, +{"fstcw", 1, 0xd9, 7, Modrm, Mem, 0, 0}, +{"fnstsw", 1, 0xdfe0, _, NoModrm, Acc, 0, 0}, +{"fnstsw", 1, 0xdd, 7, Modrm, Mem, 0, 0}, +{"fnstsw", 0, 0xdfe0, _, NoModrm, 0, 0, 0}, +{"fstsw", 1, 0xdfe0, _, NoModrm, Acc, 0, 0}, +{"fstsw", 1, 0xdd, 7, Modrm, Mem, 0, 0}, +{"fstsw", 0, 0xdfe0, _, NoModrm, 0, 0, 0}, +{"fnclex", 0, 0xdbe2, _, NoModrm, 0, 0, 0}, +{"fclex", 0, 0xdbe2, _, NoModrm, 0, 0, 0}, +/* + We ignore the short format (287) versions of fstenv/fldenv & fsave/frstor + instructions; i'm not sure how to add them or how they are different. + My 386/387 book offers no details about this. +*/ +{"fnstenv", 1, 0xd9, 6, Modrm, Mem, 0, 0}, +{"fstenv", 1, 0xd9, 6, Modrm, Mem, 0, 0}, +{"fldenv", 1, 0xd9, 4, Modrm, Mem, 0, 0}, +{"fnsave", 1, 0xdd, 6, Modrm, Mem, 0, 0}, +{"fsave", 1, 0xdd, 6, Modrm, Mem, 0, 0}, +{"frstor", 1, 0xdd, 4, Modrm, Mem, 0, 0}, + +{"ffree", 1, 0xddc0, _, ShortForm, FloatReg, 0, 0}, +{"fnop", 0, 0xd9d0, _, NoModrm, 0, 0, 0}, +{"fwait", 0, 0x9b, _, NoModrm, 0, 0, 0}, + +/* + opcode prefixes; we allow them as seperate insns too + (see prefix table below) +*/ +{"aword", 0, 0x67, _, NoModrm, 0, 0, 0}, +{"addr16", 0, 0x67, _, NoModrm, 0, 0, 0}, +{"word", 0, 0x66, _, NoModrm, 0, 0, 0}, +{"data16", 0, 0x66, _, NoModrm, 0, 0, 0}, +{"lock", 0, 0xf0, _, NoModrm, 0, 0, 0}, +{"cs", 0, 0x2e, _, NoModrm, 0, 0, 0}, +{"ds", 0, 0x3e, _, NoModrm, 0, 0, 0}, +{"es", 0, 0x26, _, NoModrm, 0, 0, 0}, +{"fs", 0, 0x64, _, NoModrm, 0, 0, 0}, +{"gs", 0, 0x65, _, NoModrm, 0, 0, 0}, +{"ss", 0, 0x36, _, NoModrm, 0, 0, 0}, +{"rep", 0, 0xf3, _, NoModrm, 0, 0, 0}, +{"repe", 0, 0xf3, _, NoModrm, 0, 0, 0}, +{ "repne", 0, 0xf2, _, NoModrm, 0, 0, 0}, +{"repz", 0, 0xf3, _, NoModrm, 0, 0, 0}, +{ "repnz", 0, 0xf2, _, NoModrm, 0, 0, 0}, + +/* 486 extensions */ +{"bswap", 1, 0x0fc8, _, ShortForm, Reg32,0,0 }, +{"xadd", 2, 0x0fc0, _, DW|Modrm, Reg, Reg|Mem, 0 }, +{"cmpxchg", 2, 0x0fb0, _, DW|Modrm, Reg, Reg|Mem, 0 }, +{"invd", 0, 0x0f08, _, NoModrm, 0, 0, 0}, +{"wbinvd", 0, 0x0f09, _, NoModrm, 0, 0, 0}, +{"invlpg", 1, 0x0f01, 7, Modrm, Mem, 0, 0}, + +{"", 0, 0, 0, 0, 0, 0, 0} /* sentinal */ +}; +#undef _ + +static const template *i386_optab_end + = i386_optab + sizeof (i386_optab)/sizeof(i386_optab[0]); + +/* 386 register table */ + +static const reg_entry i386_regtab[] = { + /* 8 bit regs */ + {"al", Reg8|Acc, 0}, {"cl", Reg8|ShiftCount, 1}, {"dl", Reg8, 2}, + {"bl", Reg8, 3}, + {"ah", Reg8, 4}, {"ch", Reg8, 5}, {"dh", Reg8, 6}, {"bh", Reg8, 7}, + /* 16 bit regs */ + {"ax", Reg16|Acc, 0}, {"cx", Reg16, 1}, {"dx", Reg16|InOutPortReg, 2}, {"bx", Reg16, 3}, + {"sp", Reg16, 4}, {"bp", Reg16, 5}, {"si", Reg16, 6}, {"di", Reg16, 7}, + /* 32 bit regs */ + {"eax", Reg32|Acc, 0}, {"ecx", Reg32, 1}, {"edx", Reg32, 2}, {"ebx", Reg32, 3}, + {"esp", Reg32, 4}, {"ebp", Reg32, 5}, {"esi", Reg32, 6}, {"edi", Reg32, 7}, + /* segment registers */ + {"es", SReg2, 0}, {"cs", SReg2, 1}, {"ss", SReg2, 2}, + {"ds", SReg2, 3}, {"fs", SReg3, 4}, {"gs", SReg3, 5}, + /* control registers */ + {"cr0", Control, 0}, {"cr2", Control, 2}, {"cr3", Control, 3}, + /* debug registers */ + {"db0", Debug, 0}, {"db1", Debug, 1}, {"db2", Debug, 2}, + {"db3", Debug, 3}, {"db6", Debug, 6}, {"db7", Debug, 7}, + /* test registers */ + {"tr6", Test, 6}, {"tr7", Test, 7}, + /* float registers */ + {"st(0)", FloatReg|FloatAcc, 0}, + {"st", FloatReg|FloatAcc, 0}, + {"st(1)", FloatReg, 1}, {"st(2)", FloatReg, 2}, + {"st(3)", FloatReg, 3}, {"st(4)", FloatReg, 4}, {"st(5)", FloatReg, 5}, + {"st(6)", FloatReg, 6}, {"st(7)", FloatReg, 7} +}; + +#define MAX_REG_NAME_SIZE 8 /* for parsing register names from input */ + +static const reg_entry *i386_regtab_end + = i386_regtab + sizeof(i386_regtab)/sizeof(i386_regtab[0]); + +/* segment stuff */ +static const seg_entry cs = { "cs", 0x2e }; +static const seg_entry ds = { "ds", 0x3e }; +static const seg_entry ss = { "ss", 0x36 }; +static const seg_entry es = { "es", 0x26 }; +static const seg_entry fs = { "fs", 0x64 }; +static const seg_entry gs = { "gs", 0x65 }; +static const seg_entry null = { "", 0x0 }; + +/* + This table is used to store the default segment register implied by all + possible memory addressing modes. + It is indexed by the mode & modrm entries of the modrm byte as follows: + index = (mode<<3) | modrm; +*/ +static const seg_entry *one_byte_segment_defaults[] = { + /* mode 0 */ + &ds, &ds, &ds, &ds, &null, &ds, &ds, &ds, + /* mode 1 */ + &ds, &ds, &ds, &ds, &null, &ss, &ds, &ds, + /* mode 2 */ + &ds, &ds, &ds, &ds, &null, &ss, &ds, &ds, + /* mode 3 --- not a memory reference; never referenced */ +}; + +static const seg_entry *two_byte_segment_defaults[] = { + /* mode 0 */ + &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds, + /* mode 1 */ + &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds, + /* mode 2 */ + &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds, + /* mode 3 --- not a memory reference; never referenced */ +}; + +static const prefix_entry i386_prefixtab[] = { + { "addr16", 0x67 }, /* address size prefix ==> 16bit addressing + * (How is this useful?) */ +#define WORD_PREFIX_OPCODE 0x66 + { "data16", 0x66 }, /* operand size prefix */ + { "lock", 0xf0 }, /* bus lock prefix */ + { "wait", 0x9b }, /* wait for coprocessor */ + { "cs", 0x2e }, { "ds", 0x3e }, /* segment overrides ... */ + { "es", 0x26 }, { "fs", 0x64 }, + { "gs", 0x65 }, { "ss", 0x36 }, +/* REPE & REPNE used to detect rep/repne with a non-string instruction */ +#define REPNE 0xf2 +#define REPE 0xf3 + { "rep", 0xf3 }, { "repe", 0xf3 }, { "repz", 0xf3 }, /* repeat string instructions */ + { "repne", 0xf2 }, { "repnz", 0xf2 } +}; + +static const prefix_entry *i386_prefixtab_end + = i386_prefixtab + sizeof(i386_prefixtab)/sizeof(i386_prefixtab[0]); + +/* end of i386-opcode.h */ diff --git a/gnu/usr.bin/as/opcode/i860.h b/gnu/usr.bin/as/opcode/i860.h new file mode 100644 index 000000000000..0842786d3494 --- /dev/null +++ b/gnu/usr.bin/as/opcode/i860.h @@ -0,0 +1,495 @@ +/* Table of opcodes for the i860. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler, and GDB, the GNU disassembler. + +GAS/GDB is free software; you can 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/GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS or GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined(__STDC__) && !defined(const) +#define const +#endif + +/* + * Structure of an opcode table entry. + */ +struct i860_opcode +{ + const char *name; + unsigned long match; /* Bits that must be set. */ + unsigned long lose; /* Bits that must not be set. */ + const char *args; + /* Nonzero if this is a possible expand-instruction. */ + char expand; +}; + +enum expand_type +{ + E_MOV = 1, E_ADDR, E_U32, E_AND, E_S32, E_DELAY +}; + +/* + All i860 opcodes are 32 bits, except for the pseudoinstructions + and the operations utilizing a 32-bit address expression, an + unsigned 32-bit constant, or a signed 32-bit constant. + These opcodes are expanded into a two-instruction sequence for + any situation where the immediate operand does not fit in 32 bits. + In the case of the add and subtract operations the expansion is + to a three-instruction sequence (ex: orh, or, adds). In cases + where the address is to be relocated, the instruction is + expanded to handle the worse case, this could be optimized at + the final link if the actual address were known. + + The pseudoinstructions are: mov, fmov, pmov, nop, and fnop. + These instructions are implemented as a one or two instruction + sequence of other operations. + + The match component is a mask saying which bits must match a + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing one character + for each operand of the instruction. + +Kinds of operands: + # Number used by optimizer. It is ignored. + 1 src1 integer register. + 2 src2 integer register. + d dest register. + c ctrlreg control register. + i 16 bit immediate. + I 16 bit immediate, aligned. + 5 5 bit immediate. + l lbroff 26 bit PC relative immediate. + r sbroff 16 bit PC relative immediate. + s split 16 bit immediate. + S split 16 bit immediate, aligned. + e src1 floating point register. + f src2 floating point register. + g dest floating point register. + +*/ + +/* The order of the opcodes in this table is significant: + + * The assembler requires that all instances of the same mnemonic must be + consecutive. If they aren't, the assembler will bomb at runtime. + + * The disassembler should not care about the order of the opcodes. */ + +static struct i860_opcode i860_opcodes[] = +{ + +/* REG-Format Instructions */ +{ "ld.c", 0x30000000, 0xcc000000, "c,d", 0 }, /* ld.c csrc2,idest */ +{ "ld.b", 0x00000000, 0xfc000000, "1(2),d", 0 }, /* ld.b isrc1(isrc2),idest */ +{ "ld.b", 0x04000000, 0xf8000000, "I(2),d", E_ADDR }, /* ld.b #const(isrc2),idest */ +{ "ld.s", 0x10000000, 0xec000001, "1(2),d", 0 }, /* ld.s isrc1(isrc2),idest */ +{ "ld.s", 0x14000001, 0xe8000000, "I(2),d", E_ADDR }, /* ld.s #const(isrc2),idest */ +{ "ld.l", 0x10000001, 0xec000000, "1(2),d", 0 }, /* ld.l isrc1(isrc2),idest */ +{ "ld.l", 0x14000001, 0xe8000000, "I(2),d", E_ADDR }, /* ld.l #const(isrc2),idest */ + +{ "st.c", 0x38000000, 0xc4000000, "1,c", 0 }, /* st.c isrc1ni,csrc2 */ +{ "st.b", 0x0c000000, 0xf0000000, "1,S(2)", E_ADDR }, /* st.b isrc1ni,#const(isrc2) */ +{ "st.s", 0x1c000000, 0xe0000000, "1,S(2)", E_ADDR }, /* st.s isrc1ni,#const(isrc2) */ +{ "st.l", 0x1c000001, 0xe0000000, "1,S(2)", E_ADDR }, /* st.l isrc1ni,#const(isrc2) */ + +{ "ixfr", 0x08000000, 0xf4000000, "1,g", 0 }, /* ixfr isrc1ni,fdest */ + +{ "fld.l", 0x20000002, 0xdc000001, "1(2),g", 0 }, /* fld.l isrc1(isrc2),fdest */ +{ "fld.l", 0x24000002, 0xd8000001, "i(2),g", E_ADDR }, /* fld.l #const(isrc2),fdest */ +{ "fld.l", 0x20000003, 0xdc000000, "1(2)++,g", 0 }, /* fld.l isrc1(isrc2)++,fdest */ +{ "fld.l", 0x24000003, 0xd8000000, "i(2)++,g", E_ADDR }, /* fld.l #const(isrc2)++,fdest */ +{ "fld.d", 0x20000000, 0xdc000007, "1(2),g", 0 }, /* fld.d isrc1(isrc2),fdest */ +{ "fld.d", 0x24000000, 0xd8000007, "i(2),g", E_ADDR }, /* fld.d #const(isrc2),fdest */ +{ "fld.d", 0x20000001, 0xdc000006, "1(2)++,g", 0 }, /* fld.d isrc1(isrc2)++,fdest */ +{ "fld.d", 0x24000001, 0xd8000006, "i(2)++,g", E_ADDR }, /* fld.d #const(isrc2)++,fdest */ +{ "fld.q", 0x20000004, 0xdc000003, "1(2),g", 0 }, /* fld.q isrc1(isrc2),fdest */ +{ "fld.q", 0x24000004, 0xd8000003, "i(2),g", E_ADDR }, /* fld.q #const(isrc2),fdest */ +{ "fld.q", 0x20000005, 0xdc000002, "1(2)++,g", 0 }, /* fld.q isrc1(isrc2)++,fdest */ +{ "fld.q", 0x24000005, 0xd8000002, "i(2)++,g", E_ADDR }, /* fld.q #const(isrc2)++,fdest */ + +{ "pfld.l", 0x60000000, 0x9c000003, "1(2),g", 0 }, /* pfld.l isrc1(isrc2),fdest */ +{ "pfld.l", 0x64000000, 0x98000003, "i(2),g", E_ADDR }, /* pfld.l #const(isrc2),fdest */ +{ "pfld.l", 0x60000001, 0x9c000002, "1(2)++,g", 0 }, /* pfld.l isrc1(isrc2)++,fdest */ +{ "pfld.l", 0x64000001, 0x98000002, "i(2)++,g", E_ADDR }, /* pfld.l #const(isrc2)++,fdest */ +{ "pfld.d", 0x60000000, 0x9c000007, "1(2),g", 0 }, /* pfld.d isrc1(isrc2),fdest */ +{ "pfld.d", 0x64000000, 0x98000007, "i(2),g", E_ADDR }, /* pfld.d #const(isrc2),fdest */ +{ "pfld.d", 0x60000001, 0x9c000006, "1(2)++,g", 0 }, /* pfld.d isrc1(isrc2)++,fdest */ +{ "pfld.d", 0x64000001, 0x98000006, "i(2)++,g", E_ADDR }, /* pfld.d #const(isrc2)++,fdest */ + +{ "fst.l", 0x28000002, 0xd4000001, "g,1(2)", 0 }, /* fst.l fdest,isrc1(isrc2) */ +{ "fst.l", 0x2c000002, 0xd0000001, "g,i(2)", E_ADDR }, /* fst.l fdest,#const(isrc2) */ +{ "fst.l", 0x28000003, 0xd4000000, "g,1(2)++", 0 }, /* fst.l fdest,isrc1(isrc2)++ */ +{ "fst.l", 0x2c000003, 0xd0000000, "g,i(2)++", E_ADDR }, /* fst.l fdest,#const(isrc2)++ */ +{ "fst.d", 0x28000000, 0xd4000007, "g,1(2)", 0 }, /* fst.d fdest,isrc1(isrc2) */ +{ "fst.d", 0x2c000000, 0xd0000007, "g,i(2)", E_ADDR }, /* fst.d fdest,#const(isrc2) */ +{ "fst.d", 0x28000001, 0xd4000006, "g,1(2)++", 0 }, /* fst.d fdest,isrc1(isrc2)++ */ +{ "fst.d", 0x2c000001, 0xd0000006, "g,i(2)++", E_ADDR }, /* fst.d fdest,#const(isrc2)++ */ +{ "fst.q", 0x28000004, 0xd4000003, "g,1(2)", 0 }, /* fst.q fdest,isrc1(isrc2) */ +{ "fst.q", 0x2c000004, 0xd0000003, "g,i(2)", E_ADDR }, /* fst.q fdest,#const(isrc2) */ +{ "fst.q", 0x28000005, 0xd4000002, "g,1(2)++", 0 }, /* fst.q fdest,isrc1(isrc2)++ */ +{ "fst.q", 0x2c000005, 0xd0000002, "g,i(2)++", E_ADDR }, /* fst.q fdest,#const(isrc2)++ */ + +{ "pst.d", 0x3c000000, 0xc0000007, "g,i(2)", E_ADDR }, /* pst.d fdest,#const(isrc2) */ +{ "pst.d", 0x3c000001, 0xc0000006, "g,i(2)++", E_ADDR }, /* pst.d fdest,#const(isrc2)++ */ + +{ "addu", 0x80000000, 0x7c000000, "1,2,d", 0 }, /* addu isrc1,isrc2,idest */ +{ "addu", 0x84000000, 0x78000000, "i,2,d", E_S32 }, /* addu #const,isrc2,idest */ +{ "adds", 0x90000000, 0x6c000000, "1,2,d", 0 }, /* adds isrc1,isrc2,idest */ +{ "adds", 0x94000000, 0x68000000, "i,2,d", E_S32 }, /* adds #const,isrc2,idest */ +{ "subu", 0x88000000, 0x74000000, "1,2,d", 0 }, /* subu isrc1,isrc2,idest */ +{ "subu", 0x8c000000, 0x70000000, "i,2,d", E_S32 }, /* subu #const,isrc2,idest */ +{ "subs", 0x98000000, 0x64000000, "1,2,d", 0 }, /* subs isrc1,isrc2,idest */ +{ "subs", 0x9c000000, 0x60000000, "i,2,d", E_S32 }, /* subs #const,isrc2,idest */ + +{ "shl", 0xa0000000, 0x5c000000, "1,2,d", 0 }, /* shl isrc1,isrc2,idest */ +{ "shl", 0xa4000000, 0x58000000, "i,2,d", 0 }, /* shl #const,isrc2,idest */ +{ "shr", 0xa8000000, 0x54000000, "1,2,d", 0 }, /* shr isrc1,isrc2,idest */ +{ "shr", 0xac000000, 0x50000000, "i,2,d", 0 }, /* shr #const,isrc2,idest */ +{ "shrd", 0xb0000000, 0x4c000000, "1,2,d", 0 }, /* shrd isrc1,isrc2,idest */ +{ "shra", 0xb8000000, 0x44000000, "1,2,d", 0 }, /* shra isrc1,isrc2,idest */ +{ "shra", 0xbc000000, 0x40000000, "i,2,d", 0 }, /* shra #const,isrc2,idest */ + +{ "mov", 0xa0000000, 0x5c00f800, "2,d", 0 }, /* shl r0,isrc2,idest */ +{ "mov", 0x94000000, 0x69e00000, "i,d", E_MOV }, /* adds #const,r0,idest */ +{ "nop", 0xa0000000, 0x5ffff800, "", 0 }, /* shl r0,r0,r0 */ +{ "fnop", 0xb0000000, 0x4ffff800, "", 0 }, /* shrd r0,r0,r0 */ + +{ "trap", 0x44000000, 0xb8000000, "1,2,d", 0 }, /* trap isrc1ni,isrc2,idest */ + +{ "flush", 0x34000000, 0xc81f0001, "i(2)", E_ADDR }, /* flush #const(isrc2) */ +{ "flush", 0x34000001, 0xc81f0000, "i(2)++", E_ADDR }, /* flush #const(isrc2)++ */ + +{ "and", 0xc0000000, 0x3c000000, "1,2,d", 0 }, /* and isrc1,isrc2,idest */ +{ "and", 0xc4000000, 0x38000000, "i,2,d", E_AND }, /* and #const,isrc2,idest */ +{ "andh", 0xc8000000, 0x34000000, "1,2,d", 0 }, /* andh isrc1,isrc2,idest */ +{ "andh", 0xcc000000, 0x30000000, "i,2,d", 0 }, /* andh #const,isrc2,idest */ +{ "andnot", 0xd0000000, 0x2c000000, "1,2,d", 0 }, /* andnot isrc1,isrc2,idest */ +{ "andnot", 0xd4000000, 0x28000000, "i,2,d", E_U32 }, /* andnot #const,isrc2,idest */ +{ "andnoth", 0xd8000000, 0x24000000, "1,2,d", 0 }, /* andnoth isrc1,isrc2,idest */ +{ "andnoth", 0xdc000000, 0x20000000, "i,2,d", 0 }, /* andnoth #const,isrc2,idest */ +{ "or", 0xe0000000, 0x1c000000, "1,2,d", 0 }, /* or isrc1,isrc2,idest */ +{ "or", 0xe4000000, 0x18000000, "i,2,d", E_U32 }, /* or #const,isrc2,idest */ +{ "orh", 0xe8000000, 0x14000000, "1,2,d", 0 }, /* orh isrc1,isrc2,idest */ +{ "orh", 0xec000000, 0x10000000, "i,2,d", 0 }, /* orh #const,isrc2,idest */ +{ "xor", 0xf0000000, 0x0c000000, "1,2,d", 0 }, /* xor isrc1,isrc2,idest */ +{ "xor", 0xf4000000, 0x08000000, "i,2,d", E_U32 }, /* xor #const,isrc2,idest */ +{ "xorh", 0xf8000000, 0x04000000, "1,2,d", 0 }, /* xorh isrc1,isrc2,idest */ +{ "xorh", 0xfc000000, 0x00000000, "i,2,d", 0 }, /* xorh #const,isrc2,idest */ + +{ "bte", 0x58000000, 0xa4000000, "1,2,s", 0 }, /* bte isrc1s,isrc2,sbroff */ +{ "bte", 0x5c000000, 0xa0000000, "5,2,s", 0 }, /* bte #const5,isrc2,sbroff */ +{ "btne", 0x50000000, 0xac000000, "1,2,s", 0 }, /* btne isrc1s,isrc2,sbroff */ +{ "btne", 0x54000000, 0xa8000000, "5,2,s", 0 }, /* btne #const5,isrc2,sbroff */ +{ "bla", 0xb4000000, 0x48000000, "1,2,s", E_DELAY }, /* bla isrc1s,isrc2,sbroff */ +{ "bri", 0x40000000, 0xbc000000, "1", E_DELAY }, /* bri isrc1ni */ + +/* Core Escape Instruction Format */ +{ "lock", 0x4c000001, 0xb000001e, "", 0 }, /* lock set BL in dirbase */ +{ "calli", 0x4c000002, 0xb000001d, "1", E_DELAY }, /* calli isrc1ni */ +{ "intovr", 0x4c000004, 0xb000001b, "", 0 }, /* intovr trap on integer overflow */ +{ "unlock", 0x4c000007, 0xb0000018, "", 0 }, /* unlock clear BL in dirbase */ + +/* CTRL-Format Instructions */ +{ "br", 0x68000000, 0x94000000, "l", E_DELAY }, /* br lbroff */ +{ "call", 0x6c000000, 0x90000000, "l", E_DELAY }, /* call lbroff */ +{ "bc", 0x70000000, 0x8c000000, "l", 0 }, /* bc lbroff */ +{ "bc.t", 0x74000000, 0x88000000, "l", E_DELAY }, /* bc.t lbroff */ +{ "bnc", 0x78000000, 0x84000000, "l", 0 }, /* bnc lbroff */ +{ "bnc.t", 0x7c000000, 0x80000000, "l", E_DELAY }, /* bnc.t lbroff */ + +/* Floating Point Escape Instruction Format - pfam.p fsrc1,fsrc2,fdest */ +{ "r2p1.ss", 0x48000400, 0xb40003ff, "e,f,g", 0 }, +{ "r2p1.sd", 0x48000480, 0xb400037f, "e,f,g", 0 }, +{ "r2p1.dd", 0x48000580, 0xb400027f, "e,f,g", 0 }, +{ "r2pt.ss", 0x48000401, 0xb40003fe, "e,f,g", 0 }, +{ "r2pt.sd", 0x48000481, 0xb400037e, "e,f,g", 0 }, +{ "r2pt.dd", 0x48000581, 0xb400027e, "e,f,g", 0 }, +{ "r2ap1.ss", 0x48000402, 0xb40003fd, "e,f,g", 0 }, +{ "r2ap1.sd", 0x48000482, 0xb400037d, "e,f,g", 0 }, +{ "r2ap1.dd", 0x48000582, 0xb400027d, "e,f,g", 0 }, +{ "r2apt.ss", 0x48000403, 0xb40003fc, "e,f,g", 0 }, +{ "r2apt.sd", 0x48000483, 0xb400037c, "e,f,g", 0 }, +{ "r2apt.dd", 0x48000583, 0xb400027c, "e,f,g", 0 }, +{ "i2p1.ss", 0x48000404, 0xb40003fb, "e,f,g", 0 }, +{ "i2p1.sd", 0x48000484, 0xb400037b, "e,f,g", 0 }, +{ "i2p1.dd", 0x48000584, 0xb400027b, "e,f,g", 0 }, +{ "i2pt.ss", 0x48000405, 0xb40003fa, "e,f,g", 0 }, +{ "i2pt.sd", 0x48000485, 0xb400037a, "e,f,g", 0 }, +{ "i2pt.dd", 0x48000585, 0xb400027a, "e,f,g", 0 }, +{ "i2ap1.ss", 0x48000406, 0xb40003f9, "e,f,g", 0 }, +{ "i2ap1.sd", 0x48000486, 0xb4000379, "e,f,g", 0 }, +{ "i2ap1.dd", 0x48000586, 0xb4000279, "e,f,g", 0 }, +{ "i2apt.ss", 0x48000407, 0xb40003f8, "e,f,g", 0 }, +{ "i2apt.sd", 0x48000487, 0xb4000378, "e,f,g", 0 }, +{ "i2apt.dd", 0x48000587, 0xb4000278, "e,f,g", 0 }, +{ "rat1p2.ss", 0x48000408, 0xb40003f7, "e,f,g", 0 }, +{ "rat1p2.sd", 0x48000488, 0xb4000377, "e,f,g", 0 }, +{ "rat1p2.dd", 0x48000588, 0xb4000277, "e,f,g", 0 }, +{ "m12apm.ss", 0x48000409, 0xb40003f6, "e,f,g", 0 }, +{ "m12apm.sd", 0x48000489, 0xb4000376, "e,f,g", 0 }, +{ "m12apm.dd", 0x48000589, 0xb4000276, "e,f,g", 0 }, +{ "ra1p2.ss", 0x4800040a, 0xb40003f5, "e,f,g", 0 }, +{ "ra1p2.sd", 0x4800048a, 0xb4000375, "e,f,g", 0 }, +{ "ra1p2.dd", 0x4800058a, 0xb4000275, "e,f,g", 0 }, +{ "m12ttpa.ss", 0x4800040b, 0xb40003f4, "e,f,g", 0 }, +{ "m12ttpa.sd", 0x4800048b, 0xb4000374, "e,f,g", 0 }, +{ "m12ttpa.dd", 0x4800058b, 0xb4000274, "e,f,g", 0 }, +{ "iat1p2.ss", 0x4800040c, 0xb40003f3, "e,f,g", 0 }, +{ "iat1p2.sd", 0x4800048c, 0xb4000373, "e,f,g", 0 }, +{ "iat1p2.dd", 0x4800058c, 0xb4000273, "e,f,g", 0 }, +{ "m12tpm.ss", 0x4800040d, 0xb40003f2, "e,f,g", 0 }, +{ "m12tpm.sd", 0x4800048d, 0xb4000372, "e,f,g", 0 }, +{ "m12tpm.dd", 0x4800058d, 0xb4000272, "e,f,g", 0 }, +{ "ia1p2.ss", 0x4800040e, 0xb40003f1, "e,f,g", 0 }, +{ "ia1p2.sd", 0x4800048e, 0xb4000371, "e,f,g", 0 }, +{ "ia1p2.dd", 0x4800058e, 0xb4000271, "e,f,g", 0 }, +{ "m12tpa.ss", 0x4800040f, 0xb40003f0, "e,f,g", 0 }, +{ "m12tpa.sd", 0x4800048f, 0xb4000370, "e,f,g", 0 }, +{ "m12tpa.dd", 0x4800058f, 0xb4000270, "e,f,g", 0 }, + +/* Floating Point Escape Instruction Format - pfsm.p fsrc1,fsrc2,fdest */ +{ "r2s1.ss", 0x48000410, 0xb40003ef, "e,f,g", 0 }, +{ "r2s1.sd", 0x48000490, 0xb400036f, "e,f,g", 0 }, +{ "r2s1.dd", 0x48000590, 0xb400026f, "e,f,g", 0 }, +{ "r2st.ss", 0x48000411, 0xb40003ee, "e,f,g", 0 }, +{ "r2st.sd", 0x48000491, 0xb400036e, "e,f,g", 0 }, +{ "r2st.dd", 0x48000591, 0xb400026e, "e,f,g", 0 }, +{ "r2as1.ss", 0x48000412, 0xb40003ed, "e,f,g", 0 }, +{ "r2as1.sd", 0x48000492, 0xb400036d, "e,f,g", 0 }, +{ "r2as1.dd", 0x48000592, 0xb400026d, "e,f,g", 0 }, +{ "r2ast.ss", 0x48000413, 0xb40003ec, "e,f,g", 0 }, +{ "r2ast.sd", 0x48000493, 0xb400036c, "e,f,g", 0 }, +{ "r2ast.dd", 0x48000593, 0xb400026c, "e,f,g", 0 }, +{ "i2s1.ss", 0x48000414, 0xb40003eb, "e,f,g", 0 }, +{ "i2s1.sd", 0x48000494, 0xb400036b, "e,f,g", 0 }, +{ "i2s1.dd", 0x48000594, 0xb400026b, "e,f,g", 0 }, +{ "i2st.ss", 0x48000415, 0xb40003ea, "e,f,g", 0 }, +{ "i2st.sd", 0x48000495, 0xb400036a, "e,f,g", 0 }, +{ "i2st.dd", 0x48000595, 0xb400026a, "e,f,g", 0 }, +{ "i2as1.ss", 0x48000416, 0xb40003e9, "e,f,g", 0 }, +{ "i2as1.sd", 0x48000496, 0xb4000369, "e,f,g", 0 }, +{ "i2as1.dd", 0x48000596, 0xb4000269, "e,f,g", 0 }, +{ "i2ast.ss", 0x48000417, 0xb40003e8, "e,f,g", 0 }, +{ "i2ast.sd", 0x48000497, 0xb4000368, "e,f,g", 0 }, +{ "i2ast.dd", 0x48000597, 0xb4000268, "e,f,g", 0 }, +{ "rat1s2.ss", 0x48000418, 0xb40003e7, "e,f,g", 0 }, +{ "rat1s2.sd", 0x48000498, 0xb4000367, "e,f,g", 0 }, +{ "rat1s2.dd", 0x48000598, 0xb4000267, "e,f,g", 0 }, +{ "m12asm.ss", 0x48000419, 0xb40003e6, "e,f,g", 0 }, +{ "m12asm.sd", 0x48000499, 0xb4000366, "e,f,g", 0 }, +{ "m12asm.dd", 0x48000599, 0xb4000266, "e,f,g", 0 }, +{ "ra1s2.ss", 0x4800041a, 0xb40003e5, "e,f,g", 0 }, +{ "ra1s2.sd", 0x4800049a, 0xb4000365, "e,f,g", 0 }, +{ "ra1s2.dd", 0x4800059a, 0xb4000265, "e,f,g", 0 }, +{ "m12ttsa.ss", 0x4800041b, 0xb40003e4, "e,f,g", 0 }, +{ "m12ttsa.sd", 0x4800049b, 0xb4000364, "e,f,g", 0 }, +{ "m12ttsa.dd", 0x4800059b, 0xb4000264, "e,f,g", 0 }, +{ "iat1s2.ss", 0x4800041c, 0xb40003e3, "e,f,g", 0 }, +{ "iat1s2.sd", 0x4800049c, 0xb4000363, "e,f,g", 0 }, +{ "iat1s2.dd", 0x4800059c, 0xb4000263, "e,f,g", 0 }, +{ "m12tsm.ss", 0x4800041d, 0xb40003e2, "e,f,g", 0 }, +{ "m12tsm.sd", 0x4800049d, 0xb4000362, "e,f,g", 0 }, +{ "m12tsm.dd", 0x4800059d, 0xb4000262, "e,f,g", 0 }, +{ "ia1s2.ss", 0x4800041e, 0xb40003e1, "e,f,g", 0 }, +{ "ia1s2.sd", 0x4800049e, 0xb4000361, "e,f,g", 0 }, +{ "ia1s2.dd", 0x4800059e, 0xb4000261, "e,f,g", 0 }, +{ "m12tsa.ss", 0x4800041f, 0xb40003e0, "e,f,g", 0 }, +{ "m12tsa.sd", 0x4800049f, 0xb4000360, "e,f,g", 0 }, +{ "m12tsa.dd", 0x4800059f, 0xb4000260, "e,f,g", 0 }, + +/* Floating Point Escape Instruction Format - pfmam.p fsrc1,fsrc2,fdest */ +{ "mr2p1.ss", 0x48000000, 0xb40007ff, "e,f,g", 0 }, +{ "mr2p1.sd", 0x48000080, 0xb400077f, "e,f,g", 0 }, +{ "mr2p1.dd", 0x48000180, 0xb400067f, "e,f,g", 0 }, +{ "mr2pt.ss", 0x48000001, 0xb40007fe, "e,f,g", 0 }, +{ "mr2pt.sd", 0x48000081, 0xb400077e, "e,f,g", 0 }, +{ "mr2pt.dd", 0x48000181, 0xb400067e, "e,f,g", 0 }, +{ "mr2mp1.ss", 0x48000002, 0xb40007fd, "e,f,g", 0 }, +{ "mr2mp1.sd", 0x48000082, 0xb400077d, "e,f,g", 0 }, +{ "mr2mp1.dd", 0x48000182, 0xb400067d, "e,f,g", 0 }, +{ "mr2mpt.ss", 0x48000003, 0xb40007fc, "e,f,g", 0 }, +{ "mr2mpt.sd", 0x48000083, 0xb400077c, "e,f,g", 0 }, +{ "mr2mpt.dd", 0x48000183, 0xb400067c, "e,f,g", 0 }, +{ "mi2p1.ss", 0x48000004, 0xb40007fb, "e,f,g", 0 }, +{ "mi2p1.sd", 0x48000084, 0xb400077b, "e,f,g", 0 }, +{ "mi2p1.dd", 0x48000184, 0xb400067b, "e,f,g", 0 }, +{ "mi2pt.ss", 0x48000005, 0xb40007fa, "e,f,g", 0 }, +{ "mi2pt.sd", 0x48000085, 0xb400077a, "e,f,g", 0 }, +{ "mi2pt.dd", 0x48000185, 0xb400067a, "e,f,g", 0 }, +{ "mi2mp1.ss", 0x48000006, 0xb40007f9, "e,f,g", 0 }, +{ "mi2mp1.sd", 0x48000086, 0xb4000779, "e,f,g", 0 }, +{ "mi2mp1.dd", 0x48000186, 0xb4000679, "e,f,g", 0 }, +{ "mi2mpt.ss", 0x48000007, 0xb40007f8, "e,f,g", 0 }, +{ "mi2mpt.sd", 0x48000087, 0xb4000778, "e,f,g", 0 }, +{ "mi2mpt.dd", 0x48000187, 0xb4000678, "e,f,g", 0 }, +{ "mrmt1p2.ss", 0x48000008, 0xb40007f7, "e,f,g", 0 }, +{ "mrmt1p2.sd", 0x48000088, 0xb4000777, "e,f,g", 0 }, +{ "mrmt1p2.dd", 0x48000188, 0xb4000677, "e,f,g", 0 }, +{ "mm12mpm.ss", 0x48000009, 0xb40007f6, "e,f,g", 0 }, +{ "mm12mpm.sd", 0x48000089, 0xb4000776, "e,f,g", 0 }, +{ "mm12mpm.dd", 0x48000189, 0xb4000676, "e,f,g", 0 }, +{ "mrm1p2.ss", 0x4800000a, 0xb40007f5, "e,f,g", 0 }, +{ "mrm1p2.sd", 0x4800008a, 0xb4000775, "e,f,g", 0 }, +{ "mrm1p2.dd", 0x4800018a, 0xb4000675, "e,f,g", 0 }, +{ "mm12ttpm.ss",0x4800000b, 0xb40007f4, "e,f,g", 0 }, +{ "mm12ttpm.sd",0x4800008b, 0xb4000774, "e,f,g", 0 }, +{ "mm12ttpm.dd",0x4800018b, 0xb4000674, "e,f,g", 0 }, +{ "mimt1p2.ss", 0x4800000c, 0xb40007f3, "e,f,g", 0 }, +{ "mimt1p2.sd", 0x4800008c, 0xb4000773, "e,f,g", 0 }, +{ "mimt1p2.dd", 0x4800018c, 0xb4000673, "e,f,g", 0 }, +{ "mm12tpm.ss", 0x4800000d, 0xb40007f2, "e,f,g", 0 }, +{ "mm12tpm.sd", 0x4800008d, 0xb4000772, "e,f,g", 0 }, +{ "mm12tpm.dd", 0x4800018d, 0xb4000672, "e,f,g", 0 }, +{ "mim1p2.ss", 0x4800000e, 0xb40007f1, "e,f,g", 0 }, +{ "mim1p2.sd", 0x4800008e, 0xb4000771, "e,f,g", 0 }, +{ "mim1p2.dd", 0x4800018e, 0xb4000671, "e,f,g", 0 }, + +/* Floating Point Escape Instruction Format - pfmsm.p fsrc1,fsrc2,fdest */ +{ "mr2s1.ss", 0x48000010, 0xb40007ef, "e,f,g", 0 }, +{ "mr2s1.sd", 0x48000090, 0xb400076f, "e,f,g", 0 }, +{ "mr2s1.dd", 0x48000190, 0xb400066f, "e,f,g", 0 }, +{ "mr2st.ss", 0x48000011, 0xb40007ee, "e,f,g", 0 }, +{ "mr2st.sd", 0x48000091, 0xb400076e, "e,f,g", 0 }, +{ "mr2st.dd", 0x48000191, 0xb400066e, "e,f,g", 0 }, +{ "mr2ms1.ss", 0x48000012, 0xb40007ed, "e,f,g", 0 }, +{ "mr2ms1.sd", 0x48000092, 0xb400076d, "e,f,g", 0 }, +{ "mr2ms1.dd", 0x48000192, 0xb400066d, "e,f,g", 0 }, +{ "mr2mst.ss", 0x48000013, 0xb40007ec, "e,f,g", 0 }, +{ "mr2mst.sd", 0x48000093, 0xb400076c, "e,f,g", 0 }, +{ "mr2mst.dd", 0x48000193, 0xb400066c, "e,f,g", 0 }, +{ "mi2s1.ss", 0x48000014, 0xb40007eb, "e,f,g", 0 }, +{ "mi2s1.sd", 0x48000094, 0xb400076b, "e,f,g", 0 }, +{ "mi2s1.dd", 0x48000194, 0xb400066b, "e,f,g", 0 }, +{ "mi2st.ss", 0x48000015, 0xb40007ea, "e,f,g", 0 }, +{ "mi2st.sd", 0x48000095, 0xb400076a, "e,f,g", 0 }, +{ "mi2st.dd", 0x48000195, 0xb400066a, "e,f,g", 0 }, +{ "mi2ms1.ss", 0x48000016, 0xb40007e9, "e,f,g", 0 }, +{ "mi2ms1.sd", 0x48000096, 0xb4000769, "e,f,g", 0 }, +{ "mi2ms1.dd", 0x48000196, 0xb4000669, "e,f,g", 0 }, +{ "mi2mst.ss", 0x48000017, 0xb40007e8, "e,f,g", 0 }, +{ "mi2mst.sd", 0x48000097, 0xb4000768, "e,f,g", 0 }, +{ "mi2mst.dd", 0x48000197, 0xb4000668, "e,f,g", 0 }, +{ "mrmt1s2.ss", 0x48000018, 0xb40007e7, "e,f,g", 0 }, +{ "mrmt1s2.sd", 0x48000098, 0xb4000767, "e,f,g", 0 }, +{ "mrmt1s2.dd", 0x48000198, 0xb4000667, "e,f,g", 0 }, +{ "mm12msm.ss", 0x48000019, 0xb40007e6, "e,f,g", 0 }, +{ "mm12msm.sd", 0x48000099, 0xb4000766, "e,f,g", 0 }, +{ "mm12msm.dd", 0x48000199, 0xb4000666, "e,f,g", 0 }, +{ "mrm1s2.ss", 0x4800001a, 0xb40007e5, "e,f,g", 0 }, +{ "mrm1s2.sd", 0x4800009a, 0xb4000765, "e,f,g", 0 }, +{ "mrm1s2.dd", 0x4800019a, 0xb4000665, "e,f,g", 0 }, +{ "mm12ttsm.ss",0x4800001b, 0xb40007e4, "e,f,g", 0 }, +{ "mm12ttsm.sd",0x4800009b, 0xb4000764, "e,f,g", 0 }, +{ "mm12ttsm.dd",0x4800019b, 0xb4000664, "e,f,g", 0 }, +{ "mimt1s2.ss", 0x4800001c, 0xb40007e3, "e,f,g", 0 }, +{ "mimt1s2.sd", 0x4800009c, 0xb4000763, "e,f,g", 0 }, +{ "mimt1s2.dd", 0x4800019c, 0xb4000663, "e,f,g", 0 }, +{ "mm12tsm.ss", 0x4800001d, 0xb40007e2, "e,f,g", 0 }, +{ "mm12tsm.sd", 0x4800009d, 0xb4000762, "e,f,g", 0 }, +{ "mm12tsm.dd", 0x4800019d, 0xb4000662, "e,f,g", 0 }, +{ "mim1s2.ss", 0x4800001e, 0xb40007e1, "e,f,g", 0 }, +{ "mim1s2.sd", 0x4800009e, 0xb4000761, "e,f,g", 0 }, +{ "mim1s2.dd", 0x4800019e, 0xb4000661, "e,f,g", 0 }, + + +{ "fmul.ss", 0x48000020, 0xb40007df, "e,f,g", 0 }, /* fmul.p fsrc1,fsrc2,fdest */ +{ "fmul.sd", 0x480000a0, 0xb400075f, "e,f,g", 0 }, /* fmul.p fsrc1,fsrc2,fdest */ +{ "fmul.dd", 0x480001a0, 0xb400065f, "e,f,g", 0 }, /* fmul.p fsrc1,fsrc2,fdest */ +{ "pfmul.ss", 0x48000420, 0xb40003df, "e,f,g", 0 }, /* pfmul.p fsrc1,fsrc2,fdest */ +{ "pfmul.sd", 0x480004a0, 0xb400035f, "e,f,g", 0 }, /* pfmul.p fsrc1,fsrc2,fdest */ +{ "pfmul.dd", 0x480005a0, 0xb400025f, "e,f,g", 0 }, /* pfmul.p fsrc1,fsrc2,fdest */ +{ "pfmul3.dd", 0x480005a4, 0xb400025b, "e,f,g", 0 }, /* pfmul3.p fsrc1,fsrc2,fdest */ +{ "fmlow.dd", 0x480001a1, 0xb400065e, "e,f,g", 0 }, /* fmlow.dd fsrc1,fsrc2,fdest */ +{ "frcp.ss", 0x48000022, 0xb40007dd, "f,g", 0 }, /* frcp.p fsrc2,fdest */ +{ "frcp.sd", 0x480000a2, 0xb400075d, "f,g", 0 }, /* frcp.p fsrc2,fdest */ +{ "frcp.dd", 0x480001a2, 0xb400065d, "f,g", 0 }, /* frcp.p fsrc2,fdest */ +{ "frsqr.ss", 0x48000023, 0xb40007dc, "f,g", 0 }, /* frsqr.p fsrc2,fdest */ +{ "frsqr.sd", 0x480000a3, 0xb400075c, "f,g", 0 }, /* frsqr.p fsrc2,fdest */ +{ "frsqr.dd", 0x480001a3, 0xb400065c, "f,g", 0 }, /* frsqr.p fsrc2,fdest */ +{ "fadd.ss", 0x48000030, 0xb40007cf, "e,f,g", 0 }, /* fadd.p fsrc1,fsrc2,fdest */ +{ "fadd.sd", 0x480000b0, 0xb400074f, "e,f,g", 0 }, /* fadd.p fsrc1,fsrc2,fdest */ +{ "fadd.dd", 0x480001b0, 0xb400064f, "e,f,g", 0 }, /* fadd.p fsrc1,fsrc2,fdest */ +{ "pfadd.ss", 0x48000430, 0xb40003cf, "e,f,g", 0 }, /* pfadd.p fsrc1,fsrc2,fdest */ +{ "pfadd.sd", 0x480004b0, 0xb400034f, "e,f,g", 0 }, /* pfadd.p fsrc1,fsrc2,fdest */ +{ "pfadd.dd", 0x480005b0, 0xb400024f, "e,f,g", 0 }, /* pfadd.p fsrc1,fsrc2,fdest */ +{ "fsub.ss", 0x48000031, 0xb40007ce, "e,f,g", 0 }, /* fsub.p fsrc1,fsrc2,fdest */ +{ "fsub.sd", 0x480000b1, 0xb400074e, "e,f,g", 0 }, /* fsub.p fsrc1,fsrc2,fdest */ +{ "fsub.dd", 0x480001b1, 0xb400064e, "e,f,g", 0 }, /* fsub.p fsrc1,fsrc2,fdest */ +{ "pfsub.ss", 0x48000431, 0xb40003ce, "e,f,g", 0 }, /* pfsub.p fsrc1,fsrc2,fdest */ +{ "pfsub.sd", 0x480004b1, 0xb400034e, "e,f,g", 0 }, /* pfsub.p fsrc1,fsrc2,fdest */ +{ "pfsub.dd", 0x480005b1, 0xb400024e, "e,f,g", 0 }, /* pfsub.p fsrc1,fsrc2,fdest */ +{ "fix.ss", 0x48000032, 0xb40007cd, "e,g", 0 }, /* fix.p fsrc1,fdest */ +{ "fix.sd", 0x480000b2, 0xb400074d, "e,g", 0 }, /* fix.p fsrc1,fdest */ +{ "fix.dd", 0x480001b2, 0xb400064d, "e,g", 0 }, /* fix.p fsrc1,fdest */ +{ "pfix.ss", 0x48000432, 0xb40003cd, "e,g", 0 }, /* pfix.p fsrc1,fdest */ +{ "pfix.sd", 0x480004b2, 0xb400034d, "e,g", 0 }, /* pfix.p fsrc1,fdest */ +{ "pfix.dd", 0x480005b2, 0xb400024d, "e,g", 0 }, /* pfix.p fsrc1,fdest */ +{ "famov.ss", 0x48000033, 0xb40007cc, "e,g", 0 }, /* famov.p fsrc1,fdest */ +{ "famov.ds", 0x48000133, 0xb40006cc, "e,g", 0 }, /* famov.p fsrc1,fdest */ +{ "famov.sd", 0x480000b3, 0xb400074c, "e,g", 0 }, /* famov.p fsrc1,fdest */ +{ "famov.dd", 0x480001b3, 0xb400064c, "e,g", 0 }, /* famov.p fsrc1,fdest */ +{ "pfamov.ss", 0x48000433, 0xb40003cc, "e,g", 0 }, /* pfamov.p fsrc1,fdest */ +{ "pfamov.ds", 0x48000533, 0xb40002cc, "e,g", 0 }, /* pfamov.p fsrc1,fdest */ +{ "pfamov.sd", 0x480004b3, 0xb400034c, "e,g", 0 }, /* pfamov.p fsrc1,fdest */ +{ "pfamov.dd", 0x480005b3, 0xb400024c, "e,g", 0 }, /* pfamov.p fsrc1,fdest */ +/* pfgt has R bit cleared; pfle has R bit set */ +{ "pfgt.ss", 0x48000434, 0xb40003cb, "e,f,g", 0 }, /* pfgt.p fsrc1,fsrc2,fdest */ +{ "pfgt.sd", 0x48000434, 0xb40003cb, "e,f,g", 0 }, /* pfgt.p fsrc1,fsrc2,fdest */ +{ "pfgt.dd", 0x48000534, 0xb40002cb, "e,f,g", 0 }, /* pfgt.p fsrc1,fsrc2,fdest */ +/* pfgt has R bit cleared; pfle has R bit set */ +{ "pfle.ss", 0x480004b4, 0xb400034b, "e,f,g", 0 }, /* pfle.p fsrc1,fsrc2,fdest */ +{ "pfle.sd", 0x480004b4, 0xb400034b, "e,f,g", 0 }, /* pfle.p fsrc1,fsrc2,fdest */ +{ "pfle.dd", 0x480005b4, 0xb400024b, "e,f,g", 0 }, /* pfle.p fsrc1,fsrc2,fdest */ +{ "ftrunc.ss", 0x4800003a, 0xb40007c5, "e,g", 0 }, /* ftrunc.p fsrc1,fdest */ +{ "ftrunc.sd", 0x480000ba, 0xb4000745, "e,g", 0 }, /* ftrunc.p fsrc1,fdest */ +{ "ftrunc.dd", 0x480001ba, 0xb4000645, "e,g", 0 }, /* ftrunc.p fsrc1,fdest */ +{ "pftrunc.ss", 0x4800043a, 0xb40003c5, "e,g", 0 }, /* pftrunc.p fsrc1,fdest */ +{ "pftrunc.sd", 0x480004ba, 0xb4000345, "e,g", 0 }, /* pftrunc.p fsrc1,fdest */ +{ "pftrunc.dd", 0x480005ba, 0xb4000245, "e,g", 0 }, /* pftrunc.p fsrc1,fdest */ +{ "fxfr", 0x48000040, 0xb40007bf, "e,d", 0 }, /* fxfr fsrc1,idest */ +{ "fiadd.ss", 0x48000049, 0xb40007b6, "e,f,g", 0 }, /* fiadd.w fsrc1,fsrc2,fdest */ +{ "fiadd.dd", 0x480001c9, 0xb4000636, "e,f,g", 0 }, /* fiadd.w fsrc1,fsrc2,fdest */ +{ "pfiadd.ss", 0x48000449, 0xb40003b6, "e,f,g", 0 }, /* pfiadd.w fsrc1,fsrc2,fdest */ +{ "pfiadd.dd", 0x480005c9, 0xb4000236, "e,f,g", 0 }, /* pfiadd.w fsrc1,fsrc2,fdest */ +{ "fisub.ss", 0x4800004d, 0xb40007b2, "e,f,g", 0 }, /* fisub.w fsrc1,fsrc2,fdest */ +{ "fisub.dd", 0x480001cd, 0xb4000632, "e,f,g", 0 }, /* fisub.w fsrc1,fsrc2,fdest */ +{ "pfisub.ss", 0x4800044d, 0xb40003b2, "e,f,g", 0 }, /* pfisub.w fsrc1,fsrc2,fdest */ +{ "pfisub.dd", 0x480005cd, 0xb4000232, "e,f,g", 0 }, /* pfisub.w fsrc1,fsrc2,fdest */ +{ "fzchkl", 0x48000057, 0xb40007a8, "e,f,g", 0 }, /* fzchkl fsrc1,fsrc2,fdest */ +{ "pfzchkl", 0x48000457, 0xb40003a8, "e,f,g", 0 }, /* pfzchkl fsrc1,fsrc2,fdest */ +{ "fzchks", 0x4800005f, 0xb40007a0, "e,f,g", 0 }, /* fzchks fsrc1,fsrc2,fdest */ +{ "pfzchks", 0x4800045f, 0xb40003a0, "e,f,g", 0 }, /* pfzchks fsrc1,fsrc2,fdest */ +{ "faddp", 0x48000050, 0xb40007af, "e,f,g", 0 }, /* faddp fsrc1,fsrc2,fdest */ +{ "pfaddp", 0x48000450, 0xb40003af, "e,f,g", 0 }, /* pfaddp fsrc1,fsrc2,fdest */ +{ "faddz", 0x48000051, 0xb40007ae, "e,f,g", 0 }, /* faddz fsrc1,fsrc2,fdest */ +{ "pfaddz", 0x48000451, 0xb40003ae, "e,f,g", 0 }, /* pfaddz fsrc1,fsrc2,fdest */ +{ "form", 0x4800005a, 0xb40007a5, "e,g", 0 }, /* form fsrc1,fdest */ +{ "pform", 0x4800045a, 0xb40003a5, "e,g", 0 }, /* pform fsrc1,fdest */ + +/* Floating point pseudo-instructions */ +{ "fmov.ss", 0x48000049, 0xb7e007b6, "e,g", 0 }, /* fiadd.ss fsrc1,f0,fdest */ +{ "fmov.dd", 0x480001c9, 0xb7e00636, "e,g", 0 }, /* fiadd.dd fsrc1,f0,fdest */ +{ "fmov.sd", 0x480000b0, 0xb7e0074f, "e,g", 0 }, /* fadd.sd fsrc1,f0,fdest */ +{ "fmov.ds", 0x48000130, 0xb7e006cf, "e,g", 0 }, /* fadd.ds fsrc1,f0,fdest */ +{ "pfmov.ds", 0x48000530, 0xb73002cf, "e,g", 0 }, /* pfadd.ds fsrc1,f0,fdest */ +{ "pfmov.dd", 0x480005c9, 0xb7e00236, "e,g", 0 }, /* pfiadd.dd fsrc1,f0,fdest */ + + +}; + +#define NUMOPCODES ((sizeof i860_opcodes)/(sizeof i860_opcodes[0])) + + diff --git a/gnu/usr.bin/as/opcode/i960.h b/gnu/usr.bin/as/opcode/i960.h new file mode 100644 index 000000000000..0e73bfbc3598 --- /dev/null +++ b/gnu/usr.bin/as/opcode/i960.h @@ -0,0 +1,434 @@ +/* Basic 80960 instruction formats. + * + * The 'COJ' instructions are actually COBR instructions with the 'b' in + * the mnemonic replaced by a 'j'; they are ALWAYS "de-optimized" if necessary: + * if the displacement will not fit in 13 bits, the assembler will replace them + * with the corresponding compare and branch instructions. + * + * All of the 'MEMn' instructions are the same format; the 'n' in the name + * indicates the default index scale factor (the size of the datum operated on). + * + * The FBRA formats are not actually an instruction format. They are the + * "convenience directives" for branching on floating-point comparisons, + * each of which generates 2 instructions (a 'bno' and one other branch). + * + * The CALLJ format is not actually an instruction format. It indicates that + * the instruction generated (a CTRL-format 'call') should have its relocation + * specially flagged for link-time replacement with a 'bal' or 'calls' if + * appropriate. + */ + +/* $Id: i960.h,v 1.1 1993/11/03 00:55:56 paul Exp $ */ + +#define CTRL 0 +#define COBR 1 +#define COJ 2 +#define REG 3 +#define MEM1 4 +#define MEM2 5 +#define MEM4 6 +#define MEM8 7 +#define MEM12 8 +#define MEM16 9 +#define FBRA 10 +#define CALLJ 11 + +/* Masks for the mode bits in REG format instructions */ +#define M1 0x0800 +#define M2 0x1000 +#define M3 0x2000 + +/* Generate the 12-bit opcode for a REG format instruction by placing the + * high 8 bits in instruction bits 24-31, the low 4 bits in instruction bits + * 7-10. + */ + +#define REG_OPC(opc) ((opc & 0xff0) << 20) | ((opc & 0xf) << 7) + +/* Generate a template for a REG format instruction: place the opcode bits + * in the appropriate fields and OR in mode bits for the operands that will not + * be used. I.e., + * set m1=1, if src1 will not be used + * set m2=1, if src2 will not be used + * set m3=1, if dst will not be used + * + * Setting the "unused" mode bits to 1 speeds up instruction execution(!). + * The information is also useful to us because some 1-operand REG instructions + * use the src1 field, others the dst field; and some 2-operand REG instructions + * use src1/src2, others src1/dst. The set mode bits enable us to distinguish. + */ +#define R_0(opc) ( REG_OPC(opc) | M1 | M2 | M3 ) /* No operands */ +#define R_1(opc) ( REG_OPC(opc) | M2 | M3 ) /* 1 operand: src1 */ +#define R_1D(opc) ( REG_OPC(opc) | M1 | M2 ) /* 1 operand: dst */ +#define R_2(opc) ( REG_OPC(opc) | M3 ) /* 2 ops: src1/src2 */ +#define R_2D(opc) ( REG_OPC(opc) | M2 ) /* 2 ops: src1/dst */ +#define R_3(opc) ( REG_OPC(opc) ) /* 3 operands */ + +/* DESCRIPTOR BYTES FOR REGISTER OPERANDS + * + * Interpret names as follows: + * R: global or local register only + * RS: global, local, or (if target allows) special-function register only + * RL: global or local register, or integer literal + * RSL: global, local, or (if target allows) special-function register; + * or integer literal + * F: global, local, or floating-point register + * FL: global, local, or floating-point register; or literal (including + * floating point) + * + * A number appended to a name indicates that registers must be aligned, + * as follows: + * 2: register number must be multiple of 2 + * 4: register number must be multiple of 4 + */ + +#define SFR 0x10 /* Mask for the "sfr-OK" bit */ +#define LIT 0x08 /* Mask for the "literal-OK" bit */ +#define FP 0x04 /* Mask for "floating-point-OK" bit */ + +/* This macro ors the bits together. Note that 'align' is a mask + * for the low 0, 1, or 2 bits of the register number, as appropriate. + */ +#define OP(align,lit,fp,sfr) ( align | lit | fp | sfr ) + +#define R OP( 0, 0, 0, 0 ) +#define RS OP( 0, 0, 0, SFR ) +#define RL OP( 0, LIT, 0, 0 ) +#define RSL OP( 0, LIT, 0, SFR ) +#define F OP( 0, 0, FP, 0 ) +#define FL OP( 0, LIT, FP, 0 ) +#define R2 OP( 1, 0, 0, 0 ) +#define RL2 OP( 1, LIT, 0, 0 ) +#define F2 OP( 1, 0, FP, 0 ) +#define FL2 OP( 1, LIT, FP, 0 ) +#define R4 OP( 3, 0, 0, 0 ) +#define RL4 OP( 3, LIT, 0, 0 ) +#define F4 OP( 3, 0, FP, 0 ) +#define FL4 OP( 3, LIT, FP, 0 ) + +#define M 0x7f /* Memory operand (MEMA & MEMB format instructions) */ + +/* Macros to extract info from the register operand descriptor byte 'od'. + */ +#define SFR_OK(od) (od & SFR) /* TRUE if sfr operand allowed */ +#define LIT_OK(od) (od & LIT) /* TRUE if literal operand allowed */ +#define FP_OK(od) (od & FP) /* TRUE if floating-point op allowed */ +#define REG_ALIGN(od,n) ((od & 0x3 & n) == 0) + /* TRUE if reg #n is properly aligned */ +#define MEMOP(od) (od == M) /* TRUE if operand is a memory operand*/ + +/* Description of a single i80960 instruction */ +struct i960_opcode { + long opcode; /* 32 bits, constant fields filled in, rest zeroed */ + char *name; /* Assembler mnemonic */ + short iclass; /* Class: see #defines below */ + char format; /* REG, COBR, CTRL, MEMn, COJ, FBRA, or CALLJ */ + char num_ops; /* Number of operands */ + char operand[3];/* Operand descriptors; same order as assembler instr */ +}; + +/* Classes of 960 intructions: + * - each instruction falls into one class. + * - each target architecture supports one or more classes. + * + * EACH CONSTANT MUST CONTAIN 1 AND ONLY 1 SET BIT!: see targ_has_iclass(). + */ +#define I_BASE 0x01 /* 80960 base instruction set */ +#define I_CX 0x02 /* 80960Cx instruction */ +#define I_DEC 0x04 /* Decimal instruction */ +#define I_FP 0x08 /* Floating point instruction */ +#define I_KX 0x10 /* 80960Kx instruction */ +#define I_MIL 0x20 /* Military instruction */ +#define I_CASIM 0x40 /* CA simulator instruction */ + +/****************************************************************************** + * + * TABLE OF i960 INSTRUCTION DESCRIPTIONS + * + ******************************************************************************/ + +const struct i960_opcode i960_opcodes[] = { + + /* if a CTRL instruction has an operand, it's always a displacement */ + + { 0x09000000, "callj", I_BASE, CALLJ, 1 },/*default=='call'*/ + { 0x08000000, "b", I_BASE, CTRL, 1 }, + { 0x09000000, "call", I_BASE, CTRL, 1 }, + { 0x0a000000, "ret", I_BASE, CTRL, 0 }, + { 0x0b000000, "bal", I_BASE, CTRL, 1 }, + { 0x10000000, "bno", I_BASE, CTRL, 1 }, + { 0x10000000, "bf", I_BASE, CTRL, 1 }, /* same as bno */ + { 0x10000000, "bru", I_BASE, CTRL, 1 }, /* same as bno */ + { 0x11000000, "bg", I_BASE, CTRL, 1 }, + { 0x11000000, "brg", I_BASE, CTRL, 1 }, /* same as bg */ + { 0x12000000, "be", I_BASE, CTRL, 1 }, + { 0x12000000, "bre", I_BASE, CTRL, 1 }, /* same as be */ + { 0x13000000, "bge", I_BASE, CTRL, 1 }, + { 0x13000000, "brge", I_BASE, CTRL, 1 }, /* same as bge */ + { 0x14000000, "bl", I_BASE, CTRL, 1 }, + { 0x14000000, "brl", I_BASE, CTRL, 1 }, /* same as bl */ + { 0x15000000, "bne", I_BASE, CTRL, 1 }, + { 0x15000000, "brlg", I_BASE, CTRL, 1 }, /* same as bne */ + { 0x16000000, "ble", I_BASE, CTRL, 1 }, + { 0x16000000, "brle", I_BASE, CTRL, 1 }, /* same as ble */ + { 0x17000000, "bo", I_BASE, CTRL, 1 }, + { 0x17000000, "bt", I_BASE, CTRL, 1 }, /* same as bo */ + { 0x17000000, "bro", I_BASE, CTRL, 1 }, /* same as bo */ + { 0x18000000, "faultno", I_BASE, CTRL, 0 }, + { 0x18000000, "faultf", I_BASE, CTRL, 0 }, /*same as faultno*/ + { 0x19000000, "faultg", I_BASE, CTRL, 0 }, + { 0x1a000000, "faulte", I_BASE, CTRL, 0 }, + { 0x1b000000, "faultge", I_BASE, CTRL, 0 }, + { 0x1c000000, "faultl", I_BASE, CTRL, 0 }, + { 0x1d000000, "faultne", I_BASE, CTRL, 0 }, + { 0x1e000000, "faultle", I_BASE, CTRL, 0 }, + { 0x1f000000, "faulto", I_BASE, CTRL, 0 }, + { 0x1f000000, "faultt", I_BASE, CTRL, 0 }, /* syn for faulto */ + + { 0x01000000, "syscall", I_CASIM,CTRL, 0 }, + + /* If a COBR (or COJ) has 3 operands, the last one is always a + * displacement and does not appear explicitly in the table. + */ + + { 0x20000000, "testno", I_BASE, COBR, 1, R }, + { 0x21000000, "testg", I_BASE, COBR, 1, R }, + { 0x22000000, "teste", I_BASE, COBR, 1, R }, + { 0x23000000, "testge", I_BASE, COBR, 1, R }, + { 0x24000000, "testl", I_BASE, COBR, 1, R }, + { 0x25000000, "testne", I_BASE, COBR, 1, R }, + { 0x26000000, "testle", I_BASE, COBR, 1, R }, + { 0x27000000, "testo", I_BASE, COBR, 1, R }, + { 0x30000000, "bbc", I_BASE, COBR, 3, RL, RS }, + { 0x31000000, "cmpobg", I_BASE, COBR, 3, RL, RS }, + { 0x32000000, "cmpobe", I_BASE, COBR, 3, RL, RS }, + { 0x33000000, "cmpobge", I_BASE, COBR, 3, RL, RS }, + { 0x34000000, "cmpobl", I_BASE, COBR, 3, RL, RS }, + { 0x35000000, "cmpobne", I_BASE, COBR, 3, RL, RS }, + { 0x36000000, "cmpoble", I_BASE, COBR, 3, RL, RS }, + { 0x37000000, "bbs", I_BASE, COBR, 3, RL, RS }, + { 0x38000000, "cmpibno", I_BASE, COBR, 3, RL, RS }, + { 0x39000000, "cmpibg", I_BASE, COBR, 3, RL, RS }, + { 0x3a000000, "cmpibe", I_BASE, COBR, 3, RL, RS }, + { 0x3b000000, "cmpibge", I_BASE, COBR, 3, RL, RS }, + { 0x3c000000, "cmpibl", I_BASE, COBR, 3, RL, RS }, + { 0x3d000000, "cmpibne", I_BASE, COBR, 3, RL, RS }, + { 0x3e000000, "cmpible", I_BASE, COBR, 3, RL, RS }, + { 0x3f000000, "cmpibo", I_BASE, COBR, 3, RL, RS }, + { 0x31000000, "cmpojg", I_BASE, COJ, 3, RL, RS }, + { 0x32000000, "cmpoje", I_BASE, COJ, 3, RL, RS }, + { 0x33000000, "cmpojge", I_BASE, COJ, 3, RL, RS }, + { 0x34000000, "cmpojl", I_BASE, COJ, 3, RL, RS }, + { 0x35000000, "cmpojne", I_BASE, COJ, 3, RL, RS }, + { 0x36000000, "cmpojle", I_BASE, COJ, 3, RL, RS }, + { 0x38000000, "cmpijno", I_BASE, COJ, 3, RL, RS }, + { 0x39000000, "cmpijg", I_BASE, COJ, 3, RL, RS }, + { 0x3a000000, "cmpije", I_BASE, COJ, 3, RL, RS }, + { 0x3b000000, "cmpijge", I_BASE, COJ, 3, RL, RS }, + { 0x3c000000, "cmpijl", I_BASE, COJ, 3, RL, RS }, + { 0x3d000000, "cmpijne", I_BASE, COJ, 3, RL, RS }, + { 0x3e000000, "cmpijle", I_BASE, COJ, 3, RL, RS }, + { 0x3f000000, "cmpijo", I_BASE, COJ, 3, RL, RS }, + + { 0x80000000, "ldob", I_BASE, MEM1, 2, M, R }, + { 0x82000000, "stob", I_BASE, MEM1, 2, R , M }, + { 0x84000000, "bx", I_BASE, MEM1, 1, M }, + { 0x85000000, "balx", I_BASE, MEM1, 2, M, R }, + { 0x86000000, "callx", I_BASE, MEM1, 1, M }, + { 0x88000000, "ldos", I_BASE, MEM2, 2, M, R }, + { 0x8a000000, "stos", I_BASE, MEM2, 2, R , M }, + { 0x8c000000, "lda", I_BASE, MEM1, 2, M, R }, + { 0x90000000, "ld", I_BASE, MEM4, 2, M, R }, + { 0x92000000, "st", I_BASE, MEM4, 2, R , M }, + { 0x98000000, "ldl", I_BASE, MEM8, 2, M, R2 }, + { 0x9a000000, "stl", I_BASE, MEM8, 2, R2 ,M }, + { 0xa0000000, "ldt", I_BASE, MEM12, 2, M, R4 }, + { 0xa2000000, "stt", I_BASE, MEM12, 2, R4 ,M }, + { 0xb0000000, "ldq", I_BASE, MEM16, 2, M, R4 }, + { 0xb2000000, "stq", I_BASE, MEM16, 2, R4 ,M }, + { 0xc0000000, "ldib", I_BASE, MEM1, 2, M, R }, + { 0xc2000000, "stib", I_BASE, MEM1, 2, R , M }, + { 0xc8000000, "ldis", I_BASE, MEM2, 2, M, R }, + { 0xca000000, "stis", I_BASE, MEM2, 2, R , M }, + + { R_3(0x580), "notbit", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x581), "and", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x582), "andnot", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x583), "setbit", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x584), "notand", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x586), "xor", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x587), "or", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x588), "nor", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x589), "xnor", I_BASE, REG, 3, RSL,RSL,RS }, + { R_2D(0x58a), "not", I_BASE, REG, 2, RSL,RS }, + { R_3(0x58b), "ornot", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x58c), "clrbit", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x58d), "notor", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x58e), "nand", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x58f), "alterbit", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x590), "addo", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x591), "addi", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x592), "subo", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x593), "subi", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x598), "shro", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x59a), "shrdi", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x59b), "shri", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x59c), "shlo", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x59d), "rotate", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x59e), "shli", I_BASE, REG, 3, RSL,RSL,RS }, + { R_2(0x5a0), "cmpo", I_BASE, REG, 2, RSL,RSL }, + { R_2(0x5a1), "cmpi", I_BASE, REG, 2, RSL,RSL }, + { R_2(0x5a2), "concmpo", I_BASE, REG, 2, RSL,RSL }, + { R_2(0x5a3), "concmpi", I_BASE, REG, 2, RSL,RSL }, + { R_3(0x5a4), "cmpinco", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x5a5), "cmpinci", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x5a6), "cmpdeco", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x5a7), "cmpdeci", I_BASE, REG, 3, RSL,RSL,RS }, + { R_2(0x5ac), "scanbyte", I_BASE, REG, 2, RSL,RSL }, + { R_2(0x5ae), "chkbit", I_BASE, REG, 2, RSL,RSL }, + { R_3(0x5b0), "addc", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x5b2), "subc", I_BASE, REG, 3, RSL,RSL,RS }, + { R_2D(0x5cc), "mov", I_BASE, REG, 2, RSL,RS }, + { R_2D(0x5dc), "movl", I_BASE, REG, 2, RL2,R2 }, + { R_2D(0x5ec), "movt", I_BASE, REG, 2, RL4,R4 }, + { R_2D(0x5fc), "movq", I_BASE, REG, 2, RL4,R4 }, + { R_3(0x610), "atmod", I_BASE, REG, 3, RS, RSL,R }, + { R_3(0x612), "atadd", I_BASE, REG, 3, RS, RSL,RS }, + { R_2D(0x640), "spanbit", I_BASE, REG, 2, RSL,RS }, + { R_2D(0x641), "scanbit", I_BASE, REG, 2, RSL,RS }, + { R_3(0x645), "modac", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x650), "modify", I_BASE, REG, 3, RSL,RSL,R }, + { R_3(0x651), "extract", I_BASE, REG, 3, RSL,RSL,R }, + { R_3(0x654), "modtc", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x655), "modpc", I_BASE, REG, 3, RSL,RSL,R }, + { R_1(0x660), "calls", I_BASE, REG, 1, RSL }, + { R_0(0x66b), "mark", I_BASE, REG, 0, }, + { R_0(0x66c), "fmark", I_BASE, REG, 0, }, + { R_0(0x66d), "flushreg", I_BASE, REG, 0, }, + { R_0(0x66f), "syncf", I_BASE, REG, 0, }, + { R_3(0x670), "emul", I_BASE, REG, 3, RSL,RSL,R2 }, + { R_3(0x671), "ediv", I_BASE, REG, 3, RSL,RL2,RS }, + { R_2D(0x672), "cvtadr", I_CASIM,REG, 2, RL, R2 }, + { R_3(0x701), "mulo", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x708), "remo", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x70b), "divo", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x741), "muli", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x748), "remi", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x749), "modi", I_BASE, REG, 3, RSL,RSL,RS }, + { R_3(0x74b), "divi", I_BASE, REG, 3, RSL,RSL,RS }, + + /* Floating-point instructions */ + + { R_2D(0x674), "cvtir", I_FP, REG, 2, RL, F }, + { R_2D(0x675), "cvtilr", I_FP, REG, 2, RL, F }, + { R_3(0x676), "scalerl", I_FP, REG, 3, RL, FL2,F2 }, + { R_3(0x677), "scaler", I_FP, REG, 3, RL, FL, F }, + { R_3(0x680), "atanr", I_FP, REG, 3, FL, FL, F }, + { R_3(0x681), "logepr", I_FP, REG, 3, FL, FL, F }, + { R_3(0x682), "logr", I_FP, REG, 3, FL, FL, F }, + { R_3(0x683), "remr", I_FP, REG, 3, FL, FL, F }, + { R_2(0x684), "cmpor", I_FP, REG, 2, FL, FL }, + { R_2(0x685), "cmpr", I_FP, REG, 2, FL, FL }, + { R_2D(0x688), "sqrtr", I_FP, REG, 2, FL, F }, + { R_2D(0x689), "expr", I_FP, REG, 2, FL, F }, + { R_2D(0x68a), "logbnr", I_FP, REG, 2, FL, F }, + { R_2D(0x68b), "roundr", I_FP, REG, 2, FL, F }, + { R_2D(0x68c), "sinr", I_FP, REG, 2, FL, F }, + { R_2D(0x68d), "cosr", I_FP, REG, 2, FL, F }, + { R_2D(0x68e), "tanr", I_FP, REG, 2, FL, F }, + { R_1(0x68f), "classr", I_FP, REG, 1, FL }, + { R_3(0x690), "atanrl", I_FP, REG, 3, FL2,FL2,F2 }, + { R_3(0x691), "logeprl", I_FP, REG, 3, FL2,FL2,F2 }, + { R_3(0x692), "logrl", I_FP, REG, 3, FL2,FL2,F2 }, + { R_3(0x693), "remrl", I_FP, REG, 3, FL2,FL2,F2 }, + { R_2(0x694), "cmporl", I_FP, REG, 2, FL2,FL2 }, + { R_2(0x695), "cmprl", I_FP, REG, 2, FL2,FL2 }, + { R_2D(0x698), "sqrtrl", I_FP, REG, 2, FL2,F2 }, + { R_2D(0x699), "exprl", I_FP, REG, 2, FL2,F2 }, + { R_2D(0x69a), "logbnrl", I_FP, REG, 2, FL2,F2 }, + { R_2D(0x69b), "roundrl", I_FP, REG, 2, FL2,F2 }, + { R_2D(0x69c), "sinrl", I_FP, REG, 2, FL2,F2 }, + { R_2D(0x69d), "cosrl", I_FP, REG, 2, FL2,F2 }, + { R_2D(0x69e), "tanrl", I_FP, REG, 2, FL2,F2 }, + { R_1(0x69f), "classrl", I_FP, REG, 1, FL2 }, + { R_2D(0x6c0), "cvtri", I_FP, REG, 2, FL, R }, + { R_2D(0x6c1), "cvtril", I_FP, REG, 2, FL, R2 }, + { R_2D(0x6c2), "cvtzri", I_FP, REG, 2, FL, R }, + { R_2D(0x6c3), "cvtzril", I_FP, REG, 2, FL, R2 }, + { R_2D(0x6c9), "movr", I_FP, REG, 2, FL, F }, + { R_2D(0x6d9), "movrl", I_FP, REG, 2, FL2,F2 }, + { R_2D(0x6e1), "movre", I_FP, REG, 2, FL4,F4 }, + { R_3(0x6e2), "cpysre", I_FP, REG, 3, FL4,FL4,F4 }, + { R_3(0x6e3), "cpyrsre", I_FP, REG, 3, FL4,FL4,F4 }, + { R_3(0x78b), "divr", I_FP, REG, 3, FL, FL, F }, + { R_3(0x78c), "mulr", I_FP, REG, 3, FL, FL, F }, + { R_3(0x78d), "subr", I_FP, REG, 3, FL, FL, F }, + { R_3(0x78f), "addr", I_FP, REG, 3, FL, FL, F }, + { R_3(0x79b), "divrl", I_FP, REG, 3, FL2,FL2,F2 }, + { R_3(0x79c), "mulrl", I_FP, REG, 3, FL2,FL2,F2 }, + { R_3(0x79d), "subrl", I_FP, REG, 3, FL2,FL2,F2 }, + { R_3(0x79f), "addrl", I_FP, REG, 3, FL2,FL2,F2 }, + + /* These are the floating point branch instructions. Each actually + * generates 2 branch instructions: the first a CTRL instruction with + * the indicated opcode, and the second a 'bno'. + */ + + { 0x12000000, "brue", I_FP, FBRA, 1 }, + { 0x11000000, "brug", I_FP, FBRA, 1 }, + { 0x13000000, "bruge", I_FP, FBRA, 1 }, + { 0x14000000, "brul", I_FP, FBRA, 1 }, + { 0x16000000, "brule", I_FP, FBRA, 1 }, + { 0x15000000, "brulg", I_FP, FBRA, 1 }, + + + /* Decimal instructions */ + + { R_3(0x642), "daddc", I_DEC, REG, 3, RSL,RSL,RS }, + { R_3(0x643), "dsubc", I_DEC, REG, 3, RSL,RSL,RS }, + { R_2D(0x644), "dmovt", I_DEC, REG, 2, RSL,RS }, + + + /* KX extensions */ + + { R_2(0x600), "synmov", I_KX, REG, 2, R, R }, + { R_2(0x601), "synmovl", I_KX, REG, 2, R, R }, + { R_2(0x602), "synmovq", I_KX, REG, 2, R, R }, + { R_2D(0x615), "synld", I_KX, REG, 2, R, R }, + + + /* MC extensions */ + + { R_3(0x603), "cmpstr", I_MIL, REG, 3, R, R, RL }, + { R_3(0x604), "movqstr", I_MIL, REG, 3, R, R, RL }, + { R_3(0x605), "movstr", I_MIL, REG, 3, R, R, RL }, + { R_2D(0x613), "inspacc", I_MIL, REG, 2, R, R }, + { R_2D(0x614), "ldphy", I_MIL, REG, 2, R, R }, + { R_3(0x617), "fill", I_MIL, REG, 3, R, RL, RL }, + { R_2D(0x646), "condrec", I_MIL, REG, 2, R, R }, + { R_2D(0x656), "receive", I_MIL, REG, 2, R, R }, + { R_3(0x662), "send", I_MIL, REG, 3, R, RL, R }, + { R_1(0x663), "sendserv", I_MIL, REG, 1, R }, + { R_1(0x664), "resumprcs", I_MIL, REG, 1, R }, + { R_1(0x665), "schedprcs", I_MIL, REG, 1, R }, + { R_0(0x666), "saveprcs", I_MIL, REG, 0, }, + { R_1(0x668), "condwait", I_MIL, REG, 1, R }, + { R_1(0x669), "wait", I_MIL, REG, 1, R }, + { R_1(0x66a), "signal", I_MIL, REG, 1, R }, + { R_1D(0x673), "ldtime", I_MIL, REG, 1, R2 }, + + + /* CX extensions */ + + { R_3(0x5d8), "eshro", I_CX, REG, 3, RSL,RSL,RS }, + { R_3(0x630), "sdma", I_CX, REG, 3, RSL,RSL,RL }, + { R_3(0x631), "udma", I_CX, REG, 0 }, + { R_3(0x659), "sysctl", I_CX, REG, 3, RSL,RSL,RL }, + + + /* END OF TABLE */ + + { 0, NULL, 0, 0 } +}; + + /* end of i960-opcode.h */ diff --git a/gnu/usr.bin/as/opcode/m68k.h b/gnu/usr.bin/as/opcode/m68k.h new file mode 100644 index 000000000000..dda833769066 --- /dev/null +++ b/gnu/usr.bin/as/opcode/m68k.h @@ -0,0 +1,1996 @@ +/* Opcode table for m680[01234]0/m6888[12]/m68851. + Copyright (C) 1989, 1991 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. */ + +/* These are used as bit flags for arch below. */ + +enum m68k_architecture { + m68000 = 0x01, + m68008 = m68000, /* synonym for -m68000. otherwise unused. */ + m68010 = 0x02, + m68020 = 0x04, + m68030 = 0x08, + m68040 = 0x10, + m68881 = 0x20, + m68882 = m68881, /* synonym for -m68881. otherwise unused. */ + m68851 = 0x40, + + /* handy aliases */ + m68040up = m68040, + m68030up = (m68030 | m68040up), + m68020up = (m68020 | m68030up), + m68010up = (m68010 | m68020up), + m68000up = (m68000 | m68010up), + + mfloat = (m68881 | m68882 | m68040), + mmmu = (m68851 | m68030 | m68040) +}; /* enum m68k_architecture */ + + /* note that differences in addressing modes that aren't distinguished + in the following table are handled explicitly by gas. */ + +struct m68k_opcode { + char *name; + unsigned long opcode; + unsigned long match; + char *args; + enum m68k_architecture arch; +}; + +/* 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. + a address register indirect 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: + 0x000 SFC Source Function Code reg [40, 30, 20, 10] + 0x001 DFC Data Function Code reg [40, 30, 20, 10] + 0x002 CACR Cache Control Register [40, 30, 20] + 0x800 USP User Stack Pointer [40, 30, 20, 10] + 0x801 VBR Vector Base reg [40, 30, 20, 10] + 0x802 CAAR Cache Address Register [ 30, 20] + 0x803 MSP Master Stack Pointer [40, 30, 20] + 0x804 ISP Interrupt Stack Pointer [40, 30, 20] + 0x003 TC MMU Translation Control [40] + 0x004 ITT0 Instruction Transparent + Translation reg 0 [40] + 0x005 ITT1 Instruction Transparent + Translation reg 1 [40] + 0x006 DTT0 Data Transparent + Translation reg 0 [40] + 0x007 DTT1 Data Transparent + Translation reg 1 [40] + 0x805 MMUSR MMU Status reg [40] + 0x806 URP User Root Pointer [40] + 0x807 SRP Supervisor Root Pointer [40] + + 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. . . + + c cache identifier which may be "nc" for no cache, "ic" + for instruction cache, "dc" for data cache, or "bc" + for both caches. Used in cinv and cpush. Always + stored in position "d". + + 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 first word, low byte, for branch displacements + W second word (entire), for branch displacements + L second and third words (entire), for branch displacements (also overloaded for move16) + b second word, low byte + w second word (entire) [variable word/long branch offset for dbra] + l second and third word (entire) + g variable 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", m68000up }, +{"abcd", one(0140410), one(0170770), "-s-d", m68000up }, + + /* Add instructions */ +{"addal", one(0150700), one(0170700), "*lAd", m68000up }, +{"addaw", one(0150300), one(0170700), "*wAd", m68000up }, +{"addib", one(0003000), one(0177700), "#b$b", m68000up }, +{"addil", one(0003200), one(0177700), "#l$l", m68000up }, +{"addiw", one(0003100), one(0177700), "#w$w", m68000up }, +{"addqb", one(0050000), one(0170700), "Qd$b", m68000up }, +{"addql", one(0050200), one(0170700), "Qd%l", m68000up }, +{"addqw", one(0050100), one(0170700), "Qd%w", m68000up }, + +{"addb", one(0050000), one(0170700), "Qd$b", m68000up }, /* addq written as add */ +{"addb", one(0003000), one(0177700), "#b$b", m68000up }, /* addi written as add */ +{"addb", one(0150000), one(0170700), ";bDd", m68000up }, /* addb <ea>, Dd */ +{"addb", one(0150400), one(0170700), "Dd~b", m68000up }, /* addb Dd, <ea> */ + +{"addw", one(0050100), one(0170700), "Qd%w", m68000up }, /* addq written as add */ +{"addw", one(0003100), one(0177700), "#w$w", m68000up }, /* addi written as add */ +{"addw", one(0150300), one(0170700), "*wAd", m68000up }, /* adda written as add */ +{"addw", one(0150100), one(0170700), "*wDd", m68000up }, /* addw <ea>, Dd */ +{"addw", one(0150500), one(0170700), "Dd~w", m68000up }, /* addw Dd, <ea> */ + +{"addl", one(0050200), one(0170700), "Qd%l", m68000up }, /* addq written as add */ +{"addl", one(0003200), one(0177700), "#l$l", m68000up }, /* addi written as add */ +{"addl", one(0150700), one(0170700), "*lAd", m68000up }, /* adda written as add */ +{"addl", one(0150200), one(0170700), "*lDd", m68000up }, /* addl <ea>, Dd */ +{"addl", one(0150600), one(0170700), "Dd~l", m68000up }, /* addl Dd, <ea> */ + +{"addxb", one(0150400), one(0170770), "DsDd", m68000up }, +{"addxb", one(0150410), one(0170770), "-s-d", m68000up }, +{"addxl", one(0150600), one(0170770), "DsDd", m68000up }, +{"addxl", one(0150610), one(0170770), "-s-d", m68000up }, +{"addxw", one(0150500), one(0170770), "DsDd", m68000up }, +{"addxw", one(0150510), one(0170770), "-s-d", m68000up }, + +{"andib", one(0001000), one(0177700), "#b$b", m68000up }, +{"andib", one(0001074), one(0177777), "#bCb", m68000up }, /* andi to ccr */ +{"andiw", one(0001100), one(0177700), "#w$w", m68000up }, +{"andiw", one(0001174), one(0177777), "#wSw", m68000up }, /* andi to sr */ +{"andil", one(0001200), one(0177700), "#l$l", m68000up }, + +{"andb", one(0001000), one(0177700), "#b$b", m68000up }, /* andi written as or */ +{"andb", one(0001074), one(0177777), "#bCb", m68000up }, /* andi to ccr */ +{"andb", one(0140000), one(0170700), ";bDd", m68000up }, /* memory to register */ +{"andb", one(0140400), one(0170700), "Dd~b", m68000up }, /* register to memory */ +{"andw", one(0001100), one(0177700), "#w$w", m68000up }, /* andi written as or */ +{"andw", one(0001174), one(0177777), "#wSw", m68000up }, /* andi to sr */ +{"andw", one(0140100), one(0170700), ";wDd", m68000up }, /* memory to register */ +{"andw", one(0140500), one(0170700), "Dd~w", m68000up }, /* register to memory */ +{"andl", one(0001200), one(0177700), "#l$l", m68000up }, /* andi written as or */ +{"andl", one(0140200), one(0170700), ";lDd", m68000up }, /* memory to register */ +{"andl", one(0140600), one(0170700), "Dd~l", m68000up }, /* register to memory */ + +{"aslb", one(0160400), one(0170770), "QdDs", m68000up }, +{"aslb", one(0160440), one(0170770), "DdDs", m68000up }, +{"asll", one(0160600), one(0170770), "QdDs", m68000up }, +{"asll", one(0160640), one(0170770), "DdDs", m68000up }, +{"aslw", one(0160500), one(0170770), "QdDs", m68000up }, +{"aslw", one(0160540), one(0170770), "DdDs", m68000up }, +{"aslw", one(0160700), one(0177700), "~s", m68000up }, /* Shift memory */ +{"asrb", one(0160000), one(0170770), "QdDs", m68000up }, +{"asrb", one(0160040), one(0170770), "DdDs", m68000up }, +{"asrl", one(0160200), one(0170770), "QdDs", m68000up }, +{"asrl", one(0160240), one(0170770), "DdDs", m68000up }, +{"asrw", one(0160100), one(0170770), "QdDs", m68000up }, +{"asrw", one(0160140), one(0170770), "DdDs", m68000up }, +{"asrw", one(0160300), one(0177700), "~s", m68000up }, /* Shift memory */ + +/* Fixed-size branches with 16-bit offsets */ + +{"bhi", one(0061000), one(0177777), "BW", m68000up }, +{"bls", one(0061400), one(0177777), "BW", m68000up }, +{"bcc", one(0062000), one(0177777), "BW", m68000up }, +{"bcs", one(0062400), one(0177777), "BW", m68000up }, +{"bne", one(0063000), one(0177777), "BW", m68000up }, +{"beq", one(0063400), one(0177777), "BW", m68000up }, +{"bvc", one(0064000), one(0177777), "BW", m68000up }, +{"bvs", one(0064400), one(0177777), "BW", m68000up }, +{"bpl", one(0065000), one(0177777), "BW", m68000up }, +{"bmi", one(0065400), one(0177777), "BW", m68000up }, +{"bge", one(0066000), one(0177777), "BW", m68000up }, +{"blt", one(0066400), one(0177777), "BW", m68000up }, +{"bgt", one(0067000), one(0177777), "BW", m68000up }, +{"ble", one(0067400), one(0177777), "BW", m68000up }, +{"bra", one(0060000), one(0177777), "BW", m68000up }, +{"bsr", one(0060400), one(0177777), "BW", m68000up }, + +/* Fixed-size branches with short (byte) offsets */ + +{"bhis", one(0061000), one(0177400), "BB", m68000up }, +{"blss", one(0061400), one(0177400), "BB", m68000up }, +{"bccs", one(0062000), one(0177400), "BB", m68000up }, +{"bcss", one(0062400), one(0177400), "BB", m68000up }, +{"bnes", one(0063000), one(0177400), "BB", m68000up }, +{"beqs", one(0063400), one(0177400), "BB", m68000up }, +{"bvcs", one(0064000), one(0177400), "BB", m68000up }, +{"bvss", one(0064400), one(0177400), "BB", m68000up }, +{"bpls", one(0065000), one(0177400), "BB", m68000up }, +{"bmis", one(0065400), one(0177400), "BB", m68000up }, +{"bges", one(0066000), one(0177400), "BB", m68000up }, +{"blts", one(0066400), one(0177400), "BB", m68000up }, +{"bgts", one(0067000), one(0177400), "BB", m68000up }, +{"bles", one(0067400), one(0177400), "BB", m68000up }, +{"bras", one(0060000), one(0177400), "BB", m68000up }, +{"bsrs", one(0060400), one(0177400), "BB", m68000up }, + +/* Fixed-size branches with long (32-bit) offsets */ + +{"bhil", one(0061377), one(0177777), "BL", m68020up }, +{"blsl", one(0061777), one(0177777), "BL", m68020up }, +{"bccl", one(0062377), one(0177777), "BL", m68020up }, +{"bcsl", one(0062777), one(0177777), "BL", m68020up }, +{"bnel", one(0063377), one(0177777), "BL", m68020up }, +{"beql", one(0063777), one(0177777), "BL", m68020up }, +{"bvcl", one(0064377), one(0177777), "BL", m68020up }, +{"bvsl", one(0064777), one(0177777), "BL", m68020up }, +{"bpll", one(0065377), one(0177777), "BL", m68020up }, +{"bmil", one(0065777), one(0177777), "BL", m68020up }, +{"bgel", one(0066377), one(0177777), "BL", m68020up }, +{"bltl", one(0066777), one(0177777), "BL", m68020up }, +{"bgtl", one(0067377), one(0177777), "BL", m68020up }, +{"blel", one(0067777), one(0177777), "BL", m68020up }, +{"bral", one(0060377), one(0177777), "BL", m68020up }, +{"bsrl", one(0060777), one(0177777), "BL", m68020up }, + +/* We now return you to our regularly scheduled instruction set */ + +{"bchg", one(0000500), one(0170700), "Dd$s", m68000up }, +{"bchg", one(0004100), one(0177700), "#b$s", m68000up }, +{"bclr", one(0000600), one(0170700), "Dd$s", m68000up }, +{"bclr", one(0004200), one(0177700), "#b$s", m68000up }, + +{"bfchg", two(0165300, 0), two(0177700, 0170000), "?sO2O3", m68020up }, +{"bfclr", two(0166300, 0), two(0177700, 0170000), "?sO2O3", m68020up }, +{"bfexts", two(0165700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up }, +{"bfextu", two(0164700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up }, +{"bfffo", two(0166700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up }, +{"bfins", two(0167700, 0), two(0177700, 0100000), "D1?sO2O3", m68020up }, +{"bfset", two(0167300, 0), two(0177700, 0170000), "?sO2O3", m68020up }, +{"bftst", two(0164300, 0), two(0177700, 0170000), "/sO2O3", m68020up }, +{"bkpt", one(0044110), one(0177770), "Qs", m68020up }, + +{"bset", one(0000700), one(0170700), "Dd$s", m68000up }, +{"bset", one(0004300), one(0177700), "#b$s", m68000up }, +{"btst", one(0000400), one(0170700), "Dd@s", m68000up }, +{"btst", one(0004000), one(0177700), "#b@s", m68000up }, + + +{"callm", one(0003300), one(0177700), "#b!s", m68020 }, + +{"cas2l", two(0007374, 0), two(0177777, 0107070), "D3D6D2D5R1R4", m68020up }, /* JF FOO really a 3 word ins */ +{"cas2w", two(0006374, 0), two(0177777, 0107070), "D3D6D2D5R1R4", m68020up }, /* JF ditto */ +{"casb", two(0005300, 0), two(0177700, 0177070), "D3D2~s", m68020up }, +{"casl", two(0007300, 0), two(0177700, 0177070), "D3D2~s", m68020up }, +{"casw", two(0006300, 0), two(0177700, 0177070), "D3D2~s", m68020up }, + +/* {"chk", one(0040600), one(0170700), ";wDd"}, JF FOO this looks wrong */ +{"chk2b", two(0000300, 0004000), two(0177700, 07777), "!sR1", m68020up }, +{"chk2l", two(0002300, 0004000), two(0177700, 07777), "!sR1", m68020up }, +{"chk2w", two(0001300, 0004000), two(0177700, 07777), "!sR1", m68020up }, +{"chkl", one(0040400), one(0170700), ";lDd", m68000up }, +{"chkw", one(0040600), one(0170700), ";wDd", m68000up }, + +#define SCOPE_LINE (0x1 << 3) +#define SCOPE_PAGE (0x2 << 3) +#define SCOPE_ALL (0x3 << 3) + +{"cinva", one(0xf400|SCOPE_ALL), one(0xff20), "ce", m68040 }, +{"cinvl", one(0xf400|SCOPE_LINE), one(0xff20), "ceas", m68040 }, +{"cinvp", one(0xf400|SCOPE_PAGE), one(0xff20), "ceas", m68040 }, + +{"cpusha", one(0xf420|SCOPE_ALL), one(0xff20), "ce", m68040 }, +{"cpushl", one(0xf420|SCOPE_LINE), one(0xff20), "ceas", m68040 }, +{"cpushp", one(0xf420|SCOPE_PAGE), one(0xff20), "ceas", m68040 }, + +#undef SCOPE_LINE +#undef SCOPE_PAGE +#undef SCOPE_ALL + +{"clrb", one(0041000), one(0177700), "$s", m68000up }, +{"clrl", one(0041200), one(0177700), "$s", m68000up }, +{"clrw", one(0041100), one(0177700), "$s", m68000up }, + +{"cmp2b", two(0000300, 0), two(0177700, 07777), "!sR1", m68020up }, +{"cmp2l", two(0002300, 0), two(0177700, 07777), "!sR1", m68020up }, +{"cmp2w", two(0001300, 0), two(0177700, 07777), "!sR1", m68020up }, +{"cmpal", one(0130700), one(0170700), "*lAd", m68000up }, +{"cmpaw", one(0130300), one(0170700), "*wAd", m68000up }, +{"cmpib", one(0006000), one(0177700), "#b;b", m68000up }, +{"cmpil", one(0006200), one(0177700), "#l;l", m68000up }, +{"cmpiw", one(0006100), one(0177700), "#w;w", m68000up }, +{"cmpb", one(0006000), one(0177700), "#b;b", m68000up }, /* cmpi written as cmp */ +{"cmpb", one(0130000), one(0170700), ";bDd", m68000up }, +{"cmpw", one(0006100), one(0177700), "#w;w", m68000up }, +{"cmpw", one(0130100), one(0170700), "*wDd", m68000up }, +{"cmpw", one(0130300), one(0170700), "*wAd", m68000up }, /* cmpa written as cmp */ +{"cmpl", one(0006200), one(0177700), "#l;l", m68000up }, +{"cmpl", one(0130200), one(0170700), "*lDd", m68000up }, +{"cmpl", one(0130700), one(0170700), "*lAd", m68000up }, +{"cmpmb", one(0130410), one(0170770), "+s+d", m68000up }, +{"cmpml", one(0130610), one(0170770), "+s+d", m68000up }, +{"cmpmw", one(0130510), one(0170770), "+s+d", m68000up }, + +{"dbcc", one(0052310), one(0177770), "DsBw", m68000up }, +{"dbcs", one(0052710), one(0177770), "DsBw", m68000up }, +{"dbeq", one(0053710), one(0177770), "DsBw", m68000up }, +{"dbf", one(0050710), one(0177770), "DsBw", m68000up }, +{"dbge", one(0056310), one(0177770), "DsBw", m68000up }, +{"dbgt", one(0057310), one(0177770), "DsBw", m68000up }, +{"dbhi", one(0051310), one(0177770), "DsBw", m68000up }, +{"dble", one(0057710), one(0177770), "DsBw", m68000up }, +{"dbls", one(0051710), one(0177770), "DsBw", m68000up }, +{"dblt", one(0056710), one(0177770), "DsBw", m68000up }, +{"dbmi", one(0055710), one(0177770), "DsBw", m68000up }, +{"dbne", one(0053310), one(0177770), "DsBw", m68000up }, +{"dbpl", one(0055310), one(0177770), "DsBw", m68000up }, +{"dbra", one(0050710), one(0177770), "DsBw", m68000up }, +{"dbt", one(0050310), one(0177770), "DsBw", m68000up }, +{"dbvc", one(0054310), one(0177770), "DsBw", m68000up }, +{"dbvs", one(0054710), one(0177770), "DsBw", m68000up }, + +{"divsl", two(0046100, 0006000), two(0177700, 0107770), ";lD3D1", m68020up }, +{"divsl", two(0046100, 0004000), two(0177700, 0107770), ";lDD", m68020up }, +{"divsll", two(0046100, 0004000), two(0177700, 0107770), ";lD3D1", m68020up }, +{"divsw", one(0100700), one(0170700), ";wDd", m68000up }, +{"divs", one(0100700), one(0170700), ";wDd", m68000up }, +{"divul", two(0046100, 0002000), two(0177700, 0107770), ";lD3D1", m68020up }, +{"divul", two(0046100, 0000000), two(0177700, 0107770), ";lDD", m68020up }, +{"divull", two(0046100, 0000000), two(0177700, 0107770), ";lD3D1", m68020up }, +{"divuw", one(0100300), one(0170700), ";wDd", m68000up }, +{"divu", one(0100300), one(0170700), ";wDd", m68000up }, +{"eorb", one(0005000), one(0177700), "#b$s", m68000up }, /* eori written as or */ +{"eorb", one(0005074), one(0177777), "#bCs", m68000up }, /* eori to ccr */ +{"eorb", one(0130400), one(0170700), "Dd$s", m68000up }, /* register to memory */ +{"eorib", one(0005000), one(0177700), "#b$s", m68000up }, +{"eorib", one(0005074), one(0177777), "#bCs", m68000up }, /* eori to ccr */ +{"eoril", one(0005200), one(0177700), "#l$s", m68000up }, +{"eoriw", one(0005100), one(0177700), "#w$s", m68000up }, +{"eoriw", one(0005174), one(0177777), "#wSs", m68000up }, /* eori to sr */ +{"eorl", one(0005200), one(0177700), "#l$s", m68000up }, +{"eorl", one(0130600), one(0170700), "Dd$s", m68000up }, +{"eorw", one(0005100), one(0177700), "#w$s", m68000up }, +{"eorw", one(0005174), one(0177777), "#wSs", m68000up }, /* eori to sr */ +{"eorw", one(0130500), one(0170700), "Dd$s", m68000up }, + +{"exg", one(0140500), one(0170770), "DdDs", m68000up }, +{"exg", one(0140510), one(0170770), "AdAs", m68000up }, +{"exg", one(0140610), one(0170770), "DdAs", m68000up }, +{"exg", one(0140610), one(0170770), "AsDd", m68000up }, + +{"extw", one(0044200), one(0177770), "Ds", m68000up }, +{"extl", one(0044300), one(0177770), "Ds", m68000up }, +{"extbl", one(0044700), one(0177770), "Ds", m68020up }, +{"extb.l", one(0044700), one(0177770), "Ds", m68020up }, /* Not sure we should support this one */ + +/* float stuff starts here */ +{"fabsb", two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fabsd", two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fabsl", two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fabsp", two(0xF000, 0x4C18), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fabss", two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fabsw", two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fabsx", two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fabsx", two(0xF000, 0x4818), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fabsx", two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +/* FIXME-NOW: The '040 book that I have claims that these should be + coded exactly like fadd. In fact, the table of opmodes calls them + fadd, fsadd, fdadd. That can't be right. If someone can give me the + right encoding, I'll fix it. By induction, I *think* the right + encoding is 38 & 3c, but I'm not sure. + + in the mean time, if you know the encoding for the opmode field, you + can replace all of the "38),"'s and "3c),"'s below with the corrected + values and these guys should then just work. xoxorich. 31Aug91 */ + +#ifdef comment +{"fsabsb", two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, +{"fsabsd", two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, +{"fsabsl", two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, +{"fsabsp", two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 }, +{"fsabss", two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, +{"fsabsw", two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, +{"fsabsx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, +{"fsabsx", two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, +{"fsabsx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiFt", m68040 }, + +{"fdabsb", two(0xF000, 0x583c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040}, +{"fdabsd", two(0xF000, 0x543c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040}, +{"fdabsl", two(0xF000, 0x403c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040}, +{"fdabsp", two(0xF000, 0x4C3c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040}, +{"fdabss", two(0xF000, 0x443c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040}, +{"fdabsw", two(0xF000, 0x503c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040}, +{"fdabsx", two(0xF000, 0x003c), two(0xF1C0, 0xE07F), "IiF8F7", m68040}, +{"fdabsx", two(0xF000, 0x483c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040}, +{"fdabsx", two(0xF000, 0x003c), two(0xF1C0, 0xE07F), "IiFt", m68040}, +#endif /* comment */ + +{"facosb", two(0xF000, 0x581C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"facosd", two(0xF000, 0x541C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"facosl", two(0xF000, 0x401C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"facosp", two(0xF000, 0x4C1C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"facoss", two(0xF000, 0x441C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"facosw", two(0xF000, 0x501C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"facosx", two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"facosx", two(0xF000, 0x481C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"facosx", two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"faddb", two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"faddd", two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"faddl", two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"faddp", two(0xF000, 0x4C22), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fadds", two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"faddw", two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"faddx", two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"faddx", two(0xF000, 0x4822), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +/* {"faddx", two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiFt", mfloat }, JF removed */ + +{"fsaddb", two(0xF000, 0x5832), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, +{"fsaddd", two(0xF000, 0x5432), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, +{"fsaddl", two(0xF000, 0x4032), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, +{"fsaddp", two(0xF000, 0x4C32), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 }, +{"fsadds", two(0xF000, 0x4432), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, +{"fsaddw", two(0xF000, 0x5032), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, +{"fsaddx", two(0xF000, 0x0032), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, +{"fsaddx", two(0xF000, 0x4832), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, +/* {"fsaddx", two(0xF000, 0x0032), two(0xF1C0, 0xE07F), "IiFt", m68040 }, JF removed */ + +{"fdaddb", two(0xF000, 0x5836), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, +{"fdaddd", two(0xF000, 0x5436), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, +{"fdaddl", two(0xF000, 0x4036), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, +{"fdaddp", two(0xF000, 0x4C36), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 }, +{"fdadds", two(0xF000, 0x4436), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, +{"fdaddw", two(0xF000, 0x5036), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, +{"fdaddx", two(0xF000, 0x0036), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, +{"fdaddx", two(0xF000, 0x4836), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, +/* {"faddx", two(0xF000, 0x0036), two(0xF1C0, 0xE07F), "IiFt", m68040 }, JF removed */ + +{"fasinb", two(0xF000, 0x580C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fasind", two(0xF000, 0x540C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fasinl", two(0xF000, 0x400C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fasinp", two(0xF000, 0x4C0C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fasins", two(0xF000, 0x440C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fasinw", two(0xF000, 0x500C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fasinx", two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fasinx", two(0xF000, 0x480C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fasinx", two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fatanb", two(0xF000, 0x580A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fatand", two(0xF000, 0x540A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fatanl", two(0xF000, 0x400A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fatanp", two(0xF000, 0x4C0A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fatans", two(0xF000, 0x440A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fatanw", two(0xF000, 0x500A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fatanx", two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fatanx", two(0xF000, 0x480A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fatanx", two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fatanhb", two(0xF000, 0x580D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fatanhd", two(0xF000, 0x540D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fatanhl", two(0xF000, 0x400D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fatanhp", two(0xF000, 0x4C0D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fatanhs", two(0xF000, 0x440D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fatanhw", two(0xF000, 0x500D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fatanhx", two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fatanhx", two(0xF000, 0x480D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fatanhx", two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +/* Fixed-size Float branches */ + +{"fbeq", one(0xF081), one(0xF1BF), "IdBW", mfloat }, +{"fbf", one(0xF080), one(0xF1BF), "IdBW", mfloat }, +{"fbge", one(0xF093), one(0xF1BF), "IdBW", mfloat }, +{"fbgl", one(0xF096), one(0xF1BF), "IdBW", mfloat }, +{"fbgle", one(0xF097), one(0xF1BF), "IdBW", mfloat }, +{"fbgt", one(0xF092), one(0xF1BF), "IdBW", mfloat }, +{"fble", one(0xF095), one(0xF1BF), "IdBW", mfloat }, +{"fblt", one(0xF094), one(0xF1BF), "IdBW", mfloat }, +{"fbne", one(0xF08E), one(0xF1BF), "IdBW", mfloat }, +{"fbnge", one(0xF09C), one(0xF1BF), "IdBW", mfloat }, +{"fbngl", one(0xF099), one(0xF1BF), "IdBW", mfloat }, +{"fbngle", one(0xF098), one(0xF1BF), "IdBW", mfloat }, +{"fbngt", one(0xF09D), one(0xF1BF), "IdBW", mfloat }, +{"fbnle", one(0xF09A), one(0xF1BF), "IdBW", mfloat }, +{"fbnlt", one(0xF09B), one(0xF1BF), "IdBW", mfloat }, +{"fboge", one(0xF083), one(0xF1BF), "IdBW", mfloat }, +{"fbogl", one(0xF086), one(0xF1BF), "IdBW", mfloat }, +{"fbogt", one(0xF082), one(0xF1BF), "IdBW", mfloat }, +{"fbole", one(0xF085), one(0xF1BF), "IdBW", mfloat }, +{"fbolt", one(0xF084), one(0xF1BF), "IdBW", mfloat }, +{"fbor", one(0xF087), one(0xF1BF), "IdBW", mfloat }, +{"fbseq", one(0xF091), one(0xF1BF), "IdBW", mfloat }, +{"fbsf", one(0xF090), one(0xF1BF), "IdBW", mfloat }, +{"fbsne", one(0xF09E), one(0xF1BF), "IdBW", mfloat }, +{"fbst", one(0xF09F), one(0xF1BF), "IdBW", mfloat }, +{"fbt", one(0xF08F), one(0xF1BF), "IdBW", mfloat }, +{"fbueq", one(0xF089), one(0xF1BF), "IdBW", mfloat }, +{"fbuge", one(0xF08B), one(0xF1BF), "IdBW", mfloat }, +{"fbugt", one(0xF08A), one(0xF1BF), "IdBW", mfloat }, +{"fbule", one(0xF08D), one(0xF1BF), "IdBW", mfloat }, +{"fbult", one(0xF08C), one(0xF1BF), "IdBW", mfloat }, +{"fbun", one(0xF088), one(0xF1BF), "IdBW", mfloat }, + +/* Float branches -- long (32-bit) displacements */ + +{"fbeql", one(0xF081), one(0xF1BF), "IdBC", mfloat }, +{"fbfl", one(0xF080), one(0xF1BF), "IdBC", mfloat }, +{"fbgel", one(0xF093), one(0xF1BF), "IdBC", mfloat }, +{"fbgll", one(0xF096), one(0xF1BF), "IdBC", mfloat }, +{"fbglel", one(0xF097), one(0xF1BF), "IdBC", mfloat }, +{"fbgtl", one(0xF092), one(0xF1BF), "IdBC", mfloat }, +{"fblel", one(0xF095), one(0xF1BF), "IdBC", mfloat }, +{"fbltl", one(0xF094), one(0xF1BF), "IdBC", mfloat }, +{"fbnel", one(0xF08E), one(0xF1BF), "IdBC", mfloat }, +{"fbngel", one(0xF09C), one(0xF1BF), "IdBC", mfloat }, +{"fbngll", one(0xF099), one(0xF1BF), "IdBC", mfloat }, +{"fbnglel", one(0xF098), one(0xF1BF), "IdBC", mfloat }, +{"fbngtl", one(0xF09D), one(0xF1BF), "IdBC", mfloat }, +{"fbnlel", one(0xF09A), one(0xF1BF), "IdBC", mfloat }, +{"fbnltl", one(0xF09B), one(0xF1BF), "IdBC", mfloat }, +{"fbogel", one(0xF083), one(0xF1BF), "IdBC", mfloat }, +{"fbogll", one(0xF086), one(0xF1BF), "IdBC", mfloat }, +{"fbogtl", one(0xF082), one(0xF1BF), "IdBC", mfloat }, +{"fbolel", one(0xF085), one(0xF1BF), "IdBC", mfloat }, +{"fboltl", one(0xF084), one(0xF1BF), "IdBC", mfloat }, +{"fborl", one(0xF087), one(0xF1BF), "IdBC", mfloat }, +{"fbseql", one(0xF091), one(0xF1BF), "IdBC", mfloat }, +{"fbsfl", one(0xF090), one(0xF1BF), "IdBC", mfloat }, +{"fbsnel", one(0xF09E), one(0xF1BF), "IdBC", mfloat }, +{"fbstl", one(0xF09F), one(0xF1BF), "IdBC", mfloat }, +{"fbtl", one(0xF08F), one(0xF1BF), "IdBC", mfloat }, +{"fbueql", one(0xF089), one(0xF1BF), "IdBC", mfloat }, +{"fbugel", one(0xF08B), one(0xF1BF), "IdBC", mfloat }, +{"fbugtl", one(0xF08A), one(0xF1BF), "IdBC", mfloat }, +{"fbulel", one(0xF08D), one(0xF1BF), "IdBC", mfloat }, +{"fbultl", one(0xF08C), one(0xF1BF), "IdBC", mfloat }, +{"fbunl", one(0xF088), one(0xF1BF), "IdBC", mfloat }, + +{"fcmpb", two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fcmpd", two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fcmpl", two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fcmpp", two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fcmps", two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fcmpw", two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fcmpx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fcmpx", two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +/* {"fcmpx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiFt", mfloat }, JF removed */ + +{"fcosb", two(0xF000, 0x581D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fcosd", two(0xF000, 0x541D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fcosl", two(0xF000, 0x401D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fcosp", two(0xF000, 0x4C1D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fcoss", two(0xF000, 0x441D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fcosw", two(0xF000, 0x501D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fcosx", two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fcosx", two(0xF000, 0x481D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fcosx", two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fcoshb", two(0xF000, 0x5819), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fcoshd", two(0xF000, 0x5419), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fcoshl", two(0xF000, 0x4019), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fcoshp", two(0xF000, 0x4C19), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fcoshs", two(0xF000, 0x4419), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fcoshw", two(0xF000, 0x5019), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fcoshx", two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fcoshx", two(0xF000, 0x4819), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fcoshx", two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fdbeq", two(0xF048, 0x0001), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbf", two(0xF048, 0x0000), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbge", two(0xF048, 0x0013), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbgl", two(0xF048, 0x0016), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbgle", two(0xF048, 0x0017), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbgt", two(0xF048, 0x0012), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdble", two(0xF048, 0x0015), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdblt", two(0xF048, 0x0014), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbne", two(0xF048, 0x000E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbnge", two(0xF048, 0x001C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbngl", two(0xF048, 0x0019), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbngle", two(0xF048, 0x0018), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbngt", two(0xF048, 0x001D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbnle", two(0xF048, 0x001A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbnlt", two(0xF048, 0x001B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdboge", two(0xF048, 0x0003), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbogl", two(0xF048, 0x0006), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbogt", two(0xF048, 0x0002), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbole", two(0xF048, 0x0005), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbolt", two(0xF048, 0x0004), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbor", two(0xF048, 0x0007), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbseq", two(0xF048, 0x0011), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbsf", two(0xF048, 0x0010), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbsne", two(0xF048, 0x001E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbst", two(0xF048, 0x001F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbt", two(0xF048, 0x000F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbueq", two(0xF048, 0x0009), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbuge", two(0xF048, 0x000B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbugt", two(0xF048, 0x000A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbule", two(0xF048, 0x000D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbult", two(0xF048, 0x000C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbun", two(0xF048, 0x0008), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, + +{"fdivb", two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fdivd", two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fdivl", two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fdivp", two(0xF000, 0x4C20), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fdivs", two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fdivw", two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fdivx", two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fdivx", two(0xF000, 0x4820), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +/* {"fdivx", two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiFt", mfloat }, JF */ + +{"fsdivb", two(0xF000, 0x5830), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, +{"fsdivd", two(0xF000, 0x5430), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, +{"fsdivl", two(0xF000, 0x4030), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, +{"fsdivp", two(0xF000, 0x4C30), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 }, +{"fsdivs", two(0xF000, 0x4430), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, +{"fsdivw", two(0xF000, 0x5030), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, +{"fsdivx", two(0xF000, 0x0030), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, +{"fsdivx", two(0xF000, 0x4830), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, +/* {"fsdivx", two(0xF000, 0x0030), two(0xF1C0, 0xE07F), "IiFt", m68040 }, JF */ + +{"fddivb", two(0xF000, 0x5834), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, +{"fddivd", two(0xF000, 0x5434), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, +{"fddivl", two(0xF000, 0x4034), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, +{"fddivp", two(0xF000, 0x4C34), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 }, +{"fddivs", two(0xF000, 0x4434), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, +{"fddivw", two(0xF000, 0x5034), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, +{"fddivx", two(0xF000, 0x0034), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, +{"fddivx", two(0xF000, 0x4834), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, +/* {"fddivx", two(0xF000, 0x0034), two(0xF1C0, 0xE07F), "IiFt", m68040 }, JF */ + +{"fetoxb", two(0xF000, 0x5810), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fetoxd", two(0xF000, 0x5410), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fetoxl", two(0xF000, 0x4010), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fetoxp", two(0xF000, 0x4C10), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fetoxs", two(0xF000, 0x4410), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fetoxw", two(0xF000, 0x5010), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fetoxx", two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fetoxx", two(0xF000, 0x4810), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fetoxx", two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fetoxm1b", two(0xF000, 0x5808), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fetoxm1d", two(0xF000, 0x5408), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fetoxm1l", two(0xF000, 0x4008), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fetoxm1p", two(0xF000, 0x4C08), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fetoxm1s", two(0xF000, 0x4408), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fetoxm1w", two(0xF000, 0x5008), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fetoxm1x", two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fetoxm1x", two(0xF000, 0x4808), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fetoxm1x", two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fgetexpb", two(0xF000, 0x581E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fgetexpd", two(0xF000, 0x541E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fgetexpl", two(0xF000, 0x401E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fgetexpp", two(0xF000, 0x4C1E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fgetexps", two(0xF000, 0x441E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fgetexpw", two(0xF000, 0x501E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fgetexpx", two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fgetexpx", two(0xF000, 0x481E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fgetexpx", two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fgetmanb", two(0xF000, 0x581F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fgetmand", two(0xF000, 0x541F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fgetmanl", two(0xF000, 0x401F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fgetmanp", two(0xF000, 0x4C1F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fgetmans", two(0xF000, 0x441F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fgetmanw", two(0xF000, 0x501F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fgetmanx", two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fgetmanx", two(0xF000, 0x481F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fgetmanx", two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fintb", two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fintd", two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fintl", two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fintp", two(0xF000, 0x4C01), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fints", two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fintw", two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fintx", two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fintx", two(0xF000, 0x4801), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fintx", two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fintrzb", two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fintrzd", two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fintrzl", two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fintrzp", two(0xF000, 0x4C03), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fintrzs", two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fintrzw", two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fintrzx", two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fintrzx", two(0xF000, 0x4803), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fintrzx", two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flog10b", two(0xF000, 0x5815), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flog10d", two(0xF000, 0x5415), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flog10l", two(0xF000, 0x4015), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flog10p", two(0xF000, 0x4C15), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flog10s", two(0xF000, 0x4415), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flog10w", two(0xF000, 0x5015), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flog10x", two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flog10x", two(0xF000, 0x4815), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flog10x", two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flog2b", two(0xF000, 0x5816), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flog2d", two(0xF000, 0x5416), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flog2l", two(0xF000, 0x4016), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flog2p", two(0xF000, 0x4C16), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flog2s", two(0xF000, 0x4416), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flog2w", two(0xF000, 0x5016), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flog2x", two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flog2x", two(0xF000, 0x4816), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flog2x", two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flognb", two(0xF000, 0x5814), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flognd", two(0xF000, 0x5414), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flognl", two(0xF000, 0x4014), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flognp", two(0xF000, 0x4C14), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flogns", two(0xF000, 0x4414), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flognw", two(0xF000, 0x5014), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flognx", two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flognx", two(0xF000, 0x4814), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flognx", two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flognp1b", two(0xF000, 0x5806), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flognp1d", two(0xF000, 0x5406), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flognp1l", two(0xF000, 0x4006), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flognp1p", two(0xF000, 0x4C06), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flognp1s", two(0xF000, 0x4406), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flognp1w", two(0xF000, 0x5006), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flognp1x", two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flognp1x", two(0xF000, 0x4806), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flognp1x", two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fmodb", two(0xF000, 0x5821), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fmodd", two(0xF000, 0x5421), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fmodl", two(0xF000, 0x4021), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fmodp", two(0xF000, 0x4C21), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fmods", two(0xF000, 0x4421), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fmodw", two(0xF000, 0x5021), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fmodx", two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fmodx", two(0xF000, 0x4821), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +/* {"fmodx", two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiFt", mfloat }, JF */ + +{"fmoveb", two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, /* fmove from <ea> to fp<n> */ +{"fmoveb", two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7@b", mfloat }, /* fmove from fp<n> to <ea> */ +{"fmoved", two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, /* fmove from <ea> to fp<n> */ +{"fmoved", two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7@F", mfloat }, /* fmove from fp<n> to <ea> */ +{"fmovel", two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, /* fmove from <ea> to fp<n> */ +{"fmovel", two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7@l", mfloat }, /* fmove from fp<n> to <ea> */ +/* 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", mfloat }, +{"fmovel", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ls8", mfloat }, + +/* {"fmovel", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s", mfloat }, +{"fmovel", two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*ss8", mfloat }, */ + +{"fmovep", two(0xF000, 0x4C00), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, /* fmove from <ea> to fp<n> */ +{"fmovep", two(0xF000, 0x6C00), two(0xF1C0, 0xFC00), "IiF7@pkC", mfloat }, /* fmove.p with k-factors: */ +{"fmovep", two(0xF000, 0x7C00), two(0xF1C0, 0xFC0F), "IiF7@pDk", mfloat }, /* fmove.p with k-factors: */ + +{"fmoves", two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, /* fmove from <ea> to fp<n> */ +{"fmoves", two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7@f", mfloat }, /* fmove from fp<n> to <ea> */ +{"fmovew", two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, /* fmove from <ea> to fp<n> */ +{"fmovew", two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7@w", mfloat }, /* fmove from fp<n> to <ea> */ +{"fmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, /* fmove from <ea> to fp<n> */ +{"fmovex", two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, /* fmove from <ea> to fp<n> */ +{"fmovex", two(0xF000, 0x6800), two(0xF1C0, 0xFC7F), "IiF7@x", mfloat }, /* fmove from fp<n> to <ea> */ +/* JF removed {"fmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiFt", mfloat }, / * fmove from <ea> to fp<n> */ + +{"fsmoveb", two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, /* fmove from <ea> to fp<n> */ +{"fsmoved", two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, /* fmove from <ea> to fp<n> */ +{"fsmovel", two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, /* fmove from <ea> to fp<n> */ +{"fsmoves", two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, /* fmove from <ea> to fp<n> */ +{"fsmovew", two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, /* fmove from <ea> to fp<n> */ +{"fsmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, /* fmove from <ea> to fp<n> */ +{"fsmovex", two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, /* fmove from <ea> to fp<n> */ +/* JF removed {"fsmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiFt", m68040 }, / * fmove from <ea> to fp<n> */ + +{"fdmoveb", two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, /* fmove from <ea> to fp<n> */ +{"fdmoved", two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, /* fmove from <ea> to fp<n> */ +{"fdmovel", two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, /* fmove from <ea> to fp<n> */ +{"fdmoves", two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, /* fmove from <ea> to fp<n> */ +{"fdmovew", two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, /* fmove from <ea> to fp<n> */ +{"fdmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, /* fmove from <ea> to fp<n> */ +{"fdmovex", two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, /* fmove from <ea> to fp<n> */ +/* JF removed {"fdmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiFt", m68040 }, / * fmove from <ea> to fp<n> */ + +{"fmovecrx", two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7", mfloat }, /* fmovecr.x #ccc, FPn */ +{"fmovecr", two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7", mfloat }, + +/* Other fmovemx. */ +{"fmovemx", two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat }, /* reg to control, static and dynamic: */ +{"fmovemx", two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat }, /* from control to reg, static and dynamic: */ + +{"fmovemx", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat }, /* to control, static and dynamic: */ +{"fmovemx", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat }, /* to control, static and dynamic: */ + +{"fmovemx", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat }, /* from control, static and dynamic: */ +{"fmovemx", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat }, /* from control, static and dynamic: */ + +{"fmovemx", two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat }, /* reg to autodecrement, static and dynamic */ +{"fmovemx", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat }, /* to autodecrement, static and dynamic */ +{"fmovemx", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat }, /* to autodecrement, static and dynamic */ + +{"fmovemx", two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat }, /* from autoinc to reg, static and dynamic: */ +{"fmovemx", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat }, /* from autoincrement, static and dynamic: */ +{"fmovemx", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat }, /* from autoincrement, static and dynamic: */ + +{"fmoveml", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8@s", mfloat }, +{"fmoveml", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Ii#8@s", mfloat }, +{"fmoveml", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s", mfloat }, + +{"fmoveml", two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*sL8", mfloat }, +{"fmoveml", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*s#8", mfloat }, +{"fmoveml", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ss8", mfloat }, + +/* fmovemx with register lists */ +{"fmovem", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat }, /* to autodec, static & dynamic */ +{"fmovem", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat }, /* to control, static and dynamic */ +{"fmovem", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat }, /* from autoinc, static & dynamic */ +{"fmovem", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat }, /* from control, static and dynamic */ + + /* Alternate mnemonics for GNU as and GNU CC */ +{"fmovem", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat }, /* to autodecrement, static and dynamic */ +{"fmovem", two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat }, /* to autodecrement, static and dynamic */ + +{"fmovem", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat }, /* to control, static and dynamic: */ +{"fmovem", two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat }, /* to control, static and dynamic: */ + +{"fmovem", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat }, /* from autoincrement, static and dynamic: */ +{"fmovem", two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat }, /* from autoincrement, static and dynamic: */ + +{"fmovem", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat }, /* from control, static and dynamic: */ +{"fmovem", two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat }, /* from control, static and dynamic: */ + +/* fmoveml a FP-control register */ +{"fmovem", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s", mfloat }, +{"fmovem", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ss8", mfloat }, + +/* fmoveml a FP-control reglist */ +{"fmovem", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8@s", mfloat }, +{"fmovem", two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*sL8", mfloat }, + +{"fmulb", two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fmuld", two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fmull", two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fmulp", two(0xF000, 0x4C23), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fmuls", two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fmulw", two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fmulx", two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fmulx", two(0xF000, 0x4823), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +/* {"fmulx", two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiFt", mfloat }, JF */ + +{"fsmulb", two(0xF000, 0x5833), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, +{"fsmuld", two(0xF000, 0x5433), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, +{"fsmull", two(0xF000, 0x4033), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, +{"fsmulp", two(0xF000, 0x4C33), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 }, +{"fsmuls", two(0xF000, 0x4433), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, +{"fsmulw", two(0xF000, 0x5033), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, +{"fsmulx", two(0xF000, 0x0033), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, +{"fsmulx", two(0xF000, 0x4833), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, +/* {"fsmulx", two(0xF000, 0x0033), two(0xF1C0, 0xE07F), "IiFt", m68040 }, JF */ + +{"fdmulb", two(0xF000, 0x5837), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, +{"fdmuld", two(0xF000, 0x5437), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, +{"fdmull", two(0xF000, 0x4037), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, +{"fdmulp", two(0xF000, 0x4C37), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 }, +{"fdmuls", two(0xF000, 0x4437), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, +{"fdmulw", two(0xF000, 0x5037), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, +{"fdmulx", two(0xF000, 0x0037), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, +{"fdmulx", two(0xF000, 0x4837), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, +/* {"dfmulx", two(0xF000, 0x0037), two(0xF1C0, 0xE07F), "IiFt", m68040 }, JF */ + +{"fnegb", two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fnegd", two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fnegl", two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fnegp", two(0xF000, 0x4C1A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fnegs", two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fnegw", two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fnegx", two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fnegx", two(0xF000, 0x481A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fnegx", two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsnegb", two(0xF000, 0x585A), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, +{"fsnegd", two(0xF000, 0x545A), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, +{"fsnegl", two(0xF000, 0x405A), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, +{"fsnegp", two(0xF000, 0x4C5A), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 }, +{"fsnegs", two(0xF000, 0x445A), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, +{"fsnegw", two(0xF000, 0x505A), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, +{"fsnegx", two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, +{"fsnegx", two(0xF000, 0x485A), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, +{"fsnegx", two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiFt", m68040 }, + +{"fdnegb", two(0xF000, 0x585E), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, +{"fdnegd", two(0xF000, 0x545E), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, +{"fdnegl", two(0xF000, 0x405E), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, +{"fdnegp", two(0xF000, 0x4C5E), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 }, +{"fdnegs", two(0xF000, 0x445E), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, +{"fdnegw", two(0xF000, 0x505E), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, +{"fdnegx", two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, +{"fdnegx", two(0xF000, 0x485E), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, +{"fdnegx", two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiFt", m68040 }, + +{"fnop", two(0xF280, 0x0000), two(0xFFFF, 0xFFFF), "Ii", mfloat }, + +{"fremb", two(0xF000, 0x5825), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fremd", two(0xF000, 0x5425), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"freml", two(0xF000, 0x4025), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fremp", two(0xF000, 0x4C25), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"frems", two(0xF000, 0x4425), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fremw", two(0xF000, 0x5025), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fremx", two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fremx", two(0xF000, 0x4825), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +/* {"fremx", two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiFt", mfloat }, JF */ + +{"frestore", one(0xF140), one(0xF1C0), "Id&s", mfloat }, +{"frestore", one(0xF158), one(0xF1F8), "Id+s", mfloat }, +{"fsave", one(0xF100), one(0xF1C0), "Id&s", mfloat }, +{"fsave", one(0xF120), one(0xF1F8), "Id-s", mfloat }, + +{"fscaleb", two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fscaled", two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fscalel", two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fscalep", two(0xF000, 0x4C26), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fscales", two(0xF000, 0x4426), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fscalew", two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fscalex", two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fscalex", two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +/* {"fscalex", two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiFt", mfloat }, 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", mfloat }, +{"fsf", two(0xF040, 0x0000), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsge", two(0xF040, 0x0013), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsgl", two(0xF040, 0x0016), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsgle", two(0xF040, 0x0017), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsgt", two(0xF040, 0x0012), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsle", two(0xF040, 0x0015), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fslt", two(0xF040, 0x0014), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsne", two(0xF040, 0x000E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsnge", two(0xF040, 0x001C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsngl", two(0xF040, 0x0019), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsngle", two(0xF040, 0x0018), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsngt", two(0xF040, 0x001D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsnle", two(0xF040, 0x001A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsnlt", two(0xF040, 0x001B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsoge", two(0xF040, 0x0003), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsogl", two(0xF040, 0x0006), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsogt", two(0xF040, 0x0002), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsole", two(0xF040, 0x0005), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsolt", two(0xF040, 0x0004), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsor", two(0xF040, 0x0007), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsseq", two(0xF040, 0x0011), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fssf", two(0xF040, 0x0010), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fssne", two(0xF040, 0x001E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsst", two(0xF040, 0x001F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fst", two(0xF040, 0x000F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsueq", two(0xF040, 0x0009), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsuge", two(0xF040, 0x000B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsugt", two(0xF040, 0x000A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsule", two(0xF040, 0x000D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsult", two(0xF040, 0x000C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsun", two(0xF040, 0x0008), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, + +{"fsgldivb", two(0xF000, 0x5824), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsgldivd", two(0xF000, 0x5424), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsgldivl", two(0xF000, 0x4024), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsgldivp", two(0xF000, 0x4C24), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsgldivs", two(0xF000, 0x4424), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsgldivw", two(0xF000, 0x5024), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsgldivx", two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsgldivx", two(0xF000, 0x4824), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsgldivx", two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsglmulb", two(0xF000, 0x5827), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsglmuld", two(0xF000, 0x5427), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsglmull", two(0xF000, 0x4027), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsglmulp", two(0xF000, 0x4C27), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsglmuls", two(0xF000, 0x4427), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsglmulw", two(0xF000, 0x5027), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsglmulx", two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsglmulx", two(0xF000, 0x4827), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsglmulx", two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsinb", two(0xF000, 0x580E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsind", two(0xF000, 0x540E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsinl", two(0xF000, 0x400E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsinp", two(0xF000, 0x4C0E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsins", two(0xF000, 0x440E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsinw", two(0xF000, 0x500E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsinx", two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsinx", two(0xF000, 0x480E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsinx", two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsinhb", two(0xF000, 0x5802), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsinhd", two(0xF000, 0x5402), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsinhl", two(0xF000, 0x4002), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsinhp", two(0xF000, 0x4C02), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsinhs", two(0xF000, 0x4402), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsinhw", two(0xF000, 0x5002), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsinhx", two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsinhx", two(0xF000, 0x4802), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsinhx", two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsincosb", two(0xF000, 0x5830), two(0xF1C0, 0xFC78), "Ii;bF3F7", mfloat }, +{"fsincosd", two(0xF000, 0x5430), two(0xF1C0, 0xFC78), "Ii;FF3F7", mfloat }, +{"fsincosl", two(0xF000, 0x4030), two(0xF1C0, 0xFC78), "Ii;lF3F7", mfloat }, +{"fsincosp", two(0xF000, 0x4C30), two(0xF1C0, 0xFC78), "Ii;pF3F7", mfloat }, +{"fsincoss", two(0xF000, 0x4430), two(0xF1C0, 0xFC78), "Ii;fF3F7", mfloat }, +{"fsincosw", two(0xF000, 0x5030), two(0xF1C0, 0xFC78), "Ii;wF3F7", mfloat }, +{"fsincosx", two(0xF000, 0x0030), two(0xF1C0, 0xE078), "IiF8F3F7", mfloat }, +{"fsincosx", two(0xF000, 0x4830), two(0xF1C0, 0xFC78), "Ii;xF3F7", mfloat }, + +{"fsqrtb", two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsqrtd", two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsqrtl", two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsqrtp", two(0xF000, 0x4C04), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsqrts", two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsqrtw", two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsqrtx", two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsqrtx", two(0xF000, 0x4804), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsqrtx", two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fssqrtb", two(0xF000, 0x5841), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, +{"fssqrtd", two(0xF000, 0x5441), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, +{"fssqrtl", two(0xF000, 0x4041), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, +{"fssqrtp", two(0xF000, 0x4C41), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 }, +{"fssqrts", two(0xF000, 0x4441), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, +{"fssqrtw", two(0xF000, 0x5041), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, +{"fssqrtx", two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, +{"fssqrtx", two(0xF000, 0x4841), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, +{"fssqrtx", two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiFt", m68040 }, + +{"fdsqrtb", two(0xF000, 0x5845), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, +{"fdsqrtd", two(0xF000, 0x5445), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, +{"fdsqrtl", two(0xF000, 0x4045), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, +{"fdsqrtp", two(0xF000, 0x4C45), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 }, +{"fdsqrts", two(0xF000, 0x4445), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, +{"fdsqrtw", two(0xF000, 0x5045), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, +{"fdsqrtx", two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, +{"fdsqrtx", two(0xF000, 0x4845), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, +{"fdsqrtx", two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiFt", m68040 }, + +{"fsubb", two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsubd", two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsubl", two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsubp", two(0xF000, 0x4C28), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsubs", two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsubw", two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsubx", two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsubx", two(0xF000, 0x4828), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsubx", two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fssubb", two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, +{"fssubd", two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, +{"fssubl", two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, +{"fssubp", two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 }, +{"fssubs", two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, +{"fssubw", two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, +{"fssubx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, +{"fssubx", two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, +{"fssubx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiFt", m68040 }, + +{"fdsubb", two(0xF000, 0x583c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040 }, +{"fdsubd", two(0xF000, 0x543c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040 }, +{"fdsubl", two(0xF000, 0x403c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040 }, +{"fdsubp", two(0xF000, 0x4C3c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040 }, +{"fdsubs", two(0xF000, 0x443c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040 }, +{"fdsubw", two(0xF000, 0x503c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040 }, +{"fdsubx", two(0xF000, 0x003c), two(0xF1C0, 0xE07F), "IiF8F7", m68040 }, +{"fdsubx", two(0xF000, 0x483c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040 }, +{"fdsubx", two(0xF000, 0x003c), two(0xF1C0, 0xE07F), "IiFt", m68040 }, + +{"ftanb", two(0xF000, 0x580F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftand", two(0xF000, 0x540F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftanl", two(0xF000, 0x400F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftanp", two(0xF000, 0x4C0F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftans", two(0xF000, 0x440F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftanw", two(0xF000, 0x500F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftanx", two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftanx", two(0xF000, 0x480F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftanx", two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"ftanhb", two(0xF000, 0x5809), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftanhd", two(0xF000, 0x5409), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftanhl", two(0xF000, 0x4009), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftanhp", two(0xF000, 0x4C09), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftanhs", two(0xF000, 0x4409), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftanhw", two(0xF000, 0x5009), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftanhx", two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftanhx", two(0xF000, 0x4809), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftanhx", two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"ftentoxb", two(0xF000, 0x5812), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftentoxd", two(0xF000, 0x5412), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftentoxl", two(0xF000, 0x4012), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftentoxp", two(0xF000, 0x4C12), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftentoxs", two(0xF000, 0x4412), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftentoxw", two(0xF000, 0x5012), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftentoxx", two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftentoxx", two(0xF000, 0x4812), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftentoxx", two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"ftrapeq", two(0xF07C, 0x0001), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapf", two(0xF07C, 0x0000), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapge", two(0xF07C, 0x0013), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapgl", two(0xF07C, 0x0016), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapgle", two(0xF07C, 0x0017), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapgt", two(0xF07C, 0x0012), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftraple", two(0xF07C, 0x0015), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftraplt", two(0xF07C, 0x0014), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapne", two(0xF07C, 0x000E), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapnge", two(0xF07C, 0x001C), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapngl", two(0xF07C, 0x0019), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapngle", two(0xF07C, 0x0018), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapngt", two(0xF07C, 0x001D), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapnle", two(0xF07C, 0x001A), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapnlt", two(0xF07C, 0x001B), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapoge", two(0xF07C, 0x0003), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapogl", two(0xF07C, 0x0006), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapogt", two(0xF07C, 0x0002), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapole", two(0xF07C, 0x0005), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapolt", two(0xF07C, 0x0004), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapor", two(0xF07C, 0x0007), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapseq", two(0xF07C, 0x0011), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapsf", two(0xF07C, 0x0010), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapsne", two(0xF07C, 0x001E), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapst", two(0xF07C, 0x001F), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapt", two(0xF07C, 0x000F), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapueq", two(0xF07C, 0x0009), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapuge", two(0xF07C, 0x000B), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapugt", two(0xF07C, 0x000A), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapule", two(0xF07C, 0x000D), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapult", two(0xF07C, 0x000C), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapun", two(0xF07C, 0x0008), two(0xF1FF, 0xFFFF), "Ii", mfloat }, + +{"ftrapeqw", two(0xF07A, 0x0001), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapfw", two(0xF07A, 0x0000), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapgew", two(0xF07A, 0x0013), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapglw", two(0xF07A, 0x0016), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapglew", two(0xF07A, 0x0017), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapgtw", two(0xF07A, 0x0012), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftraplew", two(0xF07A, 0x0015), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapltw", two(0xF07A, 0x0014), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnew", two(0xF07A, 0x000E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapngew", two(0xF07A, 0x001C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnglw", two(0xF07A, 0x0019), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnglew", two(0xF07A, 0x0018), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapngtw", two(0xF07A, 0x001D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnlew", two(0xF07A, 0x001A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnltw", two(0xF07A, 0x001B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapogew", two(0xF07A, 0x0003), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapoglw", two(0xF07A, 0x0006), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapogtw", two(0xF07A, 0x0002), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapolew", two(0xF07A, 0x0005), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapoltw", two(0xF07A, 0x0004), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftraporw", two(0xF07A, 0x0007), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapseqw", two(0xF07A, 0x0011), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapsfw", two(0xF07A, 0x0010), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapsnew", two(0xF07A, 0x001E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapstw", two(0xF07A, 0x001F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftraptw", two(0xF07A, 0x000F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapueqw", two(0xF07A, 0x0009), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapugew", two(0xF07A, 0x000B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapugtw", two(0xF07A, 0x000A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapulew", two(0xF07A, 0x000D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapultw", two(0xF07A, 0x000C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapunw", two(0xF07A, 0x0008), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, + +{"ftrapeql", two(0xF07B, 0x0001), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapfl", two(0xF07B, 0x0000), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapgel", two(0xF07B, 0x0013), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapgll", two(0xF07B, 0x0016), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapglel", two(0xF07B, 0x0017), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapgtl", two(0xF07B, 0x0012), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftraplel", two(0xF07B, 0x0015), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapltl", two(0xF07B, 0x0014), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnel", two(0xF07B, 0x000E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapngel", two(0xF07B, 0x001C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapngll", two(0xF07B, 0x0019), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnglel", two(0xF07B, 0x0018), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapngtl", two(0xF07B, 0x001D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnlel", two(0xF07B, 0x001A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnltl", two(0xF07B, 0x001B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapogel", two(0xF07B, 0x0003), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapogll", two(0xF07B, 0x0006), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapogtl", two(0xF07B, 0x0002), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapolel", two(0xF07B, 0x0005), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapoltl", two(0xF07B, 0x0004), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftraporl", two(0xF07B, 0x0007), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapseql", two(0xF07B, 0x0011), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapsfl", two(0xF07B, 0x0010), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapsnel", two(0xF07B, 0x001E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapstl", two(0xF07B, 0x001F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftraptl", two(0xF07B, 0x000F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapueql", two(0xF07B, 0x0009), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapugel", two(0xF07B, 0x000B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapugtl", two(0xF07B, 0x000A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapulel", two(0xF07B, 0x000D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapultl", two(0xF07B, 0x000C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapunl", two(0xF07B, 0x0008), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, + +{"ftstb", two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Ii;b", mfloat }, +{"ftstd", two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Ii;F", mfloat }, +{"ftstl", two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Ii;l", mfloat }, +{"ftstp", two(0xF000, 0x4C3A), two(0xF1C0, 0xFC7F), "Ii;p", mfloat }, +{"ftsts", two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Ii;f", mfloat }, +{"ftstw", two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Ii;w", mfloat }, +{"ftstx", two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8", mfloat }, +{"ftstx", two(0xF000, 0x483A), two(0xF1C0, 0xFC7F), "Ii;x", mfloat }, + +{"ftwotoxb", two(0xF000, 0x5811), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftwotoxd", two(0xF000, 0x5411), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftwotoxl", two(0xF000, 0x4011), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftwotoxp", two(0xF000, 0x4C11), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftwotoxs", two(0xF000, 0x4411), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftwotoxw", two(0xF000, 0x5011), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftwotoxx", two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftwotoxx", two(0xF000, 0x4811), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftwotoxx", two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +/* Variable-sized float branches */ + +{"fjeq", one(0xF081), one(0xF1FF), "IdBc", mfloat }, +{"fjf", one(0xF080), one(0xF1FF), "IdBc", mfloat }, +{"fjge", one(0xF093), one(0xF1FF), "IdBc", mfloat }, +{"fjgl", one(0xF096), one(0xF1FF), "IdBc", mfloat }, +{"fjgle", one(0xF097), one(0xF1FF), "IdBc", mfloat }, +{"fjgt", one(0xF092), one(0xF1FF), "IdBc", mfloat }, +{"fjle", one(0xF095), one(0xF1FF), "IdBc", mfloat }, +{"fjlt", one(0xF094), one(0xF1FF), "IdBc", mfloat }, +{"fjne", one(0xF08E), one(0xF1FF), "IdBc", mfloat }, +{"fjnge", one(0xF09C), one(0xF1FF), "IdBc", mfloat }, +{"fjngl", one(0xF099), one(0xF1FF), "IdBc", mfloat }, +{"fjngle", one(0xF098), one(0xF1FF), "IdBc", mfloat }, +{"fjngt", one(0xF09D), one(0xF1FF), "IdBc", mfloat }, +{"fjnle", one(0xF09A), one(0xF1FF), "IdBc", mfloat }, +{"fjnlt", one(0xF09B), one(0xF1FF), "IdBc", mfloat }, +{"fjoge", one(0xF083), one(0xF1FF), "IdBc", mfloat }, +{"fjogl", one(0xF086), one(0xF1FF), "IdBc", mfloat }, +{"fjogt", one(0xF082), one(0xF1FF), "IdBc", mfloat }, +{"fjole", one(0xF085), one(0xF1FF), "IdBc", mfloat }, +{"fjolt", one(0xF084), one(0xF1FF), "IdBc", mfloat }, +{"fjor", one(0xF087), one(0xF1FF), "IdBc", mfloat }, +{"fjseq", one(0xF091), one(0xF1FF), "IdBc", mfloat }, +{"fjsf", one(0xF090), one(0xF1FF), "IdBc", mfloat }, +{"fjsne", one(0xF09E), one(0xF1FF), "IdBc", mfloat }, +{"fjst", one(0xF09F), one(0xF1FF), "IdBc", mfloat }, +{"fjt", one(0xF08F), one(0xF1FF), "IdBc", mfloat }, +{"fjueq", one(0xF089), one(0xF1FF), "IdBc", mfloat }, +{"fjuge", one(0xF08B), one(0xF1FF), "IdBc", mfloat }, +{"fjugt", one(0xF08A), one(0xF1FF), "IdBc", mfloat }, +{"fjule", one(0xF08D), one(0xF1FF), "IdBc", mfloat }, +{"fjult", one(0xF08C), one(0xF1FF), "IdBc", mfloat }, +{"fjun", one(0xF088), one(0xF1FF), "IdBc", mfloat }, +/* float stuff ends here */ + +{"illegal", one(0045374), one(0177777), "", m68000up }, +{"jmp", one(0047300), one(0177700), "!s", m68000up }, +{"jsr", one(0047200), one(0177700), "!s", m68000up }, +{"lea", one(0040700), one(0170700), "!sAd", m68000up }, +{"linkw", one(0047120), one(0177770), "As#w", m68000up }, +{"linkl", one(0044010), one(0177770), "As#l", m68020up }, +{"link", one(0047120), one(0177770), "As#w", m68000up }, +{"link", one(0044010), one(0177770), "As#l", m68020up }, + +{"lslb", one(0160410), one(0170770), "QdDs", m68000up }, /* lsrb #Q, Ds */ +{"lslb", one(0160450), one(0170770), "DdDs", m68000up }, /* lsrb Dd, Ds */ +{"lslw", one(0160510), one(0170770), "QdDs", m68000up }, /* lsrb #Q, Ds */ +{"lslw", one(0160550), one(0170770), "DdDs", m68000up }, /* lsrb Dd, Ds */ +{"lslw", one(0161700), one(0177700), "~s", m68000up }, /* Shift memory */ +{"lsll", one(0160610), one(0170770), "QdDs", m68000up }, /* lsrb #Q, Ds */ +{"lsll", one(0160650), one(0170770), "DdDs", m68000up }, /* lsrb Dd, Ds */ + +{"lsrb", one(0160010), one(0170770), "QdDs", m68000up }, /* lsrb #Q, Ds */ +{"lsrb", one(0160050), one(0170770), "DdDs", m68000up }, /* lsrb Dd, Ds */ +{"lsrl", one(0160210), one(0170770), "QdDs", m68000up }, /* lsrb #Q, Ds */ +{"lsrl", one(0160250), one(0170770), "DdDs", m68000up }, /* lsrb #Q, Ds */ +{"lsrw", one(0160110), one(0170770), "QdDs", m68000up }, /* lsrb #Q, Ds */ +{"lsrw", one(0160150), one(0170770), "DdDs", m68000up }, /* lsrb #Q, Ds */ +{"lsrw", one(0161300), one(0177700), "~s", m68000up }, /* Shift memory */ + +{"moveal", one(0020100), one(0170700), "*lAd", m68000up }, +{"moveaw", one(0030100), one(0170700), "*wAd", m68000up }, +{"moveb", one(0010000), one(0170000), ";b$d", m68000up }, /* move */ +{"movel", one(0070000), one(0170400), "MsDd", m68000up }, /* moveq written as move */ +{"movel", one(0020000), one(0170000), "*l$d", m68000up }, +{"movel", one(0020100), one(0170700), "*lAd", m68000up }, +{"movel", one(0047140), one(0177770), "AsUd", m68000up }, /* move to USP */ +{"movel", one(0047150), one(0177770), "UdAs", m68000up }, /* move from USP */ + +{"movec", one(0047173), one(0177777), "R1Jj", m68010up }, +{"movec", one(0047173), one(0177777), "R1#j", m68010up }, +{"movec", one(0047172), one(0177777), "JjR1", m68010up }, +{"movec", one(0047172), one(0177777), "#jR1", m68010up }, + +/* JF added these next four for the assembler */ +{"moveml", one(0044300), one(0177700), "Lw&s", m68000up }, /* movem reg to mem. */ +{"moveml", one(0044340), one(0177770), "lw-s", m68000up }, /* movem reg to autodecrement. */ +{"moveml", one(0046300), one(0177700), "!sLw", m68000up }, /* movem mem to reg. */ +{"moveml", one(0046330), one(0177770), "+sLw", m68000up }, /* movem autoinc to reg. */ + +{"moveml", one(0044300), one(0177700), "#w&s", m68000up }, /* movem reg to mem. */ +{"moveml", one(0044340), one(0177770), "#w-s", m68000up }, /* movem reg to autodecrement. */ +{"moveml", one(0046300), one(0177700), "!s#w", m68000up }, /* movem mem to reg. */ +{"moveml", one(0046330), one(0177770), "+s#w", m68000up }, /* movem autoinc to reg. */ + +/* JF added these next four for the assembler */ +{"movemw", one(0044200), one(0177700), "Lw&s", m68000up }, /* movem reg to mem. */ +{"movemw", one(0044240), one(0177770), "lw-s", m68000up }, /* movem reg to autodecrement. */ +{"movemw", one(0046200), one(0177700), "!sLw", m68000up }, /* movem mem to reg. */ +{"movemw", one(0046230), one(0177770), "+sLw", m68000up }, /* movem autoinc to reg. */ + +{"movemw", one(0044200), one(0177700), "#w&s", m68000up }, /* movem reg to mem. */ +{"movemw", one(0044240), one(0177770), "#w-s", m68000up }, /* movem reg to autodecrement. */ +{"movemw", one(0046200), one(0177700), "!s#w", m68000up }, /* movem mem to reg. */ +{"movemw", one(0046230), one(0177770), "+s#w", m68000up }, /* movem autoinc to reg. */ + +{"movepl", one(0000510), one(0170770), "dsDd", m68000up }, /* memory to register */ +{"movepl", one(0000710), one(0170770), "Ddds", m68000up }, /* register to memory */ +{"movepw", one(0000410), one(0170770), "dsDd", m68000up }, /* memory to register */ +{"movepw", one(0000610), one(0170770), "Ddds", m68000up }, /* register to memory */ +{"moveq", one(0070000), one(0170400), "MsDd", m68000up }, +{"movew", one(0030000), one(0170000), "*w$d", m68000up }, +{"movew", one(0030100), one(0170700), "*wAd", m68000up }, /* movea, written as move */ +{"movew", one(0040300), one(0177700), "Ss$s", m68000up }, /* Move from sr */ +{"movew", one(0041300), one(0177700), "Cs$s", m68010up }, /* Move from ccr */ +{"movew", one(0042300), one(0177700), ";wCd", m68000up }, /* move to ccr */ +{"movew", one(0043300), one(0177700), ";wSd", m68000up }, /* move to sr */ + +{"movesb", two(0007000, 0), two(0177700, 07777), "~sR1", m68010up }, /* moves from memory */ +{"movesb", two(0007000, 04000), two(0177700, 07777), "R1~s", m68010up }, /* moves to memory */ +{"movesl", two(0007200, 0), two(0177700, 07777), "~sR1", m68010up }, /* moves from memory */ +{"movesl", two(0007200, 04000), two(0177700, 07777), "R1~s", m68010up }, /* moves to memory */ +{"movesw", two(0007100, 0), two(0177700, 07777), "~sR1", m68010up }, /* moves from memory */ +{"movesw", two(0007100, 04000), two(0177700, 07777), "R1~s", m68010up }, /* moves to memory */ + +{"move16", two(0xf620, 0x8000), two(0xfff8, 0x8fff), "+s+1", m68040 }, +{"move16", one(0xf600), one(0xfff8), "+s_L", m68040 }, +{"move16", one(0xf608), one(0xfff8), "_L+s", m68040 }, +{"move16", one(0xf610), one(0xfff8), "as_L", m68040 }, +{"move16", one(0xf618), one(0xfff8), "_Las", m68040 }, + +{"mulsl", two(0046000, 004000), two(0177700, 0107770), ";lD1", m68020up }, +{"mulsl", two(0046000, 006000), two(0177700, 0107770), ";lD3D1", m68020up }, +{"mulsw", one(0140700), one(0170700), ";wDd", m68000up }, +{"muls", one(0140700), one(0170700), ";wDd", m68000up }, +{"mulul", two(0046000, 000000), two(0177700, 0107770), ";lD1", m68020up }, +{"mulul", two(0046000, 002000), two(0177700, 0107770), ";lD3D1", m68020up }, +{"muluw", one(0140300), one(0170700), ";wDd", m68000up }, +{"mulu", one(0140300), one(0170700), ";wDd", m68000up }, +{"nbcd", one(0044000), one(0177700), "$s", m68000up }, +{"negb", one(0042000), one(0177700), "$s", m68000up }, +{"negl", one(0042200), one(0177700), "$s", m68000up }, +{"negw", one(0042100), one(0177700), "$s", m68000up }, +{"negxb", one(0040000), one(0177700), "$s", m68000up }, +{"negxl", one(0040200), one(0177700), "$s", m68000up }, +{"negxw", one(0040100), one(0177700), "$s", m68000up }, +{"nop", one(0047161), one(0177777), "", m68000up }, +{"notb", one(0043000), one(0177700), "$s", m68000up }, +{"notl", one(0043200), one(0177700), "$s", m68000up }, +{"notw", one(0043100), one(0177700), "$s", m68000up }, + +{"orb", one(0000000), one(0177700), "#b$s", m68000up }, /* ori written as or */ +{"orb", one(0000074), one(0177777), "#bCs", m68000up }, /* ori to ccr */ +{"orb", one(0100000), one(0170700), ";bDd", m68000up }, /* memory to register */ +{"orb", one(0100400), one(0170700), "Dd~s", m68000up }, /* register to memory */ +{"orib", one(0000000), one(0177700), "#b$s", m68000up }, +{"orib", one(0000074), one(0177777), "#bCs", m68000up }, /* ori to ccr */ +{"oril", one(0000200), one(0177700), "#l$s", m68000up }, +{"oriw", one(0000100), one(0177700), "#w$s", m68000up }, +{"oriw", one(0000174), one(0177777), "#wSs", m68000up }, /* ori to sr */ +{"orl", one(0000200), one(0177700), "#l$s", m68000up }, +{"orl", one(0100200), one(0170700), ";lDd", m68000up }, /* memory to register */ +{"orl", one(0100600), one(0170700), "Dd~s", m68000up }, /* register to memory */ +{"orw", one(0000100), one(0177700), "#w$s", m68000up }, +{"orw", one(0000174), one(0177777), "#wSs", m68000up }, /* ori to sr */ +{"orw", one(0100100), one(0170700), ";wDd", m68000up }, /* memory to register */ +{"orw", one(0100500), one(0170700), "Dd~s", m68000up }, /* register to memory */ + +{"pack", one(0100500), one(0170770), "DsDd#w", m68020up }, /* pack Ds, Dd, #w */ +{"pack", one(0100510), one(0170770), "-s-d#w", m68020up }, /* pack -(As), -(Ad), #w */ + +#ifndef NO_68851 +{"pbac", one(0xf0c7), one(0xffbf), "Bc", m68851 }, +{"pbacw", one(0xf087), one(0xffbf), "Bc", m68851 }, +{"pbas", one(0xf0c6), one(0xffbf), "Bc", m68851 }, +{"pbasw", one(0xf086), one(0xffbf), "Bc", m68851 }, +{"pbbc", one(0xf0c1), one(0xffbf), "Bc", m68851 }, +{"pbbcw", one(0xf081), one(0xffbf), "Bc", m68851 }, +{"pbbs", one(0xf0c0), one(0xffbf), "Bc", m68851 }, +{"pbbsw", one(0xf080), one(0xffbf), "Bc", m68851 }, +{"pbcc", one(0xf0cf), one(0xffbf), "Bc", m68851 }, +{"pbccw", one(0xf08f), one(0xffbf), "Bc", m68851 }, +{"pbcs", one(0xf0ce), one(0xffbf), "Bc", m68851 }, +{"pbcsw", one(0xf08e), one(0xffbf), "Bc", m68851 }, +{"pbgc", one(0xf0cd), one(0xffbf), "Bc", m68851 }, +{"pbgcw", one(0xf08d), one(0xffbf), "Bc", m68851 }, +{"pbgs", one(0xf0cc), one(0xffbf), "Bc", m68851 }, +{"pbgsw", one(0xf08c), one(0xffbf), "Bc", m68851 }, +{"pbic", one(0xf0cb), one(0xffbf), "Bc", m68851 }, +{"pbicw", one(0xf08b), one(0xffbf), "Bc", m68851 }, +{"pbis", one(0xf0ca), one(0xffbf), "Bc", m68851 }, +{"pbisw", one(0xf08a), one(0xffbf), "Bc", m68851 }, +{"pblc", one(0xf0c3), one(0xffbf), "Bc", m68851 }, +{"pblcw", one(0xf083), one(0xffbf), "Bc", m68851 }, +{"pbls", one(0xf0c2), one(0xffbf), "Bc", m68851 }, +{"pblsw", one(0xf082), one(0xffbf), "Bc", m68851 }, +{"pbsc", one(0xf0c5), one(0xffbf), "Bc", m68851 }, +{"pbscw", one(0xf085), one(0xffbf), "Bc", m68851 }, +{"pbss", one(0xf0c4), one(0xffbf), "Bc", m68851 }, +{"pbssw", one(0xf084), one(0xffbf), "Bc", m68851 }, +{"pbwc", one(0xf0c9), one(0xffbf), "Bc", m68851 }, +{"pbwcw", one(0xf089), one(0xffbf), "Bc", m68851 }, +{"pbws", one(0xf0c8), one(0xffbf), "Bc", m68851 }, +{"pbwsw", one(0xf088), one(0xffbf), "Bc", m68851 }, + +{"pdbac", two(0xf048, 0x0007), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbas", two(0xf048, 0x0006), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbbc", two(0xf048, 0x0001), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbbs", two(0xf048, 0x0000), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbcc", two(0xf048, 0x000f), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbcs", two(0xf048, 0x000e), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbgc", two(0xf048, 0x000d), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbgs", two(0xf048, 0x000c), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbic", two(0xf048, 0x000b), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbis", two(0xf048, 0x000a), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdblc", two(0xf048, 0x0003), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbls", two(0xf048, 0x0002), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbsc", two(0xf048, 0x0005), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbss", two(0xf048, 0x0004), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbwc", two(0xf048, 0x0009), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbws", two(0xf048, 0x0008), two(0xfff8, 0xffff), "DsBw", m68851 }, +#endif /* NO_68851 */ + +{"pea", one(0044100), one(0177700), "!s", m68000up }, + +#ifndef NO_68851 +{"pflusha", two(0xf000, 0x2400), two(0xffff, 0xffff), "", m68030 | m68851 }, +{"pflusha", one(0xf510), one(0xfff8), "", m68040 }, + +{"pflush", two(0xf000, 0x3010), two(0xffc0, 0xfe10), "T3T9", m68030 | m68851 }, +{"pflush", two(0xf000, 0x3810), two(0xffc0, 0xfe10), "T3T9&s", m68030 | m68851 }, +{"pflush", two(0xf000, 0x3008), two(0xffc0, 0xfe18), "D3T9", m68030 | m68851 }, +{"pflush", two(0xf000, 0x3808), two(0xffc0, 0xfe18), "D3T9&s", m68030 | m68851 }, +{"pflush", two(0xf000, 0x3000), two(0xffc0, 0xfe1e), "f3T9", m68030 | m68851 }, +{"pflush", two(0xf000, 0x3800), two(0xffc0, 0xfe1e), "f3T9&s", m68030 | m68851 }, +{"pflush", one(0xf500), one(0xfff8), "As", m68040 }, + +{"pflushan", one(0xf518), one(0xfff8), "", m68040 }, +{"pflushn", one(0xf508), one(0xfff8), "As", m68040 }, + +{"pflushr", two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s", m68851 }, + +{"pflushs", two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9", m68851 }, +{"pflushs", two(0xf000, 0x3c10), two(0xfff8, 0xfe00), "T3T9&s", m68851 }, +{"pflushs", two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9", m68851 }, +{"pflushs", two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s", m68851 }, +{"pflushs", two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9", m68851 }, +{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s", m68851 }, + +{"ploadr", two(0xf000, 0x2210), two(0xffc0, 0xfff0), "T3&s", m68030 | m68851 }, +{"ploadr", two(0xf000, 0x2208), two(0xffc0, 0xfff8), "D3&s", m68030 | m68851 }, +{"ploadr", two(0xf000, 0x2200), two(0xffc0, 0xfffe), "f3&s", m68030 | m68851 }, +{"ploadw", two(0xf000, 0x2010), two(0xffc0, 0xfff0), "T3&s", m68030 | m68851 }, +{"ploadw", two(0xf000, 0x2008), two(0xffc0, 0xfff8), "D3&s", m68030 | m68851 }, +{"ploadw", two(0xf000, 0x2000), two(0xffc0, 0xfffe), "f3&s", m68030 | m68851 }, + +/* TC, CRP, DRP, SRP, CAL, VAL, SCC, AC */ +{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "*sP8", m68030 | m68851 }, +{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "P8%s", m68030 | m68851 }, +{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "|sW8", m68030 | m68851 }, +{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "W8~s", m68030 | m68851 }, + +/* BADx, BACx */ +{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xe3e3), "*sX3", m68030 | m68851 }, +{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xe3e3), "X3%s", m68030 | m68851 }, + +/* PSR, PCSR */ +/* {"pmove", two(0xf000, 0x6100), two(oxffc0, oxffff), "*sZ8", m68030 | m68851 }, */ +{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xffff), "*sY8", m68030 | m68851 }, +{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xffff), "Y8%s", m68030 | m68851 }, +{"pmove", two(0xf000, 0x6600), two(0xffc0, 0xffff), "Z8%s", m68030 | m68851 }, + +{"prestore", one(0xf140), one(0xffc0), "&s", m68851 }, +{"prestore", one(0xf158), one(0xfff8), "+s", m68851 }, +{"psave", one(0xf100), one(0xffc0), "&s", m68851 }, +{"psave", one(0xf100), one(0xffc0), "+s", m68851 }, + +{"psac", two(0xf040, 0x0007), two(0xffc0, 0xffff), "@s", m68851 }, +{"psas", two(0xf040, 0x0006), two(0xffc0, 0xffff), "@s", m68851 }, +{"psbc", two(0xf040, 0x0001), two(0xffc0, 0xffff), "@s", m68851 }, +{"psbs", two(0xf040, 0x0000), two(0xffc0, 0xffff), "@s", m68851 }, +{"pscc", two(0xf040, 0x000f), two(0xffc0, 0xffff), "@s", m68851 }, +{"pscs", two(0xf040, 0x000e), two(0xffc0, 0xffff), "@s", m68851 }, +{"psgc", two(0xf040, 0x000d), two(0xffc0, 0xffff), "@s", m68851 }, +{"psgs", two(0xf040, 0x000c), two(0xffc0, 0xffff), "@s", m68851 }, +{"psic", two(0xf040, 0x000b), two(0xffc0, 0xffff), "@s", m68851 }, +{"psis", two(0xf040, 0x000a), two(0xffc0, 0xffff), "@s", m68851 }, +{"pslc", two(0xf040, 0x0003), two(0xffc0, 0xffff), "@s", m68851 }, +{"psls", two(0xf040, 0x0002), two(0xffc0, 0xffff), "@s", m68851 }, +{"pssc", two(0xf040, 0x0005), two(0xffc0, 0xffff), "@s", m68851 }, +{"psss", two(0xf040, 0x0004), two(0xffc0, 0xffff), "@s", m68851 }, +{"pswc", two(0xf040, 0x0009), two(0xffc0, 0xffff), "@s", m68851 }, +{"psws", two(0xf040, 0x0008), two(0xffc0, 0xffff), "@s", m68851 }, + +{"ptestr", two(0xf000, 0x8210), two(0xffc0, 0xe3f0), "T3&sQ8", m68030 | m68851 }, +{"ptestr", two(0xf000, 0x8310), two(0xffc0, 0xe310), "T3&sQ8A9", m68030 | m68851 }, +{"ptestr", two(0xf000, 0x8208), two(0xffc0, 0xe3f8), "D3&sQ8", m68030 | m68851 }, +{"ptestr", two(0xf000, 0x8308), two(0xffc0, 0xe318), "D3&sQ8A9", m68030 | m68851 }, +{"ptestr", two(0xf000, 0x8200), two(0xffc0, 0xe3fe), "f3&sQ8", m68030 | m68851 }, +{"ptestr", two(0xf000, 0x8300), two(0xffc0, 0xe31e), "f3&sQ8A9", m68030 | m68851 }, + +{"ptestr", one(0xf568), one(0xfff8), "As", m68040 }, + +{"ptestw", two(0xf000, 0x8010), two(0xffc0, 0xe3f0), "T3&sQ8", m68030 | m68851 }, +{"ptestw", two(0xf000, 0x8110), two(0xffc0, 0xe310), "T3&sQ8A9", m68030 | m68851 }, +{"ptestw", two(0xf000, 0x8008), two(0xffc0, 0xe3f8), "D3&sQ8", m68030 | m68851 }, +{"ptestw", two(0xf000, 0x8108), two(0xffc0, 0xe318), "D3&sQ8A9", m68030 | m68851 }, +{"ptestw", two(0xf000, 0x8000), two(0xffc0, 0xe3fe), "f3&sQ8", m68030 | m68851 }, +{"ptestw", two(0xf000, 0x8100), two(0xffc0, 0xe31e), "f3&sQ8A9", m68030 | m68851 }, + +{"ptestw", one(0xf548), one(0xfff8), "As", m68040 }, + +{"ptrapacw", two(0xf07a, 0x0007), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapacl", two(0xf07b, 0x0007), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapac", two(0xf07c, 0x0007), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapasw", two(0xf07a, 0x0006), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapasl", two(0xf07b, 0x0006), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapas", two(0xf07c, 0x0006), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapbcw", two(0xf07a, 0x0001), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapbcl", two(0xf07b, 0x0001), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapbc", two(0xf07c, 0x0001), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapbsw", two(0xf07a, 0x0000), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapbsl", two(0xf07b, 0x0000), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapbs", two(0xf07c, 0x0000), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapccw", two(0xf07a, 0x000f), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapccl", two(0xf07b, 0x000f), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapcc", two(0xf07c, 0x000f), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapcsw", two(0xf07a, 0x000e), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapcsl", two(0xf07b, 0x000e), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapcs", two(0xf07c, 0x000e), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapgcw", two(0xf07a, 0x000d), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapgcl", two(0xf07b, 0x000d), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapgc", two(0xf07c, 0x000d), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapgsw", two(0xf07a, 0x000c), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapgsl", two(0xf07b, 0x000c), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapgs", two(0xf07c, 0x000c), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapicw", two(0xf07a, 0x000b), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapicl", two(0xf07b, 0x000b), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapic", two(0xf07c, 0x000b), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapisw", two(0xf07a, 0x000a), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapisl", two(0xf07b, 0x000a), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapis", two(0xf07c, 0x000a), two(0xffff, 0xffff), "", m68851 }, + +{"ptraplcw", two(0xf07a, 0x0003), two(0xffff, 0xffff), "#w", m68851 }, +{"ptraplcl", two(0xf07b, 0x0003), two(0xffff, 0xffff), "#l", m68851 }, +{"ptraplc", two(0xf07c, 0x0003), two(0xffff, 0xffff), "", m68851 }, + +{"ptraplsw", two(0xf07a, 0x0002), two(0xffff, 0xffff), "#w", m68851 }, +{"ptraplsl", two(0xf07b, 0x0002), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapls", two(0xf07c, 0x0002), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapscw", two(0xf07a, 0x0005), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapscl", two(0xf07b, 0x0005), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapsc", two(0xf07c, 0x0005), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapssw", two(0xf07a, 0x0004), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapssl", two(0xf07b, 0x0004), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapss", two(0xf07c, 0x0004), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapwcw", two(0xf07a, 0x0009), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapwcl", two(0xf07b, 0x0009), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapwc", two(0xf07c, 0x0009), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapwsw", two(0xf07a, 0x0008), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapwsl", two(0xf07b, 0x0008), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapws", two(0xf07c, 0x0008), two(0xffff, 0xffff), "", m68851 }, + +{"pvalid", two(0xf000, 0x2800), two(0xffc0, 0xffff), "Vs&s", m68851 }, +{"pvalid", two(0xf000, 0x2c00), two(0xffc0, 0xfff8), "A3&s", m68851 }, + +#endif /* NO_68851 */ + +{"reset", one(0047160), one(0177777), "", m68000up }, + +{"rolb", one(0160430), one(0170770), "QdDs", m68000up }, /* rorb #Q, Ds */ +{"rolb", one(0160470), one(0170770), "DdDs", m68000up }, /* rorb Dd, Ds */ +{"roll", one(0160630), one(0170770), "QdDs", m68000up }, /* rorb #Q, Ds */ +{"roll", one(0160670), one(0170770), "DdDs", m68000up }, /* rorb Dd, Ds */ +{"rolw", one(0160530), one(0170770), "QdDs", m68000up }, /* rorb #Q, Ds */ +{"rolw", one(0160570), one(0170770), "DdDs", m68000up }, /* rorb Dd, Ds */ +{"rolw", one(0163700), one(0177700), "~s", m68000up }, /* Rotate memory */ +{"rorb", one(0160030), one(0170770), "QdDs", m68000up }, /* rorb #Q, Ds */ +{"rorb", one(0160070), one(0170770), "DdDs", m68000up }, /* rorb Dd, Ds */ +{"rorl", one(0160230), one(0170770), "QdDs", m68000up }, /* rorb #Q, Ds */ +{"rorl", one(0160270), one(0170770), "DdDs", m68000up }, /* rorb Dd, Ds */ +{"rorw", one(0160130), one(0170770), "QdDs", m68000up }, /* rorb #Q, Ds */ +{"rorw", one(0160170), one(0170770), "DdDs", m68000up }, /* rorb Dd, Ds */ +{"rorw", one(0163300), one(0177700), "~s", m68000up }, /* Rotate memory */ + +{"roxlb", one(0160420), one(0170770), "QdDs", m68000up }, /* roxrb #Q, Ds */ +{"roxlb", one(0160460), one(0170770), "DdDs", m68000up }, /* roxrb Dd, Ds */ +{"roxll", one(0160620), one(0170770), "QdDs", m68000up }, /* roxrb #Q, Ds */ +{"roxll", one(0160660), one(0170770), "DdDs", m68000up }, /* roxrb Dd, Ds */ +{"roxlw", one(0160520), one(0170770), "QdDs", m68000up }, /* roxrb #Q, Ds */ +{"roxlw", one(0160560), one(0170770), "DdDs", m68000up }, /* roxrb Dd, Ds */ +{"roxlw", one(0162700), one(0177700), "~s", m68000up }, /* Rotate memory */ +{"roxrb", one(0160020), one(0170770), "QdDs", m68000up }, /* roxrb #Q, Ds */ +{"roxrb", one(0160060), one(0170770), "DdDs", m68000up }, /* roxrb Dd, Ds */ +{"roxrl", one(0160220), one(0170770), "QdDs", m68000up }, /* roxrb #Q, Ds */ +{"roxrl", one(0160260), one(0170770), "DdDs", m68000up }, /* roxrb Dd, Ds */ +{"roxrw", one(0160120), one(0170770), "QdDs", m68000up }, /* roxrb #Q, Ds */ +{"roxrw", one(0160160), one(0170770), "DdDs", m68000up }, /* roxrb Dd, Ds */ +{"roxrw", one(0162300), one(0177700), "~s", m68000up }, /* Rotate memory */ + +{"rtd", one(0047164), one(0177777), "#w", m68010up }, +{"rte", one(0047163), one(0177777), "", m68000up }, +{"rtm", one(0003300), one(0177760), "Rs", m68020 }, +{"rtr", one(0047167), one(0177777), "", m68000up }, +{"rts", one(0047165), one(0177777), "", m68000up }, + +{"sbcd", one(0100400), one(0170770), "DsDd", m68000up }, +{"sbcd", one(0100410), one(0170770), "-s-d", m68000up }, + +{"scc", one(0052300), one(0177700), "$s", m68000up }, +{"scs", one(0052700), one(0177700), "$s", m68000up }, +{"seq", one(0053700), one(0177700), "$s", m68000up }, +{"sf", one(0050700), one(0177700), "$s", m68000up }, +{"sge", one(0056300), one(0177700), "$s", m68000up }, +{"sfge", one(0056300), one(0177700), "$s", m68000up }, +{"sgt", one(0057300), one(0177700), "$s", m68000up }, +{"sfgt", one(0057300), one(0177700), "$s", m68000up }, +{"shi", one(0051300), one(0177700), "$s", m68000up }, +{"sle", one(0057700), one(0177700), "$s", m68000up }, +{"sfle", one(0057700), one(0177700), "$s", m68000up }, +{"sls", one(0051700), one(0177700), "$s", m68000up }, +{"slt", one(0056700), one(0177700), "$s", m68000up }, +{"sflt", one(0056700), one(0177700), "$s", m68000up }, +{"smi", one(0055700), one(0177700), "$s", m68000up }, +{"sne", one(0053300), one(0177700), "$s", m68000up }, +{"sfneq", one(0053300), one(0177700), "$s", m68000up }, +{"spl", one(0055300), one(0177700), "$s", m68000up }, +{"st", one(0050300), one(0177700), "$s", m68000up }, +{"svc", one(0054300), one(0177700), "$s", m68000up }, +{"svs", one(0054700), one(0177700), "$s", m68000up }, + +{"stop", one(0047162), one(0177777), "#w", m68000up }, + +{"subal", one(0110700), one(0170700), "*lAd", m68000up }, +{"subaw", one(0110300), one(0170700), "*wAd", m68000up }, +{"subb", one(0050400), one(0170700), "Qd%s", m68000up }, /* subq written as sub */ +{"subb", one(0002000), one(0177700), "#b$s", m68000up }, /* subi written as sub */ +{"subb", one(0110000), one(0170700), ";bDd", m68000up }, /* subb ? ?, Dd */ +{"subb", one(0110400), one(0170700), "Dd~s", m68000up }, /* subb Dd, ? ? */ +{"subib", one(0002000), one(0177700), "#b$s", m68000up }, +{"subil", one(0002200), one(0177700), "#l$s", m68000up }, +{"subiw", one(0002100), one(0177700), "#w$s", m68000up }, +{"subl", one(0050600), one(0170700), "Qd%s", m68000up }, +{"subl", one(0002200), one(0177700), "#l$s", m68000up }, +{"subl", one(0110700), one(0170700), "*lAd", m68000up }, +{"subl", one(0110200), one(0170700), "*lDd", m68000up }, +{"subl", one(0110600), one(0170700), "Dd~s", m68000up }, +{"subqb", one(0050400), one(0170700), "Qd%s", m68000up }, +{"subql", one(0050600), one(0170700), "Qd%s", m68000up }, +{"subqw", one(0050500), one(0170700), "Qd%s", m68000up }, +{"subw", one(0050500), one(0170700), "Qd%s", m68000up }, +{"subw", one(0002100), one(0177700), "#w$s", m68000up }, +{"subw", one(0110100), one(0170700), "*wDd", m68000up }, +{"subw", one(0110300), one(0170700), "*wAd", m68000up }, /* suba written as sub */ +{"subw", one(0110500), one(0170700), "Dd~s", m68000up }, +{"subxb", one(0110400), one(0170770), "DsDd", m68000up }, /* subxb Ds, Dd */ +{"subxb", one(0110410), one(0170770), "-s-d", m68000up }, /* subxb -(As), -(Ad) */ +{"subxl", one(0110600), one(0170770), "DsDd", m68000up }, +{"subxl", one(0110610), one(0170770), "-s-d", m68000up }, +{"subxw", one(0110500), one(0170770), "DsDd", m68000up }, +{"subxw", one(0110510), one(0170770), "-s-d", m68000up }, + +{"swap", one(0044100), one(0177770), "Ds", m68000up }, + +{"tas", one(0045300), one(0177700), "$s", m68000up }, +{"trap", one(0047100), one(0177760), "Ts", m68000up }, + +{"trapcc", one(0052374), one(0177777), "", m68020up }, +{"trapcs", one(0052774), one(0177777), "", m68020up }, +{"trapeq", one(0053774), one(0177777), "", m68020up }, +{"trapf", one(0050774), one(0177777), "", m68020up }, +{"trapge", one(0056374), one(0177777), "", m68020up }, +{"trapgt", one(0057374), one(0177777), "", m68020up }, +{"traphi", one(0051374), one(0177777), "", m68020up }, +{"traple", one(0057774), one(0177777), "", m68020up }, +{"trapls", one(0051774), one(0177777), "", m68020up }, +{"traplt", one(0056774), one(0177777), "", m68020up }, +{"trapmi", one(0055774), one(0177777), "", m68020up }, +{"trapne", one(0053374), one(0177777), "", m68020up }, +{"trappl", one(0055374), one(0177777), "", m68020up }, +{"trapt", one(0050374), one(0177777), "", m68020up }, +{"trapvc", one(0054374), one(0177777), "", m68020up }, +{"trapvs", one(0054774), one(0177777), "", m68020up }, + +{"trapcc.w", one(0052372), one(0177777), "", m68020up }, +{"trapcs.w", one(0052772), one(0177777), "", m68020up }, +{"trapeq.w", one(0053772), one(0177777), "", m68020up }, +{"trapf.w", one(0050772), one(0177777), "", m68020up }, +{"trapge.w", one(0056372), one(0177777), "", m68020up }, +{"trapgt.w", one(0057372), one(0177777), "", m68020up }, +{"traphi.w", one(0051372), one(0177777), "", m68020up }, +{"traple.w", one(0057772), one(0177777), "", m68020up }, +{"trapls.w", one(0051772), one(0177777), "", m68020up }, +{"traplt.w", one(0056772), one(0177777), "", m68020up }, +{"trapmi.w", one(0055772), one(0177777), "", m68020up }, +{"trapne.w", one(0053372), one(0177777), "", m68020up }, +{"trappl.w", one(0055372), one(0177777), "", m68020up }, +{"trapt.w", one(0050372), one(0177777), "", m68020up }, +{"trapvc.w", one(0054372), one(0177777), "", m68020up }, +{"trapvs.w", one(0054772), one(0177777), "", m68020up }, + +{"trapcc.l", one(0052373), one(0177777), "", m68020up }, +{"trapcs.l", one(0052773), one(0177777), "", m68020up }, +{"trapeq.l", one(0053773), one(0177777), "", m68020up }, +{"trapf.l", one(0050773), one(0177777), "", m68020up }, +{"trapge.l", one(0056373), one(0177777), "", m68020up }, +{"trapgt.l", one(0057373), one(0177777), "", m68020up }, +{"traphi.l", one(0051373), one(0177777), "", m68020up }, +{"traple.l", one(0057773), one(0177777), "", m68020up }, +{"trapls.l", one(0051773), one(0177777), "", m68020up }, +{"traplt.l", one(0056773), one(0177777), "", m68020up }, +{"trapmi.l", one(0055773), one(0177777), "", m68020up }, +{"trapne.l", one(0053373), one(0177777), "", m68020up }, +{"trappl.l", one(0055373), one(0177777), "", m68020up }, +{"trapt.l", one(0050373), one(0177777), "", m68020up }, +{"trapvc.l", one(0054373), one(0177777), "", m68020up }, +{"trapvs.l", one(0054773), one(0177777), "", m68020up }, + +{"trapv", one(0047166), one(0177777), "", m68000up }, + +{"tstb", one(0045000), one(0177700), ";b", m68000up }, +{"tstw", one(0045100), one(0177700), "*w", m68000up }, +{"tstl", one(0045200), one(0177700), "*l", m68000up }, + +{"unlk", one(0047130), one(0177770), "As", m68000up }, +{"unpk", one(0100600), one(0170770), "DsDd#w", m68020up }, +{"unpk", one(0100610), one(0170770), "-s-d#w", m68020up }, + +/* Variable-sized branches */ + +{"jbsr", one(0060400), one(0177400), "Bg", m68000up }, +{"jbsr", one(0047200), one(0177700), "!s", m68000up }, +{"jra", one(0060000), one(0177400), "Bg", m68000up }, +{"jra", one(0047300), one(0177700), "!s", m68000up }, + +{"jhi", one(0061000), one(0177400), "Bg", m68000up }, +{"jls", one(0061400), one(0177400), "Bg", m68000up }, +{"jcc", one(0062000), one(0177400), "Bg", m68000up }, +{"jfnlt", one(0062000), one(0177400), "Bg", m68000up }, /* apparently a sun alias */ +{"jcs", one(0062400), one(0177400), "Bg", m68000up }, +{"jne", one(0063000), one(0177400), "Bg", m68000up }, +{"jeq", one(0063400), one(0177400), "Bg", m68000up }, +{"jfeq", one(0063400), one(0177400), "Bg", m68000up }, /* apparently a sun alias */ +{"jvc", one(0064000), one(0177400), "Bg", m68000up }, +{"jvs", one(0064400), one(0177400), "Bg", m68000up }, +{"jpl", one(0065000), one(0177400), "Bg", m68000up }, +{"jmi", one(0065400), one(0177400), "Bg", m68000up }, +{"jge", one(0066000), one(0177400), "Bg", m68000up }, +{"jlt", one(0066400), one(0177400), "Bg", m68000up }, +{"jgt", one(0067000), one(0177400), "Bg", m68000up }, +{"jle", one(0067400), one(0177400), "Bg", m68000up }, +{"jfngt", one(0067400), one(0177400), "Bg", m68000up }, /* apparently a sun alias */ + +/* aliases */ + +{"movql", one(0070000), one(0170400), "MsDd", m68000up }, +{"moveql", one(0070000), one(0170400), "MsDd", m68000up }, +{"moval", one(0020100), one(0170700), "*lAd", m68000up }, +{"movaw", one(0030100), one(0170700), "*wAd", m68000up }, +{"movb", one(0010000), one(0170000), ";b$d", m68000up }, /* mov */ +{"movl", one(0070000), one(0170400), "MsDd", m68000up }, /* movq written as mov */ +{"movl", one(0020000), one(0170000), "*l$d", m68000up }, +{"movl", one(0020100), one(0170700), "*lAd", m68000up }, +{"movl", one(0047140), one(0177770), "AsUd", m68000up }, /* mov to USP */ +{"movl", one(0047150), one(0177770), "UdAs", m68000up }, /* mov from USP */ +{"movc", one(0047173), one(0177777), "R1Jj", m68010up }, +{"movc", one(0047173), one(0177777), "R1#j", m68010up }, +{"movc", one(0047172), one(0177777), "JjR1", m68010up }, +{"movc", one(0047172), one(0177777), "#jR1", m68010up }, +{"movml", one(0044300), one(0177700), "#w&s", m68000up }, /* movm reg to mem. */ +{"movml", one(0044340), one(0177770), "#w-s", m68000up }, /* movm reg to autodecrement. */ +{"movml", one(0046300), one(0177700), "!s#w", m68000up }, /* movm mem to reg. */ +{"movml", one(0046330), one(0177770), "+s#w", m68000up }, /* movm autoinc to reg. */ +{"movml", one(0044300), one(0177700), "Lw&s", m68000up }, /* movm reg to mem. */ +{"movml", one(0044340), one(0177770), "lw-s", m68000up }, /* movm reg to autodecrement. */ +{"movml", one(0046300), one(0177700), "!sLw", m68000up }, /* movm mem to reg. */ +{"movml", one(0046330), one(0177770), "+sLw", m68000up }, /* movm autoinc to reg. */ +{"movmw", one(0044200), one(0177700), "#w&s", m68000up }, /* movm reg to mem. */ +{"movmw", one(0044240), one(0177770), "#w-s", m68000up }, /* movm reg to autodecrement. */ +{"movmw", one(0046200), one(0177700), "!s#w", m68000up }, /* movm mem to reg. */ +{"movmw", one(0046230), one(0177770), "+s#w", m68000up }, /* movm autoinc to reg. */ +{"movmw", one(0044200), one(0177700), "Lw&s", m68000up }, /* movm reg to mem. */ +{"movmw", one(0044240), one(0177770), "lw-s", m68000up }, /* movm reg to autodecrement. */ +{"movmw", one(0046200), one(0177700), "!sLw", m68000up }, /* movm mem to reg. */ +{"movmw", one(0046230), one(0177770), "+sLw", m68000up }, /* movm autoinc to reg. */ +{"movpl", one(0000510), one(0170770), "dsDd", m68000up }, /* memory to register */ +{"movpl", one(0000710), one(0170770), "Ddds", m68000up }, /* register to memory */ +{"movpw", one(0000410), one(0170770), "dsDd", m68000up }, /* memory to register */ +{"movpw", one(0000610), one(0170770), "Ddds", m68000up }, /* register to memory */ +{"movq", one(0070000), one(0170400), "MsDd", m68000up }, +{"movw", one(0030000), one(0170000), "*w$d", m68000up }, +{"movw", one(0030100), one(0170700), "*wAd", m68000up }, /* mova, written as mov */ +{"movw", one(0040300), one(0177700), "Ss$s", m68000up }, /* Move from sr */ +{"movw", one(0041300), one(0177700), "Cs$s", m68010up }, /* Move from ccr */ +{"movw", one(0042300), one(0177700), ";wCd", m68000up }, /* mov to ccr */ +{"movw", one(0043300), one(0177700), ";wSd", m68000up }, /* mov to sr */ + +{"movsb", two(0007000, 0), two(0177700, 07777), "~sR1", m68010up }, +{"movsb", two(0007000, 04000), two(0177700, 07777), "R1~s", m68010up }, +{"movsl", two(0007200, 0), two(0177700, 07777), "~sR1", m68010up }, +{"movsl", two(0007200, 04000), two(0177700, 07777), "R1~s", m68010up }, +{"movsw", two(0007100, 0), two(0177700, 07777), "~sR1", m68010up }, +{"movsw", two(0007100, 04000), two(0177700, 07777), "R1~s", m68010up }, + +}; + +int numopcodes=sizeof(m68k_opcodes)/sizeof(m68k_opcodes[0]); + +struct m68k_opcode *endop = m68k_opcodes+sizeof(m68k_opcodes)/sizeof(m68k_opcodes[0]); + +/* + * Local Variables: + * fill-column: 131 + * End: + */ + +/* end of m68k-opcode.h */ diff --git a/gnu/usr.bin/as/opcode/m88k.h b/gnu/usr.bin/as/opcode/m88k.h new file mode 100644 index 000000000000..5f685b90fc83 --- /dev/null +++ b/gnu/usr.bin/as/opcode/m88k.h @@ -0,0 +1,282 @@ +/* m88k-opcode.h -- Instruction information for the Motorola 88000 + Contributed by Devon Bowen of Buffalo University + and Torbjorn Granlund of the Swedish Institute of Computer Science. + Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined(__STDC__) && !defined(const) +#define const +#endif + +/* + Character codes for op_spec field below. + Reserved for direct matching: x , [ ] + + d = GRF Destination register (21:5) + 1 = Source register 1 (16:5) + 2 = Source register 2 (0:5) + 3 = Both source registers (same value) (0:5 and 16:5) + I = IMM16 (0:16) + b = bit field spec. (0:10) + p = 16 bit pc displ. (0:16) + P = 26 bit pc displ. (0:26) + B = bb0/bb1 condition (21:5) + M = bcnd condition (21:5) + f = fcr (5:6) + c = cr (5:6) + V = VEC9 (0:9) + ? = Give warning for this insn/operand combination + */ + +/* instruction descriptor structure */ + +struct m88k_opcode +{ + unsigned int opcode; + char *name; + char *op_spec; +}; + +/* and introducing... the Motorola 88100 instruction sets... */ + +/* These macros may seem silly, but they are in preparation + for future versions of the 88000 family. */ + +#define _MC88100(OPCODE,MNEM,OP_SPEC) {OPCODE,MNEM,OP_SPEC}, +#define _MC88xxx(OPCODE,MNEM,OP_SPEC) {OPCODE,MNEM,OP_SPEC}, + +/* Equal mnemonics must be adjacent. + More specific operand specification must go before more general. + For example, "d,1,2" must go before "d,1,I" as a register for s2 + would otherwise be considered a variable name. */ + +static struct m88k_opcode m88k_opcodes[] = +{ + /* Opcode Mnemonic Opspec */ + + _MC88xxx(0xf4007000, "add", "d,1,2") + _MC88xxx(0x70000000, "add", "d,1,I") + _MC88xxx(0xf4007200, "add.ci", "d,1,2") + _MC88xxx(0xf4007300, "add.cio", "d,1,2") + _MC88xxx(0xf4007100, "add.co", "d,1,2") + _MC88xxx(0xf4006000, "addu", "d,1,2") + _MC88xxx(0x60000000, "addu", "d,1,I") + _MC88xxx(0xf4006200, "addu.ci", "d,1,2") + _MC88xxx(0xf4006300, "addu.cio", "d,1,2") + _MC88xxx(0xf4006100, "addu.co", "d,1,2") + _MC88xxx(0xf4004000, "and", "d,1,2") + _MC88xxx(0x40000000, "and", "d,1,I") + _MC88xxx(0xf4004400, "and.c", "d,1,2") + _MC88xxx(0x44000000, "and.u", "d,1,I") + _MC88xxx(0xd0000000, "bb0", "B,1,p") + _MC88xxx(0xd4000000, "bb0.n", "B,1,p") + _MC88xxx(0xd8000000, "bb1", "B,1,p") + _MC88xxx(0xdc000000, "bb1.n", "B,1,p") + _MC88xxx(0xe8000000, "bcnd", "M,1,p") + _MC88xxx(0xec000000, "bcnd.n", "M,1,p") + _MC88xxx(0xc0000000, "br", "P") + _MC88xxx(0xc4000000, "br.n", "P") + _MC88xxx(0xc8000000, "bsr", "P") + _MC88xxx(0xcc000000, "bsr.n", "P") + _MC88xxx(0xf4008000, "clr", "d,1,2") + _MC88xxx(0xf0008000, "clr", "d,1,b") + _MC88xxx(0xf4007c00, "cmp", "d,1,2") + _MC88xxx(0x7c000000, "cmp", "d,1,I") + _MC88xxx(0xf4007800, "div", "d,1,2") + _MC88xxx(0x78000000, "div", "d,1,I") + _MC88xxx(0xf4007800, "divs", "d,1,2") + _MC88xxx(0x78000000, "divs", "d,1,I") + _MC88xxx(0xf4006800, "divu", "d,1,2") + _MC88xxx(0x68000000, "divu", "d,1,I") + _MC88xxx(0xf4009000, "ext", "d,1,2") + _MC88xxx(0xf0009000, "ext", "d,1,b") + _MC88xxx(0xf4009800, "extu", "d,1,2") + _MC88xxx(0xf0009800, "extu", "d,1,b") + _MC88xxx(0x84002800, "fadd.sss", "d,1,2") + _MC88xxx(0x84002880, "fadd.ssd", "d,1,2") + _MC88xxx(0x84002a00, "fadd.sds", "d,1,2") + _MC88xxx(0x84002a80, "fadd.sdd", "d,1,2") + _MC88xxx(0x84002820, "fadd.dss", "d,1,2") + _MC88xxx(0x840028a0, "fadd.dsd", "d,1,2") + _MC88xxx(0x84002a20, "fadd.dds", "d,1,2") + _MC88xxx(0x84002aa0, "fadd.ddd", "d,1,2") + _MC88xxx(0x84003a80, "fcmp.sdd", "d,1,2") + _MC88xxx(0x84003a00, "fcmp.sds", "d,1,2") + _MC88xxx(0x84003880, "fcmp.ssd", "d,1,2") + _MC88xxx(0x84003800, "fcmp.sss", "d,1,2") + _MC88xxx(0x84007000, "fdiv.sss", "d,1,2") + _MC88xxx(0x84007080, "fdiv.ssd", "d,1,2") + _MC88xxx(0x84007200, "fdiv.sds", "d,1,2") + _MC88xxx(0x84007280, "fdiv.sdd", "d,1,2") + _MC88xxx(0x84007020, "fdiv.dss", "d,1,2") + _MC88xxx(0x840070a0, "fdiv.dsd", "d,1,2") + _MC88xxx(0x84007220, "fdiv.dds", "d,1,2") + _MC88xxx(0x840072a0, "fdiv.ddd", "d,1,2") + _MC88xxx(0xf400ec00, "ff0", "d,2") + _MC88xxx(0xf400e800, "ff1", "d,2") + _MC88xxx(0x80004800, "fldcr", "d,f") + _MC88xxx(0x84002020, "flt.ds", "d,2") + _MC88xxx(0x84002000, "flt.ss", "d,2") + _MC88xxx(0x84000000, "fmul.sss", "d,1,2") + _MC88xxx(0x84000080, "fmul.ssd", "d,1,2") + _MC88xxx(0x84000200, "fmul.sds", "d,1,2") + _MC88xxx(0x84000280, "fmul.sdd", "d,1,2") + _MC88xxx(0x84000020, "fmul.dss", "d,1,2") + _MC88xxx(0x840000a0, "fmul.dsd", "d,1,2") + _MC88xxx(0x84000220, "fmul.dds", "d,1,2") + _MC88xxx(0x840002a0, "fmul.ddd", "d,1,2") + _MC88xxx(0x80008800, "fstcr", "3,f") + _MC88xxx(0x84003000, "fsub.sss", "d,1,2") + _MC88xxx(0x84003080, "fsub.ssd", "d,1,2") + _MC88xxx(0x84003200, "fsub.sds", "d,1,2") + _MC88xxx(0x84003280, "fsub.sdd", "d,1,2") + _MC88xxx(0x84003020, "fsub.dss", "d,1,2") + _MC88xxx(0x840030a0, "fsub.dsd", "d,1,2") + _MC88xxx(0x84003220, "fsub.dds", "d,1,2") + _MC88xxx(0x840032a0, "fsub.ddd", "d,1,2") + _MC88xxx(0x8000c800, "fxcr", "d,3,f") + _MC88xxx(0x8400fc01, "illop1", "") + _MC88xxx(0x8400fc02, "illop2", "") + _MC88xxx(0x8400fc03, "illop3", "") + _MC88xxx(0x84004880, "int.sd", "d,2") + _MC88xxx(0x84004800, "int.ss", "d,2") + _MC88xxx(0xf400c000, "jmp", "2") + _MC88xxx(0xf400c400, "jmp.n", "2") + _MC88xxx(0xf400c800, "jsr", "2") + _MC88xxx(0xf400cc00, "jsr.n", "2") + _MC88xxx(0xf4001400, "ld", "d,1,2") + _MC88xxx(0xf4001600, "ld", "d,1[2]") + _MC88xxx(0x14000000, "ld", "d,1,I") + _MC88xxx(0xf4001e00, "ld.b", "d,1[2]") + _MC88xxx(0xf4001c00, "ld.b", "d,1,2") + _MC88xxx(0x1c000000, "ld.b", "d,1,I") + _MC88xxx(0xf4001d00, "ld.b.usr", "d,1,2") + _MC88xxx(0xf4001f00, "ld.b.usr", "d,1[2]") + _MC88xxx(0xf4000e00, "ld.bu", "d,1[2]") + _MC88xxx(0xf4000c00, "ld.bu", "d,1,2") + _MC88xxx(0x0c000000, "ld.bu", "d,1,I") + _MC88xxx(0xf4000d00, "ld.bu.usr", "d,1,2") + _MC88xxx(0xf4000f00, "ld.bu.usr", "d,1[2]") + _MC88xxx(0xf4001200, "ld.d", "d,1[2]") + _MC88xxx(0xf4001000, "ld.d", "d,1,2") + _MC88xxx(0x10000000, "ld.d", "d,1,I") + _MC88xxx(0xf4001100, "ld.d.usr", "d,1,2") + _MC88xxx(0xf4001300, "ld.d.usr", "d,1[2]") + _MC88xxx(0xf4001a00, "ld.h", "d,1[2]") + _MC88xxx(0xf4001800, "ld.h", "d,1,2") + _MC88xxx(0x18000000, "ld.h", "d,1,I") + _MC88xxx(0xf4001900, "ld.h.usr", "d,1,2") + _MC88xxx(0xf4001b00, "ld.h.usr", "d,1[2]") + _MC88xxx(0xf4000a00, "ld.hu", "d,1[2]") + _MC88xxx(0xf4000800, "ld.hu", "d,1,2") + _MC88xxx(0x08000000, "ld.hu", "d,1,I") + _MC88xxx(0xf4000900, "ld.hu.usr", "d,1,2") + _MC88xxx(0xf4000b00, "ld.hu.usr", "d,1[2]") + _MC88xxx(0xf4001500, "ld.usr", "d,1,2") + _MC88xxx(0xf4001700, "ld.usr", "d,1[2]") + _MC88xxx(0xf4003600, "lda", "d,1[2]") + _MC88xxx(0xf4006000, "lda", "?d,1,2") /* Output addu */ + _MC88xxx(0x60000000, "lda", "?d,1,I") /* Output addu */ + _MC88xxx(0xf4006000, "lda.b", "?d,1[2]") /* Output addu */ + _MC88xxx(0xf4006000, "lda.b", "?d,1,2") /* Output addu */ + _MC88xxx(0x60000000, "lda.b", "?d,1,I") /* Output addu */ + _MC88xxx(0xf4003200, "lda.d", "d,1[2]") + _MC88xxx(0xf4006000, "lda.d", "?d,1,2") /* Output addu */ + _MC88xxx(0x60000000, "lda.d", "?d,1,I") /* Output addu */ + _MC88xxx(0xf4003a00, "lda.h", "d,1[2]") + _MC88xxx(0xf4006000, "lda.h", "?d,1,2") /* Output addu */ + _MC88xxx(0x60000000, "lda.h", "?d,1,I") /* Output addu */ + _MC88xxx(0x80004000, "ldcr", "d,c") + _MC88xxx(0xf400a000, "mak", "d,1,2") + _MC88xxx(0xf000a000, "mak", "d,1,b") + _MC88xxx(0x48000000, "mask", "d,1,I") + _MC88xxx(0x4c000000, "mask.u", "d,1,I") + _MC88xxx(0xf4006c00, "mul", "d,1,2") + _MC88xxx(0x6c000000, "mul", "d,1,I") + _MC88xxx(0xf4006c00, "mulu", "d,1,2") /* synonym for mul */ + _MC88xxx(0x6c000000, "mulu", "d,1,I") /* synonym for mul */ + _MC88xxx(0x84005080, "nint.sd", "d,2") + _MC88xxx(0x84005000, "nint.ss", "d,2") + _MC88xxx(0xf4005800, "or", "d,1,2") + _MC88xxx(0x58000000, "or", "d,1,I") + _MC88xxx(0xf4005c00, "or.c", "d,1,2") + _MC88xxx(0x5c000000, "or.u", "d,1,I") + _MC88xxx(0xf000a800, "rot", "d,1,b") + _MC88xxx(0xf400a800, "rot", "d,1,2") + _MC88xxx(0xf400fc00, "rte", "") + _MC88xxx(0xf4008800, "set", "d,1,2") + _MC88xxx(0xf0008800, "set", "d,1,b") + _MC88xxx(0xf4002600, "st", "d,1[2]") + _MC88xxx(0xf4002400, "st", "d,1,2") + _MC88xxx(0x24000000, "st", "d,1,I") + _MC88xxx(0xf4002e00, "st.b", "d,1[2]") + _MC88xxx(0xf4002c00, "st.b", "d,1,2") + _MC88xxx(0x2c000000, "st.b", "d,1,I") + _MC88xxx(0xf4002d00, "st.b.usr", "d,1,2") + _MC88xxx(0xf4002f00, "st.b.usr", "d,1[2]") + _MC88xxx(0xf4002200, "st.d", "d,1[2]") + _MC88xxx(0xf4002000, "st.d", "d,1,2") + _MC88xxx(0x20000000, "st.d", "d,1,I") + _MC88xxx(0xf4002100, "st.d.usr", "d,1,2") + _MC88xxx(0xf4002300, "st.d.usr", "d,1[2]") + _MC88xxx(0xf4002a00, "st.h", "d,1[2]") + _MC88xxx(0xf4002800, "st.h", "d,1,2") + _MC88xxx(0x28000000, "st.h", "d,1,I") + _MC88xxx(0xf4002900, "st.h.usr", "d,1,2") + _MC88xxx(0xf4002b00, "st.h.usr", "d,1[2]") + _MC88xxx(0xf4002500, "st.usr", "d,1,2") + _MC88xxx(0xf4002700, "st.usr", "d,1[2]") + _MC88xxx(0x80008000, "stcr", "3,c") + _MC88xxx(0xf4007400, "sub", "d,1,2") + _MC88xxx(0x74000000, "sub", "d,1,I") + _MC88xxx(0xf4007600, "sub.ci", "d,1,2") + _MC88xxx(0xf4007700, "sub.cio", "d,1,2") + _MC88xxx(0xf4007500, "sub.co", "d,1,2") + _MC88xxx(0xf4006400, "subu", "d,1,2") + _MC88xxx(0x64000000, "subu", "d,1,I") + _MC88xxx(0xf4006600, "subu.ci", "d,1,2") + _MC88xxx(0xf4006700, "subu.cio", "d,1,2") + _MC88xxx(0xf4006500, "subu.co", "d,1,2") + _MC88xxx(0xf000d000, "tb0", "B,1,V") + _MC88xxx(0xf000d800, "tb1", "B,1,V") + _MC88xxx(0xf400f800, "tbnd", "1,2") + _MC88xxx(0xf8000000, "tbnd", "1,I") + _MC88xxx(0xf000e800, "tcnd", "M,1,V") + _MC88xxx(0x84005880, "trnc.sd", "d,2") + _MC88xxx(0x84005800, "trnc.ss", "d,2") + _MC88xxx(0x8000c000, "xcr", "d,1,c") + _MC88xxx(0xf4000600, "xmem", "d,1[2]") + _MC88xxx(0xf4000400, "xmem", "d,1,2") + _MC88100(0x04000000, "xmem", "?d,1,I") + _MC88xxx(0xf4000200, "xmem.bu", "d,1[2]") + _MC88xxx(0xf4000000, "xmem.bu", "d,1,2") + _MC88100(0x00000000, "xmem.bu", "?d,1,I") + _MC88xxx(0xf4000300, "xmem.bu.usr", "d,1[2]") + _MC88xxx(0xf4000100, "xmem.bu.usr", "d,1,2") + _MC88100(0x00000100, "xmem.bu.usr", "?d,1,I") + _MC88xxx(0xf4000700, "xmem.usr", "d,1[2]") + _MC88xxx(0xf4000500, "xmem.usr", "d,1,2") + _MC88100(0x04000100, "xmem.usr", "?d,1,I") + _MC88xxx(0xf4005000, "xor", "d,1,2") + _MC88xxx(0x50000000, "xor", "d,1,I") + _MC88xxx(0xf4005400, "xor.c", "d,1,2") + _MC88xxx(0x54000000, "xor.u", "d,1,I") + _MC88xxx(0x00000000, "", 0) +}; + +#define NUMOPCODES ((sizeof m88k_opcodes)/(sizeof m88k_opcodes[0])) diff --git a/gnu/usr.bin/as/opcode/mips.h b/gnu/usr.bin/as/opcode/mips.h new file mode 100644 index 000000000000..a65678a941da --- /dev/null +++ b/gnu/usr.bin/as/opcode/mips.h @@ -0,0 +1,363 @@ +/* Mips opcde list for GDB, the GNU debugger. + Copyright (C) 1989 Free Software Foundation, Inc. + Contributed by Nobuyuki Hikichi(hikichi@sra.junet) + Made to work for little-endian machines, and debugged + by Per Bothner (bothner@cs.wisc.edu). + Many fixes contributed by Frank Yellin (fy@lucid.com). + +This file is part of GDB. + +GDB is free software; you can 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 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if BITS_BIG_ENDIAN +#define BIT_FIELDS_2(a,b) a;b; +#define BIT_FIELDS_4(a,b,c,d) a;b;c;d; +#define BIT_FIELDS_6(a,b,c,d,e,f) a;b;c;d;e;f; +#else +#define BIT_FIELDS_2(a,b) b;a; +#define BIT_FIELDS_4(a,b,c,d) d;c;b;a; +#define BIT_FIELDS_6(a,b,c,d,e,f) f;e;d;c;b;a; +#endif + +struct op_i_fmt +{ +BIT_FIELDS_4( + unsigned op : 6, + unsigned rs : 5, + unsigned rt : 5, + unsigned immediate : 16) +}; + +struct op_j_fmt +{ +BIT_FIELDS_2( + unsigned op : 6, + unsigned target : 26) +}; + +struct op_r_fmt +{ +BIT_FIELDS_6( + unsigned op : 6, + unsigned rs : 5, + unsigned rt : 5, + unsigned rd : 5, + unsigned shamt : 5, + unsigned funct : 6) +}; + + +struct fop_i_fmt +{ +BIT_FIELDS_4( + unsigned op : 6, + unsigned rs : 5, + unsigned rt : 5, + unsigned immediate : 16) +}; + +struct op_b_fmt +{ +BIT_FIELDS_4( + unsigned op : 6, + unsigned rs : 5, + unsigned rt : 5, + short delta : 16) +}; + +struct fop_r_fmt +{ +BIT_FIELDS_6( + unsigned op : 6, + unsigned fmt : 5, + unsigned ft : 5, + unsigned fs : 5, + unsigned fd : 5, + unsigned funct : 6) +}; + +struct mips_opcode +{ + char *name; + unsigned long opcode; + unsigned long match; + char *args; + int bdelay; /* Nonzero if delayed branch. */ +}; + +/* args format; + + "s" rs: source register specifier + "t" rt: target register + "i" immediate + "a" target address + "c" branch condition + "d" rd: destination register specifier + "h" shamt: shift amount + "f" funct: function field + + for fpu + "S" fs source 1 register + "T" ft source 2 register + "D" distination register +*/ + +#define one(x) (x << 26) +#define op_func(x, y) ((x << 26) | y) +#define op_cond(x, y) ((x << 26) | (y << 16)) +#define op_rs_func(x, y, z) ((x << 26) | (y << 21) | z) +#define op_rs_b11(x, y, z) ((x << 26) | (y << 21) | z) +#define op_o16(x, y) ((x << 26) | (y << 16)) +#define op_bc(x, y, z) ((x << 26) | (y << 21) | (z << 16)) + +struct mips_opcode mips_opcodes[] = +{ +/* These first opcodes are special cases of the ones in the comments */ + {"nop", 0, 0xffffffff, /*li*/ "", 0}, + {"li", op_bc(9,0,0), op_bc(0x3f,31,0), /*addiu*/ "t,j", 0}, + {"b", one(4), 0xffff0000, /*beq*/ "b", 1}, + {"move", op_func(0, 33), op_cond(0x3f,31)|0x7ff,/*addu*/ "d,s", 0}, + + {"sll", op_func(0, 0), op_func(0x3f, 0x3f), "d,t,h", 0}, + {"srl", op_func(0, 2), op_func(0x3f, 0x3f), "d,t,h", 0}, + {"sra", op_func(0, 3), op_func(0x3f, 0x3f), "d,t,h", 0}, + {"sllv", op_func(0, 4), op_func(0x3f, 0x7ff), "d,t,s", 0}, + {"srlv", op_func(0, 6), op_func(0x3f, 0x7ff), "d,t,s", 0}, + {"srav", op_func(0, 7), op_func(0x3f, 0x7ff), "d,t,s", 0}, + {"jr", op_func(0, 8), op_func(0x3f, 0x1fffff), "s", 1}, + {"jalr", op_func(0, 9), op_func(0x3f, 0x1f07ff), "d,s", 1}, + {"syscall", op_func(0, 12), op_func(0x3f, 0x3f), "", 0}, + {"break", op_func(0, 13), op_func(0x3f, 0x3f), "", 0}, + {"mfhi", op_func(0, 16), op_func(0x3f, 0x03ff07ff), "d", 0}, + {"mthi", op_func(0, 17), op_func(0x3f, 0x1fffff), "s", 0}, + {"mflo", op_func(0, 18), op_func(0x3f, 0x03ff07ff), "d", 0}, + {"mtlo", op_func(0, 19), op_func(0x3f, 0x1fffff), "s", 0}, + {"mult", op_func(0, 24), op_func(0x3f, 0xffff), "s,t", 0}, + {"multu", op_func(0, 25), op_func(0x3f, 0xffff), "s,t", 0}, + {"div", op_func(0, 26), op_func(0x3f, 0xffff), "s,t", 0}, + {"divu", op_func(0, 27), op_func(0x3f, 0xffff), "s,t", 0}, + {"add", op_func(0, 32), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"addu", op_func(0, 33), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"sub", op_func(0, 34), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"subu", op_func(0, 35), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"and", op_func(0, 36), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"or", op_func(0, 37), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"xor", op_func(0, 38), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"nor", op_func(0, 39), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"slt", op_func(0, 42), op_func(0x3f, 0x7ff), "d,s,t", 0}, + {"sltu", op_func(0, 43), op_func(0x3f, 0x7ff), "d,s,t", 0}, + + {"bltz", op_cond (1, 0), op_cond(0x3f, 0x1f), "s,b", 1}, + {"bgez", op_cond (1, 1), op_cond(0x3f, 0x1f), "s,b", 1}, + {"bltzal", op_cond (1, 16),op_cond(0x3f, 0x1f), "s,b", 1}, + {"bgezal", op_cond (1, 17),op_cond(0x3f, 0x1f), "s,b", 1}, + + + {"j", one(2), one(0x3f), "a", 1}, + {"jal", one(3), one(0x3f), "a", 1}, + {"beq", one(4), one(0x3f), "s,t,b", 1}, + {"bne", one(5), one(0x3f), "s,t,b", 1}, + {"blez", one(6), one(0x3f) | 0x1f0000, "s,b", 1}, + {"bgtz", one(7), one(0x3f) | 0x1f0000, "s,b", 1}, + {"addi", one(8), one(0x3f), "t,s,j", 0}, + {"addiu", one(9), one(0x3f), "t,s,j", 0}, + {"slti", one(10), one(0x3f), "t,s,j", 0}, + {"sltiu", one(11), one(0x3f), "t,s,j", 0}, + {"andi", one(12), one(0x3f), "t,s,i", 0}, + {"ori", one(13), one(0x3f), "t,s,i", 0}, + {"xori", one(14), one(0x3f), "t,s,i", 0}, + /* rs field is don't care field? */ + {"lui", one(15), one(0x3f), "t,i", 0}, + +/* co processor 0 instruction */ + {"mfc0", op_rs_b11 (16, 0, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"cfc0", op_rs_b11 (16, 2, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"mtc0", op_rs_b11 (16, 4, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"ctc0", op_rs_b11 (16, 6, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + + {"bc0f", op_o16(16, 0x100), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc0f", op_o16(16, 0x180), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc0t", op_o16(16, 0x101), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc0t", op_o16(16, 0x181), op_o16(0x3f, 0x3ff), "b", 1}, + + {"tlbr", op_rs_func(16, 0x10, 1), ~0, "", 0}, + {"tlbwi", op_rs_func(16, 0x10, 2), ~0, "", 0}, + {"tlbwr", op_rs_func(16, 0x10, 6), ~0, "", 0}, + {"tlbp", op_rs_func(16, 0x10, 8), ~0, "", 0}, + {"rfe", op_rs_func(16, 0x10, 16), ~0, "", 0}, + + {"mfc1", op_rs_b11 (17, 0, 0), op_rs_b11(0x3f, 0x1f, 0),"t,S", 0}, + {"cfc1", op_rs_b11 (17, 2, 0), op_rs_b11(0x3f, 0x1f, 0),"t,S", 0}, + {"mtc1", op_rs_b11 (17, 4, 0), op_rs_b11(0x3f, 0x1f, 0),"t,S", 0}, + {"ctc1", op_rs_b11 (17, 6, 0), op_rs_b11(0x3f, 0x1f, 0),"t,S", 0}, + + {"bc1f", op_o16(17, 0x100), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc1f", op_o16(17, 0x180), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc1t", op_o16(17, 0x101), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc1t", op_o16(17, 0x181), op_o16(0x3f, 0x3ff), "b", 1}, + +/* fpu instruction */ + {"add.s", op_rs_func(17, 0x10, 0), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"add.d", op_rs_func(17, 0x11, 0), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"sub.s", op_rs_func(17, 0x10, 1), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"sub.d", op_rs_func(17, 0x11, 1), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"mul.s", op_rs_func(17, 0x10, 2), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"mul.d", op_rs_func(17, 0x11, 2), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"div.s", op_rs_func(17, 0x10, 3), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"div.d", op_rs_func(17, 0x11, 3), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T", 0}, + {"abs.s", op_rs_func(17, 0x10, 5), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"abs.d", op_rs_func(17, 0x11, 5), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"mov.s", op_rs_func(17, 0x10, 6), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"mov.d", op_rs_func(17, 0x11, 6), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"neg.s", op_rs_func(17, 0x10, 7), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"neg.d", op_rs_func(17, 0x11, 7), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.s.s", op_rs_func(17, 0x10, 32), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.s.d", op_rs_func(17, 0x11, 32), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.s.w", op_rs_func(17, 0x14, 32), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.d.s", op_rs_func(17, 0x10, 33), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.d.d", op_rs_func(17, 0x11, 33), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.d.w", op_rs_func(17, 0x14, 33), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.w.s", op_rs_func(17, 0x10, 36), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"cvt.w.d", op_rs_func(17, 0x11, 36), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S", 0}, + {"c.f.s", op_rs_func(17, 0x10, 48), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.f.d", op_rs_func(17, 0x11, 48), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.un.s", op_rs_func(17, 0x10, 49), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.un.d", op_rs_func(17, 0x11, 49), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.eq.s", op_rs_func(17, 0x10, 50), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.eq.d", op_rs_func(17, 0x11, 50), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ueq.s", op_rs_func(17, 0x10, 51), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ueq.d", op_rs_func(17, 0x11, 51), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.olt.s", op_rs_func(17, 0x10, 52), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.olt.d", op_rs_func(17, 0x11, 52), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ult.s", op_rs_func(17, 0x10, 53), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ult.d", op_rs_func(17, 0x11, 53), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ole.s", op_rs_func(17, 0x10, 54), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ole.d", op_rs_func(17, 0x11, 54), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ule.s", op_rs_func(17, 0x10, 55), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ule.d", op_rs_func(17, 0x11, 55), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.sf.s", op_rs_func(17, 0x10, 56), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.sf.d", op_rs_func(17, 0x11, 56), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ngle.s", op_rs_func(17, 0x10, 57), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ngle.d", op_rs_func(17, 0x11, 57), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.seq.s", op_rs_func(17, 0x10, 58), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.seq.d", op_rs_func(17, 0x11, 58), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ngl.s", op_rs_func(17, 0x10, 59), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ngl.d", op_rs_func(17, 0x11, 59), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.lt.s", op_rs_func(17, 0x10, 60), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.lt.d", op_rs_func(17, 0x11, 60), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.nge.s", op_rs_func(17, 0x10, 61), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.nge.d", op_rs_func(17, 0x11, 61), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.le.s", op_rs_func(17, 0x10, 62), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.le.d", op_rs_func(17, 0x11, 62), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ngt.s", op_rs_func(17, 0x10, 63), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + {"c.ngt.d", op_rs_func(17, 0x11, 63), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T", 0}, + +/* co processor 2 instruction */ + {"mfc2", op_rs_b11 (18, 0, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"cfc2", op_rs_b11 (18, 2, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"mtc2", op_rs_b11 (18, 4, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"ctc2", op_rs_b11 (18, 6, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"bc2f", op_o16(18, 0x100), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc2f", op_o16(18, 0x180), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc2f", op_o16(18, 0x101), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc2t", op_o16(18, 0x181), op_o16(0x3f, 0x3ff), "b", 1}, + +/* co processor 3 instruction */ + {"mtc3", op_rs_b11 (19, 0, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"cfc3", op_rs_b11 (19, 2, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"mtc3", op_rs_b11 (19, 4, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"ctc3", op_rs_b11 (19, 6, 0), op_rs_b11(0x3f, 0x1f, 0x1ffff), "t,d", 0}, + {"bc3f", op_o16(19, 0x100), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc3f", op_o16(19, 0x180), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc3t", op_o16(19, 0x101), op_o16(0x3f, 0x3ff), "b", 1}, + {"bc3t", op_o16(19, 0x181), op_o16(0x3f, 0x3ff), "b", 1}, + + {"lb", one(32), one(0x3f), "t,j(s)", 0}, + {"lh", one(33), one(0x3f), "t,j(s)", 0}, + {"lwl", one(34), one(0x3f), "t,j(s)", 0}, + {"lw", one(35), one(0x3f), "t,j(s)", 0}, + {"lbu", one(36), one(0x3f), "t,j(s)", 0}, + {"lhu", one(37), one(0x3f), "t,j(s)", 0}, + {"lwr", one(38), one(0x3f), "t,j(s)", 0}, + {"sb", one(40), one(0x3f), "t,j(s)", 0}, + {"sh", one(41), one(0x3f), "t,j(s)", 0}, + {"swl", one(42), one(0x3f), "t,j(s)", 0}, + {"swr", one(46), one(0x3f), "t,j(s)", 0}, + {"sw", one(43), one(0x3f), "t,j(s)", 0}, + {"lwc0", one(48), one(0x3f), "t,j(s)", 0}, +/* for fpu */ + {"lwc1", one(49), one(0x3f), "T,j(s)", 0}, + {"lwc2", one(50), one(0x3f), "t,j(s)", 0}, + {"lwc3", one(51), one(0x3f), "t,j(s)", 0}, + {"swc0", one(56), one(0x3f), "t,j(s)", 0}, +/* for fpu */ + {"swc1", one(57), one(0x3f), "T,j(s)", 0}, + {"swc2", one(58), one(0x3f), "t,j(s)", 0}, + {"swc3", one(59), one(0x3f), "t,j(s)", 0}, +}; diff --git a/gnu/usr.bin/as/opcode/np1.h b/gnu/usr.bin/as/opcode/np1.h new file mode 100644 index 000000000000..654682570fa3 --- /dev/null +++ b/gnu/usr.bin/as/opcode/np1.h @@ -0,0 +1,422 @@ +/* Print GOULD NPL instructions for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can 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 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct gld_opcode +{ + char *name; + unsigned long opcode; + unsigned long mask; + char *args; + int length; +}; + +/* 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 at most four. The length of the + instruction is based on the opcode. + + The mask 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 characters + that are used to format the arguments to the instruction. */ + +/* Kinds of operands: + r Register in first field + R Register in second field + b Base register in first field + B Base register in second field + v Vector register in first field + V Vector register in first field + A Optional address register (base register) + X Optional index register + I Immediate data (16bits signed) + O Offset field (16bits signed) + h Offset field (15bits signed) + d Offset field (14bits signed) + S Shift count field + + any other characters are printed as is... +*/ + +/* The assembler requires that this array be sorted as follows: + all instances of the same mnemonic must be consecutive. + All instances of the same mnemonic with the same number of operands + must be consecutive. + */ +struct gld_opcode gld_opcodes[] = +{ +{ "lb", 0xb4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lnb", 0xb8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lbs", 0xec080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lh", 0xb4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lnh", 0xb8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lw", 0xb4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lnw", 0xb8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "ld", 0xb4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lnd", 0xb8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "li", 0xf8000000, 0xfc7f0000, "r,I", 4 }, +{ "lpa", 0x50080000, 0xfc080000, "r,xOA,X", 4 }, +{ "la", 0x50000000, 0xfc080000, "r,xOA,X", 4 }, +{ "labr", 0x58080000, 0xfc080000, "b,xOA,X", 4 }, +{ "lbp", 0x90080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lhp", 0x90000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lwp", 0x90000000, 0xfc080000, "r,xOA,X", 4 }, +{ "ldp", 0x90000002, 0xfc080002, "r,xOA,X", 4 }, +{ "suabr", 0x58000000, 0xfc080000, "b,xOA,X", 4 }, +{ "lf", 0xbc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lfbr", 0xbc080000, 0xfc080000, "b,xOA,X", 4 }, +{ "lwbr", 0x5c000000, 0xfc080000, "b,xOA,X", 4 }, +{ "stb", 0xd4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "sth", 0xd4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "stw", 0xd4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "std", 0xd4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "stf", 0xdc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stfbr", 0xdc080000, 0xfc080000, "b,xOA,X", 4 }, +{ "stwbr", 0x54000000, 0xfc080000, "b,xOA,X", 4 }, +{ "zmb", 0xd8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "zmh", 0xd8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "zmw", 0xd8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "zmd", 0xd8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "stbp", 0x94080000, 0xfc080000, "r,xOA,X", 4 }, +{ "sthp", 0x94000001, 0xfc080001, "r,xOA,X", 4 }, +{ "stwp", 0x94000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stdp", 0x94000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lil", 0xf80b0000, 0xfc7f0000, "r,D", 4 }, +{ "lwsl1", 0xec000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lwsl2", 0xfc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lwsl3", 0xfc080000, 0xfc080000, "r,xOA,X", 4 }, + +{ "lvb", 0xb0080000, 0xfc080000, "v,xOA,X", 4 }, +{ "lvh", 0xb0000001, 0xfc080001, "v,xOA,X", 4 }, +{ "lvw", 0xb0000000, 0xfc080000, "v,xOA,X", 4 }, +{ "lvd", 0xb0000002, 0xfc080002, "v,xOA,X", 4 }, +{ "liv", 0x3c040000, 0xfc0f0000, "v,R", 2 }, +{ "livf", 0x3c080000, 0xfc0f0000, "v,R", 2 }, +{ "stvb", 0xd0080000, 0xfc080000, "v,xOA,X", 4 }, +{ "stvh", 0xd0000001, 0xfc080001, "v,xOA,X", 4 }, +{ "stvw", 0xd0000000, 0xfc080000, "v,xOA,X", 4 }, +{ "stvd", 0xd0000002, 0xfc080002, "v,xOA,X", 4 }, + +{ "trr", 0x2c000000, 0xfc0f0000, "r,R", 2 }, +{ "trn", 0x2c040000, 0xfc0f0000, "r,R", 2 }, +{ "trnd", 0x2c0c0000, 0xfc0f0000, "r,R", 2 }, +{ "trabs", 0x2c010000, 0xfc0f0000, "r,R", 2 }, +{ "trabsd", 0x2c090000, 0xfc0f0000, "r,R", 2 }, +{ "trc", 0x2c030000, 0xfc0f0000, "r,R", 2 }, +{ "xcr", 0x28040000, 0xfc0f0000, "r,R", 2 }, +{ "cxcr", 0x2c060000, 0xfc0f0000, "r,R", 2 }, +{ "cxcrd", 0x2c0e0000, 0xfc0f0000, "r,R", 2 }, +{ "tbrr", 0x2c020000, 0xfc0f0000, "r,B", 2 }, +{ "trbr", 0x28030000, 0xfc0f0000, "b,R", 2 }, +{ "xcbr", 0x28020000, 0xfc0f0000, "b,B", 2 }, +{ "tbrbr", 0x28010000, 0xfc0f0000, "b,B", 2 }, + +{ "trvv", 0x28050000, 0xfc0f0000, "v,V", 2 }, +{ "trvvn", 0x2c050000, 0xfc0f0000, "v,V", 2 }, +{ "trvvnd", 0x2c0d0000, 0xfc0f0000, "v,V", 2 }, +{ "trvab", 0x2c070000, 0xfc0f0000, "v,V", 2 }, +{ "trvabd", 0x2c0f0000, 0xfc0f0000, "v,V", 2 }, +{ "cmpv", 0x14060000, 0xfc0f0000, "v,V", 2 }, +{ "expv", 0x14070000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvlt", 0x10030000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvle", 0x10040000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvgt", 0x14030000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvge", 0x14040000, 0xfc0f0000, "v,V", 2 }, +{ "mrvveq", 0x10050000, 0xfc0f0000, "v,V", 2 }, +{ "mrvvne", 0x10050000, 0xfc0f0000, "v,V", 2 }, +{ "mrvrlt", 0x100d0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvrle", 0x100e0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvrgt", 0x140d0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvrge", 0x140e0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvreq", 0x100f0000, 0xfc0f0000, "v,R", 2 }, +{ "mrvrne", 0x140f0000, 0xfc0f0000, "v,R", 2 }, +{ "trvr", 0x140b0000, 0xfc0f0000, "r,V", 2 }, +{ "trrv", 0x140c0000, 0xfc0f0000, "v,R", 2 }, + +{ "bu", 0x40000000, 0xff880000, "xOA,X", 4 }, +{ "bns", 0x70080000, 0xff880000, "xOA,X", 4 }, +{ "bnco", 0x70880000, 0xff880000, "xOA,X", 4 }, +{ "bge", 0x71080000, 0xff880000, "xOA,X", 4 }, +{ "bne", 0x71880000, 0xff880000, "xOA,X", 4 }, +{ "bunge", 0x72080000, 0xff880000, "xOA,X", 4 }, +{ "bunle", 0x72880000, 0xff880000, "xOA,X", 4 }, +{ "bgt", 0x73080000, 0xff880000, "xOA,X", 4 }, +{ "bnany", 0x73880000, 0xff880000, "xOA,X", 4 }, +{ "bs" , 0x70000000, 0xff880000, "xOA,X", 4 }, +{ "bco", 0x70800000, 0xff880000, "xOA,X", 4 }, +{ "blt", 0x71000000, 0xff880000, "xOA,X", 4 }, +{ "beq", 0x71800000, 0xff880000, "xOA,X", 4 }, +{ "buge", 0x72000000, 0xff880000, "xOA,X", 4 }, +{ "bult", 0x72800000, 0xff880000, "xOA,X", 4 }, +{ "ble", 0x73000000, 0xff880000, "xOA,X", 4 }, +{ "bany", 0x73800000, 0xff880000, "xOA,X", 4 }, +{ "brlnk", 0x44000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bib", 0x48000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bih", 0x48080000, 0xfc080000, "r,xOA,X", 4 }, +{ "biw", 0x4c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bid", 0x4c080000, 0xfc080000, "r,xOA,X", 4 }, +{ "bivb", 0x60000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bivh", 0x60080000, 0xfc080000, "r,xOA,X", 4 }, +{ "bivw", 0x64000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bivd", 0x64080000, 0xfc080000, "r,xOA,X", 4 }, +{ "bvsb", 0x68000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bvsh", 0x68080000, 0xfc080000, "r,xOA,X", 4 }, +{ "bvsw", 0x6c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bvsd", 0x6c080000, 0xfc080000, "r,xOA,X", 4 }, + +{ "camb", 0x80080000, 0xfc080000, "r,xOA,X", 4 }, +{ "camh", 0x80000001, 0xfc080001, "r,xOA,X", 4 }, +{ "camw", 0x80000000, 0xfc080000, "r,xOA,X", 4 }, +{ "camd", 0x80000002, 0xfc080002, "r,xOA,X", 4 }, +{ "car", 0x10000000, 0xfc0f0000, "r,R", 2 }, +{ "card", 0x14000000, 0xfc0f0000, "r,R", 2 }, +{ "ci", 0xf8050000, 0xfc7f0000, "r,I", 4 }, +{ "chkbnd", 0x5c080000, 0xfc080000, "r,xOA,X", 4 }, + +{ "cavv", 0x10010000, 0xfc0f0000, "v,V", 2 }, +{ "cavr", 0x10020000, 0xfc0f0000, "v,R", 2 }, +{ "cavvd", 0x10090000, 0xfc0f0000, "v,V", 2 }, +{ "cavrd", 0x100b0000, 0xfc0f0000, "v,R", 2 }, + +{ "anmb", 0x84080000, 0xfc080000, "r,xOA,X", 4 }, +{ "anmh", 0x84000001, 0xfc080001, "r,xOA,X", 4 }, +{ "anmw", 0x84000000, 0xfc080000, "r,xOA,X", 4 }, +{ "anmd", 0x84000002, 0xfc080002, "r,xOA,X", 4 }, +{ "anr", 0x04000000, 0xfc0f0000, "r,R", 2 }, +{ "ani", 0xf8080000, 0xfc7f0000, "r,I", 4 }, +{ "ormb", 0xb8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "ormh", 0xb8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "ormw", 0xb8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "ormd", 0xb8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "orr", 0x08000000, 0xfc0f0000, "r,R", 2 }, +{ "oi", 0xf8090000, 0xfc7f0000, "r,I", 4 }, +{ "eomb", 0x8c080000, 0xfc080000, "r,xOA,X", 4 }, +{ "eomh", 0x8c000001, 0xfc080001, "r,xOA,X", 4 }, +{ "eomw", 0x8c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "eomd", 0x8c000002, 0xfc080002, "r,xOA,X", 4 }, +{ "eor", 0x0c000000, 0xfc0f0000, "r,R", 2 }, +{ "eoi", 0xf80a0000, 0xfc7f0000, "r,I", 4 }, + +{ "anvv", 0x04010000, 0xfc0f0000, "v,V", 2 }, +{ "anvr", 0x04020000, 0xfc0f0000, "v,R", 2 }, +{ "orvv", 0x08010000, 0xfc0f0000, "v,V", 2 }, +{ "orvr", 0x08020000, 0xfc0f0000, "v,R", 2 }, +{ "eovv", 0x0c010000, 0xfc0f0000, "v,V", 2 }, +{ "eovr", 0x0c020000, 0xfc0f0000, "v,R", 2 }, + +{ "sacz", 0x100c0000, 0xfc0f0000, "r,R", 2 }, +{ "sla", 0x1c400000, 0xfc600000, "r,S", 2 }, +{ "sll", 0x1c600000, 0xfc600000, "r,S", 2 }, +{ "slc", 0x24400000, 0xfc600000, "r,S", 2 }, +{ "slad", 0x20400000, 0xfc600000, "r,S", 2 }, +{ "slld", 0x20600000, 0xfc600000, "r,S", 2 }, +{ "sra", 0x1c000000, 0xfc600000, "r,S", 2 }, +{ "srl", 0x1c200000, 0xfc600000, "r,S", 2 }, +{ "src", 0x24000000, 0xfc600000, "r,S", 2 }, +{ "srad", 0x20000000, 0xfc600000, "r,S", 2 }, +{ "srld", 0x20200000, 0xfc600000, "r,S", 2 }, +{ "sda", 0x3c030000, 0xfc0f0000, "r,R", 2 }, +{ "sdl", 0x3c020000, 0xfc0f0000, "r,R", 2 }, +{ "sdc", 0x3c010000, 0xfc0f0000, "r,R", 2 }, +{ "sdad", 0x3c0b0000, 0xfc0f0000, "r,R", 2 }, +{ "sdld", 0x3c0a0000, 0xfc0f0000, "r,R", 2 }, + +{ "svda", 0x3c070000, 0xfc0f0000, "v,R", 2 }, +{ "svdl", 0x3c060000, 0xfc0f0000, "v,R", 2 }, +{ "svdc", 0x3c050000, 0xfc0f0000, "v,R", 2 }, +{ "svdad", 0x3c0e0000, 0xfc0f0000, "v,R", 2 }, +{ "svdld", 0x3c0d0000, 0xfc0f0000, "v,R", 2 }, + +{ "sbm", 0xac080000, 0xfc080000, "f,xOA,X", 4 }, +{ "zbm", 0xac000000, 0xfc080000, "f,xOA,X", 4 }, +{ "tbm", 0xa8080000, 0xfc080000, "f,xOA,X", 4 }, +{ "incmb", 0xa0000000, 0xfc080000, "xOA,X", 4 }, +{ "incmh", 0xa0080000, 0xfc080000, "xOA,X", 4 }, +{ "incmw", 0xa4000000, 0xfc080000, "xOA,X", 4 }, +{ "incmd", 0xa4080000, 0xfc080000, "xOA,X", 4 }, +{ "sbmd", 0x7c080000, 0xfc080000, "r,xOA,X", 4 }, +{ "zbmd", 0x7c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "tbmd", 0x78080000, 0xfc080000, "r,xOA,X", 4 }, + +{ "ssm", 0x9c080000, 0xfc080000, "f,xOA,X", 4 }, +{ "zsm", 0x9c000000, 0xfc080000, "f,xOA,X", 4 }, +{ "tsm", 0x98080000, 0xfc080000, "f,xOA,X", 4 }, + +{ "admb", 0xc8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "admh", 0xc8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "admw", 0xc8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "admd", 0xc8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "adr", 0x38000000, 0xfc0f0000, "r,R", 2 }, +{ "armb", 0xe8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "armh", 0xe8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "armw", 0xe8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "armd", 0xe8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "adi", 0xf8010000, 0xfc0f0000, "r,I", 4 }, +{ "sumb", 0xcc080000, 0xfc080000, "r,xOA,X", 4 }, +{ "sumh", 0xcc000001, 0xfc080001, "r,xOA,X", 4 }, +{ "sumw", 0xcc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "sumd", 0xcc000002, 0xfc080002, "r,xOA,X", 4 }, +{ "sur", 0x3c000000, 0xfc0f0000, "r,R", 2 }, +{ "sui", 0xf8020000, 0xfc0f0000, "r,I", 4 }, +{ "mpmb", 0xc0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpmh", 0xc0000001, 0xfc080001, "r,xOA,X", 4 }, +{ "mpmw", 0xc0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpr", 0x38020000, 0xfc0f0000, "r,R", 2 }, +{ "mprd", 0x3c0f0000, 0xfc0f0000, "r,R", 2 }, +{ "mpi", 0xf8030000, 0xfc0f0000, "r,I", 4 }, +{ "dvmb", 0xc4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvmh", 0xc4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "dvmw", 0xc4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvr", 0x380a0000, 0xfc0f0000, "r,R", 2 }, +{ "dvi", 0xf8040000, 0xfc0f0000, "r,I", 4 }, +{ "exs", 0x38080000, 0xfc0f0000, "r,R", 2 }, + +{ "advv", 0x30000000, 0xfc0f0000, "v,V", 2 }, +{ "advvd", 0x30080000, 0xfc0f0000, "v,V", 2 }, +{ "adrv", 0x34000000, 0xfc0f0000, "v,R", 2 }, +{ "adrvd", 0x34080000, 0xfc0f0000, "v,R", 2 }, +{ "suvv", 0x30010000, 0xfc0f0000, "v,V", 2 }, +{ "suvvd", 0x30090000, 0xfc0f0000, "v,V", 2 }, +{ "surv", 0x34010000, 0xfc0f0000, "v,R", 2 }, +{ "survd", 0x34090000, 0xfc0f0000, "v,R", 2 }, +{ "mpvv", 0x30020000, 0xfc0f0000, "v,V", 2 }, +{ "mprv", 0x34020000, 0xfc0f0000, "v,R", 2 }, + +{ "adfw", 0xe0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "adfd", 0xe0080002, 0xfc080002, "r,xOA,X", 4 }, +{ "adrfw", 0x38010000, 0xfc0f0000, "r,R", 2 }, +{ "adrfd", 0x38090000, 0xfc0f0000, "r,R", 2 }, +{ "surfw", 0xe0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "surfd", 0xe0000002, 0xfc080002, "r,xOA,X", 4 }, +{ "surfw", 0x38030000, 0xfc0f0000, "r,R", 2 }, +{ "surfd", 0x380b0000, 0xfc0f0000, "r,R", 2 }, +{ "mpfw", 0xe4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpfd", 0xe4080002, 0xfc080002, "r,xOA,X", 4 }, +{ "mprfw", 0x38060000, 0xfc0f0000, "r,R", 2 }, +{ "mprfd", 0x380e0000, 0xfc0f0000, "r,R", 2 }, +{ "rfw", 0xe4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "rfd", 0xe4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "rrfw", 0x0c0e0000, 0xfc0f0000, "r", 2 }, +{ "rrfd", 0x0c0f0000, 0xfc0f0000, "r", 2 }, + +{ "advvfw", 0x30040000, 0xfc0f0000, "v,V", 2 }, +{ "advvfd", 0x300c0000, 0xfc0f0000, "v,V", 2 }, +{ "adrvfw", 0x34040000, 0xfc0f0000, "v,R", 2 }, +{ "adrvfd", 0x340c0000, 0xfc0f0000, "v,R", 2 }, +{ "suvvfw", 0x30050000, 0xfc0f0000, "v,V", 2 }, +{ "suvvfd", 0x300d0000, 0xfc0f0000, "v,V", 2 }, +{ "survfw", 0x34050000, 0xfc0f0000, "v,R", 2 }, +{ "survfd", 0x340d0000, 0xfc0f0000, "v,R", 2 }, +{ "mpvvfw", 0x30060000, 0xfc0f0000, "v,V", 2 }, +{ "mpvvfd", 0x300e0000, 0xfc0f0000, "v,V", 2 }, +{ "mprvfw", 0x34060000, 0xfc0f0000, "v,R", 2 }, +{ "mprvfd", 0x340e0000, 0xfc0f0000, "v,R", 2 }, +{ "rvfw", 0x30070000, 0xfc0f0000, "v", 2 }, +{ "rvfd", 0x300f0000, 0xfc0f0000, "v", 2 }, + +{ "fltw", 0x38070000, 0xfc0f0000, "r,R", 2 }, +{ "fltd", 0x380f0000, 0xfc0f0000, "r,R", 2 }, +{ "fixw", 0x38050000, 0xfc0f0000, "r,R", 2 }, +{ "fixd", 0x380d0000, 0xfc0f0000, "r,R", 2 }, +{ "cfpds", 0x3c090000, 0xfc0f0000, "r,R", 2 }, + +{ "fltvw", 0x080d0000, 0xfc0f0000, "v,V", 2 }, +{ "fltvd", 0x080f0000, 0xfc0f0000, "v,V", 2 }, +{ "fixvw", 0x080c0000, 0xfc0f0000, "v,V", 2 }, +{ "fixvd", 0x080e0000, 0xfc0f0000, "v,V", 2 }, +{ "cfpvds", 0x0c0d0000, 0xfc0f0000, "v,V", 2 }, + +{ "orvrn", 0x000a0000, 0xfc0f0000, "r,V", 2 }, +{ "andvrn", 0x00080000, 0xfc0f0000, "r,V", 2 }, +{ "frsteq", 0x04090000, 0xfc0f0000, "r,V", 2 }, +{ "sigma", 0x0c080000, 0xfc0f0000, "r,V", 2 }, +{ "sigmad", 0x0c0a0000, 0xfc0f0000, "r,V", 2 }, +{ "sigmf", 0x08080000, 0xfc0f0000, "r,V", 2 }, +{ "sigmfd", 0x080a0000, 0xfc0f0000, "r,V", 2 }, +{ "prodf", 0x04080000, 0xfc0f0000, "r,V", 2 }, +{ "prodfd", 0x040a0000, 0xfc0f0000, "r,V", 2 }, +{ "maxv", 0x10080000, 0xfc0f0000, "r,V", 2 }, +{ "maxvd", 0x100a0000, 0xfc0f0000, "r,V", 2 }, +{ "minv", 0x14080000, 0xfc0f0000, "r,V", 2 }, +{ "minvd", 0x140a0000, 0xfc0f0000, "r,V", 2 }, + +{ "lpsd", 0xf0000000, 0xfc080000, "xOA,X", 4 }, +{ "ldc", 0xf0080000, 0xfc080000, "xOA,X", 4 }, +{ "spm", 0x040c0000, 0xfc0f0000, "r", 2 }, +{ "rpm", 0x040d0000, 0xfc0f0000, "r", 2 }, +{ "tritr", 0x00070000, 0xfc0f0000, "r", 2 }, +{ "trrit", 0x00060000, 0xfc0f0000, "r", 2 }, +{ "rpswt", 0x04080000, 0xfc0f0000, "r", 2 }, +{ "exr", 0xf8070000, 0xfc0f0000, "", 4 }, +{ "halt", 0x00000000, 0xfc0f0000, "", 2 }, +{ "wait", 0x00010000, 0xfc0f0000, "", 2 }, +{ "nop", 0x00020000, 0xfc0f0000, "", 2 }, +{ "eiae", 0x00030000, 0xfc0f0000, "", 2 }, +{ "efae", 0x000d0000, 0xfc0f0000, "", 2 }, +{ "diae", 0x000e0000, 0xfc0f0000, "", 2 }, +{ "dfae", 0x000f0000, 0xfc0f0000, "", 2 }, +{ "spvc", 0xf8060000, 0xfc0f0000, "r,T,N", 4 }, +{ "rdsts", 0x00090000, 0xfc0f0000, "r", 2 }, +{ "setcpu", 0x000c0000, 0xfc0f0000, "r", 2 }, +{ "cmc", 0x000b0000, 0xfc0f0000, "r", 2 }, +{ "trrcu", 0x00040000, 0xfc0f0000, "r", 2 }, +{ "attnio", 0x00050000, 0xfc0f0000, "", 2 }, +{ "fudit", 0x28080000, 0xfc0f0000, "", 2 }, +{ "break", 0x28090000, 0xfc0f0000, "", 2 }, +{ "frzss", 0x280a0000, 0xfc0f0000, "", 2 }, +{ "ripi", 0x04040000, 0xfc0f0000, "r,R", 2 }, +{ "xcp", 0x04050000, 0xfc0f0000, "r", 2 }, +{ "block", 0x04060000, 0xfc0f0000, "", 2 }, +{ "unblock", 0x04070000, 0xfc0f0000, "", 2 }, +{ "trsc", 0x08060000, 0xfc0f0000, "r,R", 2 }, +{ "tscr", 0x08070000, 0xfc0f0000, "r,R", 2 }, +{ "fq", 0x04080000, 0xfc0f0000, "r", 2 }, +{ "flupte", 0x2c080000, 0xfc0f0000, "r", 2 }, +{ "rviu", 0x040f0000, 0xfc0f0000, "", 2 }, +{ "ldel", 0x280c0000, 0xfc0f0000, "r,R", 2 }, +{ "ldu", 0x280d0000, 0xfc0f0000, "r,R", 2 }, +{ "stdecc", 0x280b0000, 0xfc0f0000, "r,R", 2 }, +{ "trpc", 0x08040000, 0xfc0f0000, "r", 2 }, +{ "tpcr", 0x08050000, 0xfc0f0000, "r", 2 }, +{ "ghalt", 0x0c050000, 0xfc0f0000, "r", 2 }, +{ "grun", 0x0c040000, 0xfc0f0000, "", 2 }, +{ "tmpr", 0x2c0a0000, 0xfc0f0000, "r,R", 2 }, +{ "trmp", 0x2c0b0000, 0xfc0f0000, "r,R", 2 }, + +{ "trrve", 0x28060000, 0xfc0f0000, "r", 2 }, +{ "trver", 0x28070000, 0xfc0f0000, "r", 2 }, +{ "trvlr", 0x280f0000, 0xfc0f0000, "r", 2 }, + +{ "linkfl", 0x18000000, 0xfc0f0000, "r,R", 2 }, +{ "linkbl", 0x18020000, 0xfc0f0000, "r,R", 2 }, +{ "linkfp", 0x18010000, 0xfc0f0000, "r,R", 2 }, +{ "linkbp", 0x18030000, 0xfc0f0000, "r,R", 2 }, +{ "linkpl", 0x18040000, 0xfc0f0000, "r,R", 2 }, +{ "ulinkl", 0x18080000, 0xfc0f0000, "r,R", 2 }, +{ "ulinkp", 0x18090000, 0xfc0f0000, "r,R", 2 }, +{ "ulinktl", 0x180a0000, 0xfc0f0000, "r,R", 2 }, +{ "ulinktp", 0x180b0000, 0xfc0f0000, "r,R", 2 }, +}; + +int numopcodes = sizeof(gld_opcodes) / sizeof(gld_opcodes[0]); + +struct gld_opcode *endop = gld_opcodes + sizeof(gld_opcodes) / + sizeof(gld_opcodes[0]); diff --git a/gnu/usr.bin/as/opcode/ns32k.h b/gnu/usr.bin/as/opcode/ns32k.h new file mode 100644 index 000000000000..2a7621a9ca32 --- /dev/null +++ b/gnu/usr.bin/as/opcode/ns32k.h @@ -0,0 +1,491 @@ +/* ns32k-opcode.h -- Opcode table for National Semi 32k processor + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#ifdef TE_SEQUENT +#define DEF_MODEC 20 +#define DEF_MODEL 21 +#endif + +#ifndef DEF_MODEC +#define DEF_MODEC 20 +#endif + +#ifndef DEF_MODEL +#define DEF_MODEL 20 +#endif +/* + After deciding the instruction entry (via hash.c) the instruction parser + will try to match the operands after the instruction to the required set + given in the entry operandfield. Every operand will result in a change in + the opcode or the addition of data to the opcode. + The operands in the source instruction are checked for inconsistent + semantics. + + F : 32 bit float general form + L : 64 bit float " + B : byte " + W : word " + D : double-word " + Q : quad-word " + A : double-word gen-address-form ie no regs allowed + d : displacement + b : displacement - pc relative addressing acb + p : displacement - pc relative addressing br bcond bsr cxp + q : quick + i : immediate (8 bits) + This is not a standard ns32k operandtype, it is used to build + instructions like svc arg1,arg2 + Svc is the instruction SuperVisorCall and is sometimes used to + call OS-routines from usermode. Some args might be handy! + r : register number (3 bits) + O : setcfg instruction optionslist + C : cinv instruction optionslist + S : stringinstruction optionslist + U : registerlist save,enter + u : registerlist restore,exit + M : mmu register + P : cpu register + g : 3:rd operand of inss or exts instruction + G : 4:th operand of inss or exts instruction + Those operands are encoded in the same byte. + This byte is placed last in the instruction. + f : operand of sfsr + H : sequent-hack for bsr (Warning) + +column 1 instructions + 2 number of bits in opcode. + 3 number of bits in opcode explicitly + determined by the instruction type. + 4 opcodeseed, the number we build our opcode + from. + 5 operandtypes, used by operandparser. + 6 size in bytes of immediate +*/ +struct ns32k_opcode { + char *name; + unsigned char opcode_id_size; /* not used by the assembler */ + unsigned char opcode_size; + unsigned long opcode_seed; + char *operands; + unsigned char im_size; /* not used by dissassembler */ + char *default_args; /* default to those args when none given */ + char default_modec; /* default to this addr-mode when ambigous + ie when the argument of a general addr-mode + is a plain constant */ + char default_model; /* is a plain label */ +}; + +#ifdef comment +/* This section was from the gdb version of this file. */ + +#ifndef ns32k_opcodeT +#define ns32k_opcodeT int +#endif /* no ns32k_opcodeT */ + +struct not_wot /* ns32k opcode table: wot to do with this */ + /* particular opcode */ +{ + int obits; /* number of opcode bits */ + int ibits; /* number of instruction bits */ + ns32k_opcodeT code; /* op-code (may be > 8 bits!) */ + char *args; /* how to compile said opcode */ +}; + +struct not /* ns32k opcode text */ +{ + char * name; /* opcode name: lowercase string [key] */ + struct not_wot detail; /* rest of opcode table [datum] */ +}; + +/* Instructions look like this: + + basic instruction--1, 2, or 3 bytes + index byte for operand A, if operand A is indexed--1 byte + index byte for operand B, if operand B is indexed--1 byte + addressing extension for operand A + addressing extension for operand B + implied operands + + Operand A is the operand listed first in the following opcode table. + Operand B is the operand listed second in the following opcode table. + All instructions have at most 2 general operands, so this is enough. + The implied operands are associated with operands other than A and B. + + Each operand has a digit and a letter. + + The digit gives the position in the assembly language. The letter, + one of the following, tells us what kind of operand it is. */ + +/* F : 32 bit float + * L : 64 bit float + * B : byte + * W : word + * D : double-word + * Q : quad-word + * d : displacement + * q : quick + * i : immediate (8 bits) + * r : register number (3 bits) + * p : displacement - pc relative addressing +*/ + + +#endif /* comment */ + +static const struct ns32k_opcode ns32k_opcodes[]= +{ + { "absf", 14,24, 0x35be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "absl", 14,24, 0x34be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, + { "absb", 14,24, 0x304e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "absw", 14,24, 0x314e, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "absd", 14,24, 0x334e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "acbb", 7,16, 0x4c, "2B1q3p", 1, "", DEF_MODEC,DEF_MODEL }, + { "acbw", 7,16, 0x4d, "2W1q3p", 2, "", DEF_MODEC,DEF_MODEL }, + { "acbd", 7,16, 0x4f, "2D1q3p", 4, "", DEF_MODEC,DEF_MODEL }, + { "addf", 14,24, 0x01be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "addl", 14,24, 0x00be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, + { "addb", 6,16, 0x00, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "addw", 6,16, 0x01, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "addd", 6,16, 0x03, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "addcb", 6,16, 0x10, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "addcw", 6,16, 0x11, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "addcd", 6,16, 0x13, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "addpb", 14,24, 0x3c4e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "addpw", 14,24, 0x3d4e, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "addpd", 14,24, 0x3f4e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "addqb", 7,16, 0x0c, "2B1q", 1, "", DEF_MODEC,DEF_MODEL }, + { "addqw", 7,16, 0x0d, "2W1q", 2, "", DEF_MODEC,DEF_MODEL }, + { "addqd", 7,16, 0x0f, "2D1q", 4, "", DEF_MODEC,DEF_MODEL }, + { "addr", 6,16, 0x27, "1A2D", 4, "", 21,21 }, + { "adjspb", 11,16, 0x057c, "1B", 1, "", DEF_MODEC,DEF_MODEL }, + { "adjspw", 11,16, 0x057d, "1W", 2, "", DEF_MODEC,DEF_MODEL }, + { "adjspd", 11,16, 0x057f, "1D", 4, "", DEF_MODEC,DEF_MODEL }, + { "andb", 6,16, 0x28, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "andw", 6,16, 0x29, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "andd", 6,16, 0x2b, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "ashb", 14,24, 0x044e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "ashw", 14,24, 0x054e, "1B2W", 1, "", DEF_MODEC,DEF_MODEL }, + { "ashd", 14,24, 0x074e, "1B2D", 1, "", DEF_MODEC,DEF_MODEL }, + { "beq", 8,8, 0x0a, "1p", 0, "", 21,21 }, + { "bne", 8,8, 0x1a, "1p", 0, "", 21,21 }, + { "bcs", 8,8, 0x2a, "1p", 0, "", 21,21 }, + { "bcc", 8,8, 0x3a, "1p", 0, "", 21,21 }, + { "bhi", 8,8, 0x4a, "1p", 0, "", 21,21 }, + { "bls", 8,8, 0x5a, "1p", 0, "", 21,21 }, + { "bgt", 8,8, 0x6a, "1p", 0, "", 21,21 }, + { "ble", 8,8, 0x7a, "1p", 0, "", 21,21 }, + { "bfs", 8,8, 0x8a, "1p", 0, "", 21,21 }, + { "bfc", 8,8, 0x9a, "1p", 0, "", 21,21 }, + { "blo", 8,8, 0xaa, "1p", 0, "", 21,21 }, + { "bhs", 8,8, 0xba, "1p", 0, "", 21,21 }, + { "blt", 8,8, 0xca, "1p", 0, "", 21,21 }, + { "bge", 8,8, 0xda, "1p", 0, "", 21,21 }, + { "but", 8,8, 0xea, "1p", 0, "", 21,21 }, + { "buf", 8,8, 0xfa, "1p", 0, "", 21,21 }, + { "bicb", 6,16, 0x08, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "bicw", 6,16, 0x09, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "bicd", 6,16, 0x0b, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "bicpsrb", 11,16, 0x17c, "1B", 1, "", DEF_MODEC,DEF_MODEL }, + { "bicpsrw", 11,16, 0x17d, "1W", 2, "", DEF_MODEC,DEF_MODEL }, + { "bispsrb", 11,16, 0x37c, "1B", 1, "", DEF_MODEC,DEF_MODEL }, + { "bispsrw", 11,16, 0x37d, "1W", 2, "", DEF_MODEC,DEF_MODEL }, + { "bpt", 8,8, 0xf2, "", 0, "", DEF_MODEC,DEF_MODEL }, + { "br", 8,8, 0xea, "1p", 0, "", 21,21 }, +#ifdef TE_SEQUENT + { "bsr", 8,8, 0x02, "1H", 0, "", 21,21 }, +#else + { "bsr", 8,8, 0x02, "1p", 0, "", 21,21 }, +#endif + { "caseb", 11,16, 0x77c, "1B", 1, "", DEF_MODEC,DEF_MODEL }, + { "casew", 11,16, 0x77d, "1W", 2, "", DEF_MODEC,DEF_MODEL }, + { "cased", 11,16, 0x77f, "1D", 4, "", DEF_MODEC,DEF_MODEL }, + { "cbitb", 14,24, 0x084e, "1B2D", 1, "", DEF_MODEC,DEF_MODEL }, + { "cbitw", 14,24, 0x094e, "1W2D", 2, "", DEF_MODEC,DEF_MODEL }, + { "cbitd", 14,24, 0x0b4e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "cbitib", 14,24, 0x0c4e, "1B2D", 1, "", DEF_MODEC,DEF_MODEL }, + { "cbitiw", 14,24, 0x0d4e, "1W2D", 2, "", DEF_MODEC,DEF_MODEL }, + { "cbitid", 14,24, 0x0f4e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "checkb", 11,24, 0x0ee, "2A3B1r", 1, "", DEF_MODEC,DEF_MODEL }, + { "checkw", 11,24, 0x1ee, "2A3W1r", 2, "", DEF_MODEC,DEF_MODEL }, + { "checkd", 11,24, 0x3ee, "2A3D1r", 4, "", DEF_MODEC,DEF_MODEL }, + { "cinv", 14,24, 0x271e, "2D1C", 4, "", DEF_MODEC,DEF_MODEL }, + { "cmpf", 14,24, 0x09be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "cmpl", 14,24, 0x08be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, + { "cmpb", 6,16, 0x04, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "cmpw", 6,16, 0x05, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "cmpd", 6,16, 0x07, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "cmpmb", 14,24, 0x04ce, "1A2A3b", 1, "", DEF_MODEC,DEF_MODEL }, + { "cmpmw", 14,24, 0x05ce, "1A2A3b", 2, "", DEF_MODEC,DEF_MODEL }, + { "cmpmd", 14,24, 0x07ce, "1A2A3b", 4, "", DEF_MODEC,DEF_MODEL }, + { "cmpqb", 7,16, 0x1c, "2B1q", 1, "", DEF_MODEC,DEF_MODEL }, + { "cmpqw", 7,16, 0x1d, "2W1q", 2, "", DEF_MODEC,DEF_MODEL }, + { "cmpqd", 7,16, 0x1f, "2D1q", 4, "", DEF_MODEC,DEF_MODEL }, + { "cmpsb", 16,24, 0x040e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "cmpsw", 16,24, 0x050e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "cmpsd", 16,24, 0x070e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "cmpst", 16,24, 0x840e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "comb", 14,24, 0x344e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "comw", 14,24, 0x354e, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "comd", 14,24, 0x374e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "cvtp", 11,24, 0x036e, "2A3D1r", 4, "", DEF_MODEC,DEF_MODEL }, + { "cxp", 8,8, 0x22, "1p", 0, "", 21,21 }, + { "cxpd", 11,16, 0x07f, "1A", 4, "", DEF_MODEC,DEF_MODEL }, + { "deib", 14,24, 0x2cce, "1B2W", 1, "", DEF_MODEC,DEF_MODEL }, + { "deiw", 14,24, 0x2dce, "1W2D", 2, "", DEF_MODEC,DEF_MODEL }, + { "deid", 14,24, 0x2fce, "1D2Q", 4, "", DEF_MODEC,DEF_MODEL }, + { "dia", 8,8, 0xc2, "", 1, "", DEF_MODEC,DEF_MODEL }, + { "divf", 14,24, 0x21be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "divl", 14,24, 0x20be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, + { "divb", 14,24, 0x3cce, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "divw", 14,24, 0x3dce, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "divd", 14,24, 0x3fce, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "enter", 8,8, 0x82, "1U2d", 0, "", DEF_MODEC,DEF_MODEL }, + { "exit", 8,8, 0x92, "1u", 0, "", DEF_MODEC,DEF_MODEL }, + { "extb", 11,24, 0x02e, "2D3B1r4d", 1, "", DEF_MODEC,DEF_MODEL }, + { "extw", 11,24, 0x12e, "2D3W1r4d", 2, "", DEF_MODEC,DEF_MODEL }, + { "extd", 11,24, 0x32e, "2D3D1r4d", 4, "", DEF_MODEC,DEF_MODEL }, + { "extsb", 14,24, 0x0cce, "1D2B3g4G", 1, "", DEF_MODEC,DEF_MODEL }, + { "extsw", 14,24, 0x0dce, "1D2W3g4G", 2, "", DEF_MODEC,DEF_MODEL }, + { "extsd", 14,24, 0x0fce, "1D2D3g4G", 4, "", DEF_MODEC,DEF_MODEL }, + { "ffsb", 14,24, 0x046e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "ffsw", 14,24, 0x056e, "1W2B", 2, "", DEF_MODEC,DEF_MODEL }, + { "ffsd", 14,24, 0x076e, "1D2B", 4, "", DEF_MODEC,DEF_MODEL }, + { "flag", 8,8, 0xd2, "", 0, "", DEF_MODEC,DEF_MODEL }, + { "floorfb", 14,24, 0x3c3e, "1F2B", 4, "", DEF_MODEC,DEF_MODEL }, + { "floorfw", 14,24, 0x3d3e, "1F2W", 4, "", DEF_MODEC,DEF_MODEL }, + { "floorfd", 14,24, 0x3f3e, "1F2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "floorlb", 14,24, 0x383e, "1L2B", 8, "", DEF_MODEC,DEF_MODEL }, + { "floorlw", 14,24, 0x393e, "1L2W", 8, "", DEF_MODEC,DEF_MODEL }, + { "floorld", 14,24, 0x3b3e, "1L2D", 8, "", DEF_MODEC,DEF_MODEL }, + { "ibitb", 14,24, 0x384e, "1B2D", 1, "", DEF_MODEC,DEF_MODEL }, + { "ibitw", 14,24, 0x394e, "1W2D", 2, "", DEF_MODEC,DEF_MODEL }, + { "ibitd", 14,24, 0x3b4e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "indexb", 11,24, 0x42e, "2B3B1r", 1, "", DEF_MODEC,DEF_MODEL }, + { "indexw", 11,24, 0x52e, "2W3W1r", 2, "", DEF_MODEC,DEF_MODEL }, + { "indexd", 11,24, 0x72e, "2D3D1r", 4, "", DEF_MODEC,DEF_MODEL }, + { "insb", 11,24, 0x0ae, "2B3B1r4d", 1, "", DEF_MODEC,DEF_MODEL }, + { "insw", 11,24, 0x1ae, "2W3W1r4d", 2, "", DEF_MODEC,DEF_MODEL }, + { "insd", 11,24, 0x3ae, "2D3D1r4d", 4, "", DEF_MODEC,DEF_MODEL }, + { "inssb", 14,24, 0x08ce, "1B2D3g4G", 1, "", DEF_MODEC,DEF_MODEL }, + { "inssw", 14,24, 0x09ce, "1W2D3g4G", 2, "", DEF_MODEC,DEF_MODEL }, + { "inssd", 14,24, 0x0bce, "1D2D3g4G", 4, "", DEF_MODEC,DEF_MODEL }, + { "jsr", 11,16, 0x67f, "1A", 4, "", 21,21 }, + { "jump", 11,16, 0x27f, "1A", 4, "", 21,21 }, + { "lfsr", 19,24, 0x00f3e,"1D", 4, "", DEF_MODEC,DEF_MODEL }, + { "lmr", 15,24, 0x0b1e, "2D1M", 4, "", DEF_MODEC,DEF_MODEL }, + { "lprb", 7,16, 0x6c, "2B1P", 1, "", DEF_MODEC,DEF_MODEL }, + { "lprw", 7,16, 0x6d, "2W1P", 2, "", DEF_MODEC,DEF_MODEL }, + { "lprd", 7,16, 0x6f, "2D1P", 4, "", DEF_MODEC,DEF_MODEL }, + { "lshb", 14,24, 0x144e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "lshw", 14,24, 0x154e, "1B2W", 1, "", DEF_MODEC,DEF_MODEL }, + { "lshd", 14,24, 0x174e, "1B2D", 1, "", DEF_MODEC,DEF_MODEL }, + { "meib", 14,24, 0x24ce, "1B2W", 1, "", DEF_MODEC,DEF_MODEL }, + { "meiw", 14,24, 0x25ce, "1W2D", 2, "", DEF_MODEC,DEF_MODEL }, + { "meid", 14,24, 0x27ce, "1D2Q", 4, "", DEF_MODEC,DEF_MODEL }, + { "modb", 14,24, 0x38ce, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "modw", 14,24, 0x39ce, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "modd", 14,24, 0x3bce, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "movf", 14,24, 0x05be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "movl", 14,24, 0x04be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, + { "movb", 6,16, 0x14, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "movw", 6,16, 0x15, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "movd", 6,16, 0x17, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "movbf", 14,24, 0x043e, "1B2F", 1, "", DEF_MODEC,DEF_MODEL }, + { "movwf", 14,24, 0x053e, "1W2F", 2, "", DEF_MODEC,DEF_MODEL }, + { "movdf", 14,24, 0x073e, "1D2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "movbl", 14,24, 0x003e, "1B2L", 1, "", DEF_MODEC,DEF_MODEL }, + { "movwl", 14,24, 0x013e, "1W2L", 2, "", DEF_MODEC,DEF_MODEL }, + { "movdl", 14,24, 0x033e, "1D2L", 4, "", DEF_MODEC,DEF_MODEL }, + { "movfl", 14,24, 0x1b3e, "1F2L", 4, "", DEF_MODEC,DEF_MODEL }, + { "movlf", 14,24, 0x163e, "1L2F", 8, "", DEF_MODEC,DEF_MODEL }, + { "movmb", 14,24, 0x00ce, "1A2A3b", 1, "", DEF_MODEC,DEF_MODEL }, + { "movmw", 14,24, 0x01ce, "1A2A3b", 2, "", DEF_MODEC,DEF_MODEL }, + { "movmd", 14,24, 0x03ce, "1A2A3b", 4, "", DEF_MODEC,DEF_MODEL }, + { "movqb", 7,16, 0x5c, "2B1q", 1, "", DEF_MODEC,DEF_MODEL }, + { "movqw", 7,16, 0x5d, "2B1q", 2, "", DEF_MODEC,DEF_MODEL }, + { "movqd", 7,16, 0x5f, "2B1q", 4, "", DEF_MODEC,DEF_MODEL }, + { "movsb", 16,24, 0x000e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "movsw", 16,24, 0x010e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "movsd", 16,24, 0x030e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "movst", 16,24, 0x800e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "movsub", 14,24, 0x0cae, "1A2A", 1, "", DEF_MODEC,DEF_MODEL }, + { "movsuw", 14,24, 0x0dae, "1A2A", 2, "", DEF_MODEC,DEF_MODEL }, + { "movsud", 14,24, 0x0fae, "1A2A", 4, "", DEF_MODEC,DEF_MODEL }, + { "movusb", 14,24, 0x1cae, "1A2A", 1, "", DEF_MODEC,DEF_MODEL }, + { "movusw", 14,24, 0x1dae, "1A2A", 2, "", DEF_MODEC,DEF_MODEL }, + { "movusd", 14,24, 0x1fae, "1A2A", 4, "", DEF_MODEC,DEF_MODEL }, + { "movxbd", 14,24, 0x1cce, "1B2D", 1, "", DEF_MODEC,DEF_MODEL }, + { "movxwd", 14,24, 0x1dce, "1W2D", 2, "", DEF_MODEC,DEF_MODEL }, + { "movxbw", 14,24, 0x10ce, "1B2W", 1, "", DEF_MODEC,DEF_MODEL }, + { "movzbd", 14,24, 0x18ce, "1B2D", 1, "", DEF_MODEC,DEF_MODEL }, + { "movzwd", 14,24, 0x19ce, "1W2D", 2, "", DEF_MODEC,DEF_MODEL }, + { "movzbw", 14,24, 0x14ce, "1B2W", 1, "", DEF_MODEC,DEF_MODEL }, + { "mulf", 14,24, 0x31be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "mull", 14,24, 0x30be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, + { "mulb", 14,24, 0x20ce, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "mulw", 14,24, 0x21ce, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "muld", 14,24, 0x23ce, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "negf", 14,24, 0x15be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "negl", 14,24, 0x14be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, + { "negb", 14,24, 0x204e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "negw", 14,24, 0x214e, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "negd", 14,24, 0x234e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "nop", 8,8, 0xa2, "", 0, "", DEF_MODEC,DEF_MODEL }, + { "notb", 14,24, 0x244e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "notw", 14,24, 0x254e, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "notd", 14,24, 0x274e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "orb", 6,16, 0x18, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "orw", 6,16, 0x19, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "ord", 6,16, 0x1b, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "quob", 14,24, 0x30ce, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "quow", 14,24, 0x31ce, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "quod", 14,24, 0x33ce, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "rdval", 19,24, 0x0031e,"1A", 4, "", DEF_MODEC,DEF_MODEL }, + { "remb", 14,24, 0x34ce, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "remw", 14,24, 0x35ce, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "remd", 14,24, 0x37ce, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "restore", 8,8, 0x72, "1u", 0, "", DEF_MODEC,DEF_MODEL }, + { "ret", 8,8, 0x12, "1d", 0, "", DEF_MODEC,DEF_MODEL }, + { "reti", 8,8, 0x52, "", 0, "", DEF_MODEC,DEF_MODEL }, + { "rett", 8,8, 0x42, "1d", 0, "", DEF_MODEC,DEF_MODEL }, + { "rotb", 14,24, 0x004e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "rotw", 14,24, 0x014e, "1B2W", 1, "", DEF_MODEC,DEF_MODEL }, + { "rotd", 14,24, 0x034e, "1B2D", 1, "", DEF_MODEC,DEF_MODEL }, + { "roundfb", 14,24, 0x243e, "1F2B", 4, "", DEF_MODEC,DEF_MODEL }, + { "roundfw", 14,24, 0x253e, "1F2W", 4, "", DEF_MODEC,DEF_MODEL }, + { "roundfd", 14,24, 0x273e, "1F2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "roundlb", 14,24, 0x203e, "1L2B", 8, "", DEF_MODEC,DEF_MODEL }, + { "roundlw", 14,24, 0x213e, "1L2W", 8, "", DEF_MODEC,DEF_MODEL }, + { "roundld", 14,24, 0x233e, "1L2D", 8, "", DEF_MODEC,DEF_MODEL }, + { "rxp", 8,8, 0x32, "1d", 0, "", DEF_MODEC,DEF_MODEL }, + { "seqb", 11,16, 0x3c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "seqw", 11,16, 0x3d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "seqd", 11,16, 0x3f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sneb", 11,16, 0xbc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "snew", 11,16, 0xbd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sned", 11,16, 0xbf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "scsb", 11,16, 0x13c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "scsw", 11,16, 0x13d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "scsd", 11,16, 0x13f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sccb", 11,16, 0x1bc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sccw", 11,16, 0x1bd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sccd", 11,16, 0x1bf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "shib", 11,16, 0x23c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "shiw", 11,16, 0x23d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "shid", 11,16, 0x23f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "slsb", 11,16, 0x2bc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "slsw", 11,16, 0x2bd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "slsd", 11,16, 0x2bf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sgtb", 11,16, 0x33c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sgtw", 11,16, 0x33d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sgtd", 11,16, 0x33f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sleb", 11,16, 0x3bc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "slew", 11,16, 0x3bd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sled", 11,16, 0x3bf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sfsb", 11,16, 0x43c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sfsw", 11,16, 0x43d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sfsd", 11,16, 0x43f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sfcb", 11,16, 0x4bc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sfcw", 11,16, 0x4bd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sfcd", 11,16, 0x4bf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "slob", 11,16, 0x53c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "slow", 11,16, 0x53d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "slod", 11,16, 0x53f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "shsb", 11,16, 0x5bc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "shsw", 11,16, 0x5bd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "shsd", 11,16, 0x5bf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sltb", 11,16, 0x63c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sltw", 11,16, 0x63d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sltd", 11,16, 0x63f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sgeb", 11,16, 0x6bc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sgew", 11,16, 0x6bd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sged", 11,16, 0x6bf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sutb", 11,16, 0x73c, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sutw", 11,16, 0x73d, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sutd", 11,16, 0x73f, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "sufb", 11,16, 0x7bc, "1B", 0, "", DEF_MODEC,DEF_MODEL }, + { "sufw", 11,16, 0x7bd, "1W", 0, "", DEF_MODEC,DEF_MODEL }, + { "sufd", 11,16, 0x7bf, "1D", 0, "", DEF_MODEC,DEF_MODEL }, + { "save", 8,8, 0x62, "1U", 0, "", DEF_MODEC,DEF_MODEL }, + { "sbitb", 14,24, 0x184e, "1B2A", 1, "", DEF_MODEC,DEF_MODEL }, + { "sbitw", 14,24, 0x194e, "1W2A", 2, "", DEF_MODEC,DEF_MODEL }, + { "sbitd", 14,24, 0x1b4e, "1D2A", 4, "", DEF_MODEC,DEF_MODEL }, + { "sbitib", 14,24, 0x1c4e, "1B2A", 1, "", DEF_MODEC,DEF_MODEL }, + { "sbitiw", 14,24, 0x1d4e, "1W2A", 2, "", DEF_MODEC,DEF_MODEL }, + { "sbitid", 14,24, 0x1f4e, "1D2A", 4, "", DEF_MODEC,DEF_MODEL }, + { "setcfg", 15,24, 0x0b0e, "1O", 0, "", DEF_MODEC,DEF_MODEL }, + { "sfsr", 14,24, 0x373e, "1f", 0, "", DEF_MODEC,DEF_MODEL }, + { "skpsb", 16,24, 0x0c0e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "skpsw", 16,24, 0x0d0e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "skpsd", 16,24, 0x0f0e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "skpst", 16,24, 0x8c0e, "1S", 0, "[]", DEF_MODEC,DEF_MODEL }, + { "smr", 15,24, 0x0f1e, "2D1M", 4, "", DEF_MODEC,DEF_MODEL }, + { "sprb", 7,16, 0x2c, "2B1P", 1, "", DEF_MODEC,DEF_MODEL }, + { "sprw", 7,16, 0x2d, "2W1P", 2, "", DEF_MODEC,DEF_MODEL }, + { "sprd", 7,16, 0x2f, "2D1P", 4, "", DEF_MODEC,DEF_MODEL }, + { "subf", 14,24, 0x11be, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "subl", 14,24, 0x10be, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, + { "subb", 6,16, 0x20, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "subw", 6,16, 0x21, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "subd", 6,16, 0x23, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "subcb", 6,16, 0x30, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "subcw", 6,16, 0x31, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "subcd", 6,16, 0x33, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "subpb", 14,24, 0x2c4e, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "subpw", 14,24, 0x2d4e, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "subpd", 14,24, 0x2f4e, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, +#ifdef NS32K_SVC_IMMED_OPERANDS + { "svc", 8,8, 0xe2, "2i1i", 1, "", DEF_MODEC,DEF_MODEL }, /* not really, but unix uses it */ +#else + { "svc", 8,8, 0xe2, "", 0, "", DEF_MODEC,DEF_MODEL }, +#endif + { "tbitb", 6,16, 0x34, "1B2A", 1, "", DEF_MODEC,DEF_MODEL }, + { "tbitw", 6,16, 0x35, "1W2A", 2, "", DEF_MODEC,DEF_MODEL }, + { "tbitd", 6,16, 0x37, "1D2A", 4, "", DEF_MODEC,DEF_MODEL }, + { "truncfb", 14,24, 0x2c3e, "1F2B", 4, "", DEF_MODEC,DEF_MODEL }, + { "truncfw", 14,24, 0x2d3e, "1F2W", 4, "", DEF_MODEC,DEF_MODEL }, + { "truncfd", 14,24, 0x2f3e, "1F2D", 4, "", DEF_MODEC,DEF_MODEL }, + { "trunclb", 14,24, 0x283e, "1L2B", 8, "", DEF_MODEC,DEF_MODEL }, + { "trunclw", 14,24, 0x293e, "1L2W", 8, "", DEF_MODEC,DEF_MODEL }, + { "truncld", 14,24, 0x2b3e, "1L2D", 8, "", DEF_MODEC,DEF_MODEL }, + { "wait", 8,8, 0xb2, "", 0, "", DEF_MODEC,DEF_MODEL }, + { "wrval", 19,24, 0x0071e,"1A", 0, "", DEF_MODEC,DEF_MODEL }, + { "xorb", 6,16, 0x38, "1B2B", 1, "", DEF_MODEC,DEF_MODEL }, + { "xorw", 6,16, 0x39, "1W2W", 2, "", DEF_MODEC,DEF_MODEL }, + { "xord", 6,16, 0x3b, "1D2D", 4, "", DEF_MODEC,DEF_MODEL }, +#if defined(NS32381) /* I'm not too sure of these */ + { "dotf", 14,24, 0x0dfe, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "dotl", 14,24, 0x0cfe, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, + { "logbf", 14,24, 0x15fe, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "logbl", 14,24, 0x14fe, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, + { "polyf", 14,24, 0x09fe, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "polyl", 14,24, 0x08fe, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, + { "scalbf", 14,24, 0x11fe, "1F2F", 4, "", DEF_MODEC,DEF_MODEL }, + { "scalbl", 14,24, 0x10fe, "1L2L", 8, "", DEF_MODEC,DEF_MODEL }, +#endif +}; + +static const int numopcodes=sizeof(ns32k_opcodes)/sizeof(ns32k_opcodes[0]); + +static const struct ns32k_opcode *endop = ns32k_opcodes+sizeof(ns32k_opcodes)/sizeof(ns32k_opcodes[0]); + +#define MAX_ARGS 4 +#define ARG_LEN 50 + diff --git a/gnu/usr.bin/as/opcode/pn.h b/gnu/usr.bin/as/opcode/pn.h new file mode 100644 index 000000000000..fde4764c02ce --- /dev/null +++ b/gnu/usr.bin/as/opcode/pn.h @@ -0,0 +1,282 @@ +/* Print GOULD PN (PowerNode) instructions for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can 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 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR 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; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct gld_opcode +{ + char *name; + unsigned long opcode; + unsigned long mask; + char *args; + int length; +}; + +/* 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 at most four. The length of the + instruction is based on the opcode. + + The mask 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 characters + that are used to format the arguments to the instruction. */ + +/* Kinds of operands: + r Register in first field + R Register in second field + b Base register in first field + B Base register in second field + v Vector register in first field + V Vector register in first field + A Optional address register (base register) + X Optional index register + I Immediate data (16bits signed) + O Offset field (16bits signed) + h Offset field (15bits signed) + d Offset field (14bits signed) + S Shift count field + + any other characters are printed as is... +*/ + +/* The assembler requires that this array be sorted as follows: + all instances of the same mnemonic must be consecutive. + All instances of the same mnemonic with the same number of operands + must be consecutive. + */ +struct gld_opcode gld_opcodes[] = +{ +{ "abm", 0xa0080000, 0xfc080000, "f,xOA,X", 4 }, +{ "abr", 0x18080000, 0xfc0c0000, "r,f", 2 }, +{ "aci", 0xfc770000, 0xfc7f8000, "r,I", 4 }, +{ "adfd", 0xe0080002, 0xfc080002, "r,xOA,X", 4 }, +{ "adfw", 0xe0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "adi", 0xc8010000, 0xfc7f0000, "r,I", 4 }, +{ "admb", 0xb8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "admd", 0xb8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "admh", 0xb8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "admw", 0xb8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "adr", 0x38000000, 0xfc0f0000, "r,R", 2 }, +{ "adrfd", 0x38090000, 0xfc0f0000, "r,R", 2 }, +{ "adrfw", 0x38010000, 0xfc0f0000, "r,R", 2 }, +{ "adrm", 0x38080000, 0xfc0f0000, "r,R", 2 }, +{ "ai", 0xfc030000, 0xfc07ffff, "I", 4 }, +{ "anmb", 0x84080000, 0xfc080000, "r,xOA,X", 4 }, +{ "anmd", 0x84000002, 0xfc080002, "r,xOA,X", 4 }, +{ "anmh", 0x84000001, 0xfc080001, "r,xOA,X", 4 }, +{ "anmw", 0x84000000, 0xfc080000, "r,xOA,X", 4 }, +{ "anr", 0x04000000, 0xfc0f0000, "r,R", 2 }, +{ "armb", 0xe8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "armd", 0xe8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "armh", 0xe8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "armw", 0xe8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "bcf", 0xf0000000, 0xfc080000, "I,xOA,X", 4 }, +{ "bct", 0xec000000, 0xfc080000, "I,xOA,X", 4 }, +{ "bei", 0x00060000, 0xffff0000, "", 2 }, +{ "bft", 0xf0000000, 0xff880000, "xOA,X", 4 }, +{ "bib", 0xf4000000, 0xfc780000, "r,xOA", 4 }, +{ "bid", 0xf4600000, 0xfc780000, "r,xOA", 4 }, +{ "bih", 0xf4200000, 0xfc780000, "r,xOA", 4 }, +{ "biw", 0xf4400000, 0xfc780000, "r,xOA", 4 }, +{ "bl", 0xf8800000, 0xff880000, "xOA,X", 4 }, +{ "bsub", 0x5c080000, 0xff8f0000, "", 2 }, +{ "bsubm", 0x28080000, 0xfc080000, "", 4 }, +{ "bu", 0xec000000, 0xff880000, "xOA,X", 4 }, +{ "call", 0x28080000, 0xfc0f0000, "", 2 }, +{ "callm", 0x5c080000, 0xff880000, "", 4 }, +{ "camb", 0x90080000, 0xfc080000, "r,xOA,X", 4 }, +{ "camd", 0x90000002, 0xfc080002, "r,xOA,X", 4 }, +{ "camh", 0x90000001, 0xfc080001, "r,xOA,X", 4 }, +{ "camw", 0x90000000, 0xfc080000, "r.xOA,X", 4 }, +{ "car", 0x10000000, 0xfc0f0000, "r,R", 2 }, +{ "cd", 0xfc060000, 0xfc070000, "r,f", 4 }, +{ "cea", 0x000f0000, 0xffff0000, "", 2 }, +{ "ci", 0xc8050000, 0xfc7f0000, "r,I", 4 }, +{ "cmc", 0x040a0000, 0xfc7f0000, "r", 2 }, +{ "cmmb", 0x94080000, 0xfc080000, "r,xOA,X", 4 }, +{ "cmmd", 0x94000002, 0xfc080002, "r,xOA,X", 4 }, +{ "cmmh", 0x94000001, 0xfc080001, "r,xOA,X", 4 }, +{ "cmmw", 0x94000000, 0xfc080000, "r,xOA,X", 4 }, +{ "cmr", 0x14000000, 0xfc0f0000, "r,R", 2 }, +{ "daci", 0xfc7f0000, 0xfc7f8000, "r,I", 4 }, +{ "dae", 0x000e0000, 0xffff0000, "", 2 }, +{ "dai", 0xfc040000, 0xfc07ffff, "I", 4 }, +{ "dci", 0xfc6f0000, 0xfc7f8000, "r,I", 4 }, +{ "di", 0xfc010000, 0xfc07ffff, "I", 4 }, +{ "dvfd", 0xe4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "dvfw", 0xe4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvi", 0xc8040000, 0xfc7f0000, "r,I", 4 }, +{ "dvmb", 0xc4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvmh", 0xc4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "dvmw", 0xc4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "dvr", 0x380a0000, 0xfc0f0000, "r,R", 2 }, +{ "dvrfd", 0x380c0000, 0xfc0f0000, "r,R", 4 }, +{ "dvrfw", 0x38040000, 0xfc0f0000, "r,xOA,X", 4 }, +{ "eae", 0x00080000, 0xffff0000, "", 2 }, +{ "eci", 0xfc670000, 0xfc7f8080, "r,I", 4 }, +{ "ecwcs", 0xfc4f0000, 0xfc7f8000, "", 4 }, +{ "ei", 0xfc000000, 0xfc07ffff, "I", 4 }, +{ "eomb", 0x8c080000, 0xfc080000, "r,xOA,X", 4 }, +{ "eomd", 0x8c000002, 0xfc080002, "r,xOA,X", 4 }, +{ "eomh", 0x8c000001, 0xfc080001, "r,xOA,X", 4 }, +{ "eomw", 0x8c000000, 0xfc080000, "r,xOA,X", 4 }, +{ "eor", 0x0c000000, 0xfc0f0000, "r,R", 2 }, +{ "eorm", 0x0c080000, 0xfc0f0000, "r,R", 2 }, +{ "es", 0x00040000, 0xfc7f0000, "r", 2 }, +{ "exm", 0xa8000000, 0xff880000, "xOA,X", 4 }, +{ "exr", 0xc8070000, 0xfc7f0000, "r", 2 }, +{ "exrr", 0xc8070002, 0xfc7f0002, "r", 2 }, +{ "fixd", 0x380d0000, 0xfc0f0000, "r,R", 2 }, +{ "fixw", 0x38050000, 0xfc0f0000, "r,R", 2 }, +{ "fltd", 0x380f0000, 0xfc0f0000, "r,R", 2 }, +{ "fltw", 0x38070000, 0xfc0f0000, "r,R", 2 }, +{ "grio", 0xfc3f0000, 0xfc7f8000, "r,I", 4 }, +{ "halt", 0x00000000, 0xffff0000, "", 2 }, +{ "hio", 0xfc370000, 0xfc7f8000, "r,I", 4 }, +{ "jwcs", 0xfa080000, 0xff880000, "xOA,X", 4 }, +{ "la", 0x50000000, 0xfc000000, "r,xOA,X", 4 }, +{ "labr", 0x58080000, 0xfc080000, "b,xOA,X", 4 }, +{ "lb", 0xac080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lcs", 0x00030000, 0xfc7f0000, "r", 2 }, +{ "ld", 0xac000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lear", 0x80000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lf", 0xcc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lfbr", 0xcc080000, 0xfc080000, "b,xOA,X", 4 }, +{ "lh", 0xac000001, 0xfc080001, "r,xOA,X", 4 }, +{ "li", 0xc8000000, 0xfc7f0000, "r,I", 4 }, +{ "lmap", 0x2c070000, 0xfc7f0000, "r", 2 }, +{ "lmb", 0xb0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lmd", 0xb0000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lmh", 0xb0000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lmw", 0xb0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lnb", 0xb4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "lnd", 0xb4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "lnh", 0xb4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "lnw", 0xb4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lpsd", 0xf9800000, 0xff880000, "r,xOA,X", 4 }, +{ "lpsdcm", 0xfa800000, 0xff880000, "r,xOA,X", 4 }, +{ "lw", 0xac000000, 0xfc080000, "r,xOA,X", 4 }, +{ "lwbr", 0x5c000000, 0xfc080000, "b,xOA,X", 4 }, +{ "mpfd", 0xe4080002, 0xfc080002, "r,xOA,X", 4 }, +{ "mpfw", 0xe4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpi", 0xc8030000, 0xfc7f0000, "r,I", 4 }, +{ "mpmb", 0xc0080000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpmh", 0xc0000001, 0xfc080001, "r,xOA,X", 4 }, +{ "mpmw", 0xc0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "mpr", 0x38020000, 0xfc0f0000, "r,R", 2 }, +{ "mprfd", 0x380e0000, 0xfc0f0000, "r,R", 2 }, +{ "mprfw", 0x38060000, 0xfc0f0000, "r,R", 2 }, +{ "nop", 0x00020000, 0xffff0000, "", 2 }, +{ "ormb", 0x88080000, 0xfc080000, "r,xOA,X", 4 }, +{ "ormd", 0x88000002, 0xfc080002, "r,xOA,X", 4 }, +{ "ormh", 0x88000001, 0xfc080001, "r,xOA,X", 4 }, +{ "ormw", 0x88000000, 0xfc080000, "r,xOA,X", 4 }, +{ "orr", 0x08000000, 0xfc0f0000, "r,R", 2 }, +{ "orrm", 0x08080000, 0xfc0f0000, "r,R", 2 }, +{ "rdsts", 0x00090000, 0xfc7f0000, "r", 2 }, +{ "return", 0x280e0000, 0xfc7f0000, "", 2 }, +{ "ri", 0xfc020000, 0xfc07ffff, "I", 4 }, +{ "rnd", 0x00050000, 0xfc7f0000, "r", 2 }, +{ "rpswt", 0x040b0000, 0xfc7f0000, "r", 2 }, +{ "rschnl", 0xfc2f0000, 0xfc7f8000, "r,I", 4 }, +{ "rsctl", 0xfc470000, 0xfc7f8000, "r,I", 4 }, +{ "rwcs", 0x000b0000, 0xfc0f0000, "r,R", 2 }, +{ "sacz", 0x10080000, 0xfc0f0000, "r,R", 2 }, +{ "sbm", 0x98080000, 0xfc080000, "f,xOA,X", 4 }, +{ "sbr", 0x18000000, 0xfc0c0000, "r,f", 4 }, +{ "sea", 0x000d0000, 0xffff0000, "", 2 }, +{ "setcpu", 0x2c090000, 0xfc7f0000, "r", 2 }, +{ "sio", 0xfc170000, 0xfc7f8000, "r,I", 4 }, +{ "sipu", 0x000a0000, 0xffff0000, "", 2 }, +{ "sla", 0x1c400000, 0xfc600000, "r,S", 2 }, +{ "slad", 0x20400000, 0xfc600000, "r,S", 2 }, +{ "slc", 0x24400000, 0xfc600000, "r,S", 2 }, +{ "sll", 0x1c600000, 0xfc600000, "r,S", 2 }, +{ "slld", 0x20600000, 0xfc600000, "r,S", 2 }, +{ "smc", 0x04070000, 0xfc070000, "", 2 }, +{ "sra", 0x1c000000, 0xfc600000, "r,S", 2 }, +{ "srad", 0x20000000, 0xfc600000, "r,S", 2 }, +{ "src", 0x24000000, 0xfc600000, "r,S", 2 }, +{ "srl", 0x1c200000, 0xfc600000, "r,S", 2 }, +{ "srld", 0x20200000, 0xfc600000, "r,S", 2 }, +{ "stb", 0xd4080000, 0xfc080000, "r,xOA,X", 4 }, +{ "std", 0xd4000002, 0xfc080002, "r,xOA,X", 4 }, +{ "stf", 0xdc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stfbr", 0x54000000, 0xfc080000, "b,xOA,X", 4 }, +{ "sth", 0xd4000001, 0xfc080001, "r,xOA,X", 4 }, +{ "stmb", 0xd8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "stmd", 0xd8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "stmh", 0xd8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "stmw", 0xd8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stpio", 0xfc270000, 0xfc7f8000, "r,I", 4 }, +{ "stw", 0xd4000000, 0xfc080000, "r,xOA,X", 4 }, +{ "stwbr", 0x54000000, 0xfc080000, "b,xOA,X", 4 }, +{ "suabr", 0x58000000, 0xfc080000, "b,xOA,X", 4 }, +{ "sufd", 0xe0000002, 0xfc080002, "r,xOA,X", 4 }, +{ "sufw", 0xe0000000, 0xfc080000, "r,xOA,X", 4 }, +{ "sui", 0xc8020000, 0xfc7f0000, "r,I", 4 }, +{ "sumb", 0xbc080000, 0xfc080000, "r,xOA,X", 4 }, +{ "sumd", 0xbc000002, 0xfc080002, "r,xOA,X", 4 }, +{ "sumh", 0xbc000001, 0xfc080001, "r,xOA,X", 4 }, +{ "sumw", 0xbc000000, 0xfc080000, "r,xOA,X", 4 }, +{ "sur", 0x3c000000, 0xfc0f0000, "r,R", 2 }, +{ "surfd", 0x380b0000, 0xfc0f0000, "r,xOA,X", 4 }, +{ "surfw", 0x38030000, 0xfc0f0000, "r,R", 2 }, +{ "surm", 0x3c080000, 0xfc0f0000, "r,R", 2 }, +{ "svc", 0xc8060000, 0xffff0000, "", 4 }, +{ "tbm", 0xa4080000, 0xfc080000, "f,xOA,X", 4 }, +{ "tbr", 0x180c0000, 0xfc0c0000, "r,f", 2 }, +{ "tbrr", 0x2c020000, 0xfc0f0000, "r,B", 2 }, +{ "tccr", 0x28040000, 0xfc7f0000, "", 2 }, +{ "td", 0xfc050000, 0xfc070000, "r,f", 4 }, +{ "tio", 0xfc1f0000, 0xfc7f8000, "r,I", 4 }, +{ "tmapr", 0x2c0a0000, 0xfc0f0000, "r,R", 2 }, +{ "tpcbr", 0x280c0000, 0xfc7f0000, "r", 2 }, +{ "trbr", 0x2c010000, 0xfc0f0000, "b,R", 2 }, +{ "trc", 0x2c030000, 0xfc0f0000, "r,R", 2 }, +{ "trcc", 0x28050000, 0xfc7f0000, "", 2 }, +{ "trcm", 0x2c0b0000, 0xfc0f0000, "r,R", 2 }, +{ "trn", 0x2c040000, 0xfc0f0000, "r,R", 2 }, +{ "trnm", 0x2c0c0000, 0xfc0f0000, "r,R", 2 }, +{ "trr", 0x2c000000, 0xfc0f0000, "r,R", 2 }, +{ "trrm", 0x2c080000, 0xfc0f0000, "r,R", 2 }, +{ "trsc", 0x2c0e0000, 0xfc0f0000, "r,R", 2 }, +{ "trsw", 0x28000000, 0xfc7f0000, "r", 2 }, +{ "tscr", 0x2c0f0000, 0xfc0f0000, "r,R", 2 }, +{ "uei", 0x00070000, 0xffff0000, "", 2 }, +{ "wait", 0x00010000, 0xffff0000, "", 2 }, +{ "wcwcs", 0xfc5f0000, 0xfc7f8000, "", 4 }, +{ "wwcs", 0x000c0000, 0xfc0f0000, "r,R", 2 }, +{ "xcbr", 0x28020000, 0xfc0f0000, "b,B", 2 }, +{ "xcr", 0x2c050000, 0xfc0f0000, "r,R", 2 }, +{ "xcrm", 0x2c0d0000, 0xfc0f0000, "r,R", 2 }, +{ "zbm", 0x9c080000, 0xfc080000, "f,xOA,X", 4 }, +{ "zbr", 0x18040000, 0xfc0c0000, "r,f", 2 }, +{ "zmb", 0xf8080000, 0xfc080000, "r,xOA,X", 4 }, +{ "zmd", 0xf8000002, 0xfc080002, "r,xOA,X", 4 }, +{ "zmh", 0xf8000001, 0xfc080001, "r,xOA,X", 4 }, +{ "zmw", 0xf8000000, 0xfc080000, "r,xOA,X", 4 }, +{ "zr", 0x0c000000, 0xfc0f0000, "r", 2 }, +}; + +int numopcodes = sizeof(gld_opcodes) / sizeof(gld_opcodes[0]); + +struct gld_opcode *endop = gld_opcodes + sizeof(gld_opcodes) / + sizeof(gld_opcodes[0]); diff --git a/gnu/usr.bin/as/opcode/pyr.h b/gnu/usr.bin/as/opcode/pyr.h new file mode 100644 index 000000000000..06632b8d9197 --- /dev/null +++ b/gnu/usr.bin/as/opcode/pyr.h @@ -0,0 +1,287 @@ +/* pyramid.opcode.h -- gdb initial attempt. */ + +/* pyramid opcode table: wot to do with this + particular opcode */ + +struct pyr_datum +{ + char nargs; + char * args; /* how to compile said opcode */ + unsigned long mask; /* Bit vector: which operand modes are valid + for this opcode */ + unsigned char code; /* op-code (always 6(?) bits */ +}; + +typedef struct pyr_insn_format { + unsigned int mode :4; + unsigned int operator :8; + unsigned int index_scale :2; + unsigned int index_reg :6; + unsigned int operand_1 :6; + unsigned int operand_2:6; +} pyr_insn_format; + + +/* We store four bytes of opcode for all opcodes. + Pyramid is sufficiently RISCy that: + - insns are always an integral number of words; + - the length of any insn can be told from the first word of + the insn. (ie, if there are zero, one, or two words of + immediate operand/offset). + + + 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: + mask assembler syntax description + 0x0001: movw Rn,Rn register to register + 0x0002: movw K,Rn quick immediate to register + 0x0004: movw I,Rn long immediate to register + 0x0008: movw (Rn),Rn register indirect to register + movw (Rn)[x],Rn register indirect to register + 0x0010: movw I(Rn),Rn offset register indirect to register + movw I(Rn)[x],Rn offset register indirect, indexed, to register + + 0x0020: movw Rn,(Rn) register to register indirect + 0x0040: movw K,(Rn) quick immediate to register indirect + 0x0080: movw I,(Rn) long immediate to register indirect + 0x0100: movw (Rn),(Rn) register indirect to-register indirect + 0x0100: movw (Rn),(Rn) register indirect to-register indirect + 0x0200: movw I(Rn),(Rn) register indirect+offset to register indirect + 0x0200: movw I(Rn),(Rn) register indirect+offset to register indirect + + 0x0400: movw Rn,I(Rn) register to register indirect+offset + 0x0800: movw K,I(Rn) quick immediate to register indirect+offset + 0x1000: movw I,I(Rn) long immediate to register indirect+offset + 0x1000: movw (Rn),I(Rn) register indirect to-register indirect+offset + 0x1000: movw I(Rn),I(Rn) register indirect+offset to register indirect + +offset + 0x0000: (irregular) ??? + + + Each insn has a four-bit field encoding the type(s) of its operands. +*/ + +/* Some common combinations + */ + +/* the first 5,(0x1|0x2|0x4|0x8|0x10) ie (1|2|4|8|16), ie ( 32 -1)*/ +#define GEN_TO_REG (31) + +#define UNKNOWN ((unsigned long)-1) +#define ANY (GEN_TO_REG | (GEN_TO_REG << 5) | (GEN_TO_REG << 15)) + +#define CONVERT (1|8|0x10|0x20|0x200) + +#define K_TO_REG (2) +#define I_TO_REG (4) +#define NOTK_TO_REG (GEN_TO_REG & ~K_TO_REG) +#define NOTI_TO_REG (GEN_TO_REG & ~I_TO_REG) + +/* The assembler requires that this array be sorted as follows: + all instances of the same mnemonic must be consecutive. + All instances of the same mnemonic with the same number of operands + must be consecutive. + */ + +struct pyr_opcode /* pyr opcode text */ +{ + char * name; /* opcode name: lowercase string [key] */ + struct pyr_datum datum; /* rest of opcode table [datum] */ +}; + +#define pyr_how args +#define pyr_nargs nargs +#define pyr_mask mask +#define pyr_name name + +struct pyr_opcode pyr_opcodes[] = +{ + {"movb", { 2, "", UNKNOWN, 0x11}, }, + {"movh", { 2, "", UNKNOWN, 0x12} }, + {"movw", { 2, "", ANY, 0x10} }, + {"movl", { 2, "", ANY, 0x13} }, + {"mnegw", { 2, "", (0x1|0x8|0x10), 0x14} }, + {"mnegf", { 2, "", 0x1, 0x15} }, + {"mnegd", { 2, "", 0x1, 0x16} }, + {"mcomw", { 2, "", (0x1|0x8|0x10), 0x17} }, + {"mabsw", { 2, "", (0x1|0x8|0x10), 0x18} }, + {"mabsf", { 2, "", 0x1, 0x19} }, + {"mabsd", { 2, "", 0x1, 0x1a} }, + {"mtstw", { 2, "", (0x1|0x8|0x10), 0x1c} }, + {"mtstf", { 2, "", 0x1, 0x1d} }, + {"mtstd", { 2, "", 0x1, 0x1e} }, + {"mova", { 2, "", 0x8|0x10, 0x1f} }, + {"movzbw", { 2, "", (0x1|0x8|0x10), 0x20} }, + {"movzhw", { 2, "", (0x1|0x8|0x10), 0x21} }, + /* 2 insns out of order here */ + {"movbl", { 2, "", 1, 0x4f} }, + {"filbl", { 2, "", 1, 0x4e} }, + + {"cvtbw", { 2, "", CONVERT, 0x22} }, + {"cvthw", { 2, "", CONVERT, 0x23} }, + {"cvtwb", { 2, "", CONVERT, 0x24} }, + {"cvtwh", { 2, "", CONVERT, 0x25} }, + {"cvtwf", { 2, "", CONVERT, 0x26} }, + {"cvtwd", { 2, "", CONVERT, 0x27} }, + {"cvtfw", { 2, "", CONVERT, 0x28} }, + {"cvtfd", { 2, "", CONVERT, 0x29} }, + {"cvtdw", { 2, "", CONVERT, 0x2a} }, + {"cvtdf", { 2, "", CONVERT, 0x2b} }, + + {"addw", { 2, "", GEN_TO_REG, 0x40} }, + {"addwc", { 2, "", GEN_TO_REG, 0x41} }, + {"subw", { 2, "", GEN_TO_REG, 0x42} }, + {"subwb", { 2, "", GEN_TO_REG, 0x43} }, + {"rsubw", { 2, "", GEN_TO_REG, 0x44} }, + {"mulw", { 2, "", GEN_TO_REG, 0x45} }, + {"emul", { 2, "", GEN_TO_REG, 0x47} }, + {"umulw", { 2, "", GEN_TO_REG, 0x46} }, + {"divw", { 2, "", GEN_TO_REG, 0x48} }, + {"ediv", { 2, "", GEN_TO_REG, 0x4a} }, + {"rdivw", { 2, "", GEN_TO_REG, 0x4b} }, + {"udivw", { 2, "", GEN_TO_REG, 0x49} }, + {"modw", { 2, "", GEN_TO_REG, 0x4c} }, + {"umodw", { 2, "", GEN_TO_REG, 0x4d} }, + + + {"addf", { 2, "", 1, 0x50} }, + {"addd", { 2, "", 1, 0x51} }, + {"subf", { 2, "", 1, 0x52} }, + {"subd", { 2, "", 1, 0x53} }, + {"mulf", { 2, "", 1, 0x56} }, + {"muld", { 2, "", 1, 0x57} }, + {"divf", { 2, "", 1, 0x58} }, + {"divd", { 2, "", 1, 0x59} }, + + + {"cmpb", { 2, "", UNKNOWN, 0x61} }, + {"cmph", { 2, "", UNKNOWN, 0x62} }, + {"cmpw", { 2, "", UNKNOWN, 0x60} }, + {"ucmpb", { 2, "", UNKNOWN, 0x66} }, + /* WHY no "ucmph"??? */ + {"ucmpw", { 2, "", UNKNOWN, 0x65} }, + {"xchw", { 2, "", UNKNOWN, 0x0f} }, + + + {"andw", { 2, "", GEN_TO_REG, 0x30} }, + {"orw", { 2, "", GEN_TO_REG, 0x31} }, + {"xorw", { 2, "", GEN_TO_REG, 0x32} }, + {"bicw", { 2, "", GEN_TO_REG, 0x33} }, + {"lshlw", { 2, "", GEN_TO_REG, 0x38} }, + {"ashlw", { 2, "", GEN_TO_REG, 0x3a} }, + {"ashll", { 2, "", GEN_TO_REG, 0x3c} }, + {"ashrw", { 2, "", GEN_TO_REG, 0x3b} }, + {"ashrl", { 2, "", GEN_TO_REG, 0x3d} }, + {"rotlw", { 2, "", GEN_TO_REG, 0x3e} }, + {"rotrw", { 2, "", GEN_TO_REG, 0x3f} }, + + /* push and pop insns are "going away next release". */ + {"pushw", { 2, "", GEN_TO_REG, 0x0c} }, + {"popw", { 2, "", (0x1|0x8|0x10), 0x0d} }, + {"pusha", { 2, "", (0x8|0x10), 0x0e} }, + + {"bitsw", { 2, "", UNKNOWN, 0x35} }, + {"bitcw", { 2, "", UNKNOWN, 0x36} }, + /* some kind of ibra/dbra insns??*/ + {"icmpw", { 2, "", UNKNOWN, 0x67} }, + {"dcmpw", { 2, "", (1|4|0x20|0x80|0x400|0x1000), 0x69} },/*FIXME*/ + {"acmpw", { 2, "", 1, 0x6b} }, + + /* Call is written as a 1-op insn, but is always (dis)assembled as a 2-op + insn with a 2nd op of tr14. The assembler will have to grok this. */ + {"call", { 2, "", GEN_TO_REG, 0x04} }, + {"call", { 1, "", GEN_TO_REG, 0x04} }, + + {"callk", { 1, "", UNKNOWN, 0x06} },/* system call?*/ + /* Ret is usually written as a 0-op insn, but gets disassembled as a + 1-op insn. The operand is always tr15. */ + {"ret", { 0, "", UNKNOWN, 0x09} }, + {"ret", { 1, "", UNKNOWN, 0x09} }, + {"adsf", { 2, "", (1|2|4), 0x08} }, + {"retd", { 2, "", UNKNOWN, 0x0a} }, + {"btc", { 2, "", UNKNOWN, 0x01} }, + {"bfc", { 2, "", UNKNOWN, 0x02} }, + /* Careful: halt is 0x00000000. Jump must have some other (mode?)bit set?? */ + {"jump", { 1, "", UNKNOWN, 0x00} }, + {"btp", { 2, "", UNKNOWN, 0xf00} }, + /* read control-stack pointer is another 1-or-2 operand insn. */ + {"rcsp", { 2, "", UNKNOWN, 0x01f} }, + {"rcsp", { 1, "", UNKNOWN, 0x01f} } +}; + +/* end: pyramid.opcode.h */ +/* One day I will have to take the time to find out what operands + are valid for these insns, and guess at what they mean. + + I can't imagine what the "I???" insns (iglob, etc) do. + + the arithmetic-sounding insns ending in "p" sound awfully like BCD + arithmetic insns: + dshlp -> Decimal SHift Left Packed + dshrp -> Decimal SHift Right Packed + and cvtlp would be convert long to packed. + I have no idea how the operands are interpreted; but having them be + a long register with (address, length) of an in-memory packed BCD operand + would not be surprising. + They are unlikely to be a packed bcd string: 64 bits of long give + is only 15 digits+sign, which isn't enough for COBOL. + */ +#if 0 + {"wcsp", { 2, "", UNKNOWN, 0x00} }, /*write csp?*/ + /* The OSx Operating System Porting Guide claims SSL does things + with tr12 (a register reserved to it) to do with static block-structure + references. SSL=Set Static Link? It's "Going away next release". */ + {"ssl", { 2, "", UNKNOWN, 0x00} }, + {"ccmps", { 2, "", UNKNOWN, 0x00} }, + {"lcd", { 2, "", UNKNOWN, 0x00} }, + {"uemul", { 2, "", UNKNOWN, 0x00} }, /*unsigned emul*/ + {"srf", { 2, "", UNKNOWN, 0x00} }, /*Gidget time???*/ + {"mnegp", { 2, "", UNKNOWN, 0x00} }, /move-neg phys?*/ + {"ldp", { 2, "", UNKNOWN, 0x00} }, /*load phys?*/ + {"ldti", { 2, "", UNKNOWN, 0x00} }, + {"ldb", { 2, "", UNKNOWN, 0x00} }, + {"stp", { 2, "", UNKNOWN, 0x00} }, + {"stti", { 2, "", UNKNOWN, 0x00} }, + {"stb", { 2, "", UNKNOWN, 0x00} }, + {"stu", { 2, "", UNKNOWN, 0x00} }, + {"addp", { 2, "", UNKNOWN, 0x00} }, + {"subp", { 2, "", UNKNOWN, 0x00} }, + {"mulp", { 2, "", UNKNOWN, 0x00} }, + {"divp", { 2, "", UNKNOWN, 0x00} }, + {"dshlp", { 2, "", UNKNOWN, 0x00} }, /* dec shl packed? */ + {"dshrp", { 2, "", UNKNOWN, 0x00} }, /* dec shr packed? */ + {"movs", { 2, "", UNKNOWN, 0x00} }, /*move (string?)?*/ + {"cmpp", { 2, "", UNKNOWN, 0x00} }, /* cmp phys?*/ + {"cmps", { 2, "", UNKNOWN, 0x00} }, /* cmp (string?)?*/ + {"cvtlp", { 2, "", UNKNOWN, 0x00} }, /* cvt long to p??*/ + {"cvtpl", { 2, "", UNKNOWN, 0x00} }, /* cvt p to l??*/ + {"dintr", { 2, "", UNKNOWN, 0x00} }, /* ?? intr ?*/ + {"rphysw", { 2, "", UNKNOWN, 0x00} }, /* read phys word?*/ + {"wphysw", { 2, "", UNKNOWN, 0x00} }, /* write phys word?*/ + {"cmovs", { 2, "", UNKNOWN, 0x00} }, + {"rsubw", { 2, "", UNKNOWN, 0x00} }, + {"bicpsw", { 2, "", UNKNOWN, 0x00} }, /* clr bit in psw? */ + {"bispsw", { 2, "", UNKNOWN, 0x00} }, /* set bit in psw? */ + {"eio", { 2, "", UNKNOWN, 0x00} }, /* ?? ?io ? */ + {"callp", { 2, "", UNKNOWN, 0x00} }, /* call phys?*/ + {"callr", { 2, "", UNKNOWN, 0x00} }, + {"lpcxt", { 2, "", UNKNOWN, 0x00} }, /*load proc context*/ + {"rei", { 2, "", UNKNOWN, 0x00} }, /*ret from intrpt*/ + {"rport", { 2, "", UNKNOWN, 0x00} }, /*read-port?*/ + {"rtod", { 2, "", UNKNOWN, 0x00} }, /*read-time-of-day?*/ + {"ssi", { 2, "", UNKNOWN, 0x00} }, + {"vtpa", { 2, "", UNKNOWN, 0x00} }, /*virt-to-phys-addr?*/ + {"wicl", { 2, "", UNKNOWN, 0x00} }, /* write icl ? */ + {"wport", { 2, "", UNKNOWN, 0x00} }, /*write-port?*/ + {"wtod", { 2, "", UNKNOWN, 0x00} }, /*write-time-of-day?*/ + {"flic", { 2, "", UNKNOWN, 0x00} }, + {"iglob", { 2, "", UNKNOWN, 0x00} }, /* I global? */ + {"iphys", { 2, "", UNKNOWN, 0x00} }, /* I physical? */ + {"ipid", { 2, "", UNKNOWN, 0x00} }, /* I pid? */ + {"ivect", { 2, "", UNKNOWN, 0x00} }, /* I vector? */ + {"lamst", { 2, "", UNKNOWN, 0x00} }, + {"tio", { 2, "", UNKNOWN, 0x00} }, +#endif diff --git a/gnu/usr.bin/as/opcode/sparc.h b/gnu/usr.bin/as/opcode/sparc.h new file mode 100644 index 000000000000..d18b3ebc0d81 --- /dev/null +++ b/gnu/usr.bin/as/opcode/sparc.h @@ -0,0 +1,871 @@ + +/* Table of opcodes for the sparc. + Copyright 1989, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler, GDB, the GNU debugger, and +the GNU Binutils. + +GAS/GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GAS/GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS or GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * $Id: sparc.h,v 1.1 1993/11/03 00:56:11 paul Exp $ + */ + + /* FIXME-someday: perhaps the ,a's and such should be embedded in the + instruction's name rather than the args. This would make gas faster, pinsn + slower, but would mess up some macros a bit. xoxorich. */ + +#if !defined(__STDC__) && !defined(const) +#define const +#endif + +/* + * Structure of an opcode table entry. + */ +enum sparc_architecture { + v6 = 0, + v7, + v8, +}; + +static const char *architecture_pname[] = { + "v6", + "v7", + "v8", + NULL, +}; + +struct sparc_opcode { + const char *name; + unsigned long match; /* Bits that must be set. */ + unsigned long lose; /* Bits that must not be set. */ + const char *args; + /* This was called "delayed" in versions before the flags. */ + char flags; + enum sparc_architecture architecture; +}; + +#define F_DELAYED 1 /* Delayed branch */ +#define F_ALIAS 2 /* Alias for a "real" instruction */ + +/* + +All sparc opcodes are 32 bits, except for the `set' instruction (really a +macro), which is 64 bits. It is handled as a special case. + +The match component is a mask saying which bits must match a particular +opcode in order for an instruction to be an instance of that opcode. + +The args component is a string containing one character for each operand of the +instruction. + +Kinds of operands: + # Number used by optimizer. It is ignored. + 1 rs1 register. + 2 rs2 register. + d rd register. + e frs1 floating point register. + v frs1 floating point register (double/even). + V frs1 floating point register (quad/multiple of 4). + f frs2 floating point register. + B frs2 floating point register (double/even). + R frs2 floating point register (quad/multiple of 4). + g frsd floating point register. + H frsd floating point register (double/even). + J frsd floating point register (quad/multiple of 4). + b crs1 coprocessor register + c crs2 coprocessor register + D crsd coprocessor register + m alternate space register (asr) in rd + M alternate space register (asr) in rs1 + h 22 high bits. + i 13 bit Immediate. + n 22 bit immediate. + l 22 bit PC relative immediate. + L 30 bit PC relative immediate. + a Annul. The annul bit is set. + A Alternate address space. Stored as 8 bits. + C Coprocessor state register. + F floating point state register. + p Processor state register. + q Floating point queue. + r Single register that is both rs1 and rsd. + Q Coprocessor queue. + S Special case. + x Single register that is both rs2 and rsd. + t Trap base register. + w Window invalid mask register. + y Y register. + +The following chars are unused: (note: ,[] are used as punctuation) +[oOX3450] + +*/ + +/* The order of the opcodes in this table is significant: + + * The assembler requires that all instances of the same mnemonic must + be consecutive. If they aren't, the assembler will bomb at runtime. + + * The disassembler should not care about the order of the opcodes. + +*/ + +#define OP2(x) (((x)&0x7) << 22) /* op2 field of format2 insns */ +#define OP3(x) (((x)&0x3f) << 19) /* op3 field of format3 insns */ +#define OP(x) (((x)&0x3) << 30) /* op field of all insns */ +#define OPF(x) (((x)&0x1ff) << 5) /* opf field of float insns */ +#define F3F(x, y, z) (OP(x) | OP3(y) | OPF(z)) /* format3 float insns */ +#define F3I(x) (((x)&0x1) << 13) /* immediate field of format 3 insns */ +#define F2(x, y) (OP(x) | OP2(y)) /* format 2 insns */ +#define F3(x, y, z) (OP(x) | OP3(y) | F3I(z)) /* format3 insns */ +#define F1(x) (OP(x)) +#define DISP30(x) ((x)&0x3fffffff) +#define ASI(x) (((x)&0xff) << 5) /* asi field of format3 insns */ +#define RS2(x) ((x)&0x1f) /* rs2 field */ +#define SIMM13(x) ((x)&0x1fff) /* simm13 field */ +#define RD(x) (((x)&0x1f) << 25) /* destination register field */ +#define RS1(x) (((x)&0x1f) << 14) /* rs1 field */ +#define ASI_RS2(x) (SIMM13(x)) + +#define ANNUL (1<<29) +#define IMMED F3I(1) +#define RD_G0 RD(~0) +#define RS1_G0 RS1(~0) +#define RS2_G0 RS2(~0) + +#define COND(x) (((x)&0xf)<<25) + +#define CONDA (COND(0x8)) +#define CONDCC (COND(0xd)) +#define CONDCS (COND(0x5)) +#define CONDE (COND(0x1)) +#define CONDG (COND(0xa)) +#define CONDGE (COND(0xb)) +#define CONDGU (COND(0xc)) +#define CONDL (COND(0x3)) +#define CONDLE (COND(0x2)) +#define CONDLEU (COND(0x4)) +#define CONDN (COND(0x0)) +#define CONDNE (COND(0x9)) +#define CONDNEG (COND(0x6)) +#define CONDPOS (COND(0xe)) +#define CONDVC (COND(0xf)) +#define CONDVS (COND(0x7)) + +#define CONDNZ CONDNE +#define CONDZ CONDE +#define CONDGEU CONDCC +#define CONDLU CONDCS + +#define FCONDA (COND(0x8)) +#define FCONDE (COND(0x9)) +#define FCONDG (COND(0x6)) +#define FCONDGE (COND(0xb)) +#define FCONDL (COND(0x4)) +#define FCONDLE (COND(0xd)) +#define FCONDLG (COND(0x2)) +#define FCONDN (COND(0x0)) +#define FCONDNE (COND(0x1)) +#define FCONDO (COND(0xf)) +#define FCONDU (COND(0x7)) +#define FCONDUE (COND(0xa)) +#define FCONDUG (COND(0x5)) +#define FCONDUGE (COND(0xc)) +#define FCONDUL (COND(0x3)) +#define FCONDULE (COND(0xe)) + +#define FCONDNZ FCONDNE +#define FCONDZ FCONDE + + +static const struct sparc_opcode sparc_opcodes[] = { + +{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", 0, v6 }, +{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ld [rs1+0],d */ +{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0), "[1+2],g", 0, v6 }, +{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0)|RS2_G0, "[1],g", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[1+i],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[i+1],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|RS1_G0, "[i],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|SIMM13(~0), "[1],g", 0, v6 }, /* ld [rs1+0],d */ +{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0), "[1+2],F", 0, v6 }, +{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RS2_G0, "[1],F", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1), "[1+i],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1), "[i+1],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RS1_G0, "[i],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|SIMM13(~0), "[1],F", 0, v6 }, /* ld [rs1+0],d */ +{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2],D", 0, v6 }, +{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0, "[1],D", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[1+i],D", 0, v6 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[i+1],D", 0, v6 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0, "[i],D", 0, v6 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0), "[1],D", 0, v6 }, /* ld [rs1+0],d */ +{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0), "[1+2],C", 0, v6 }, +{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0)|RS2_G0, "[1],C", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[1+i],C", 0, v6 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[i+1],C", 0, v6 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|RS1_G0, "[i],C", 0, v6 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|SIMM13(~0), "[1],C", 0, v6 }, /* ld [rs1+0],d */ + + + +{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0), "[1+2]A,d", 0, v6 }, +{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lda [rs1+%g0],d */ + +{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[1+i],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[i+1],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldd [rs1+0],d */ +{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI(~0), "[1+2],g", 0, v6 }, +{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI_RS2(~0), "[1],g", 0, v6 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[1+i],g", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[i+1],g", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|RS1_G0, "[i],g", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|SIMM13(~0), "[1],g", 0, v6 }, /* ldd [rs1+0],d */ +{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI(~0), "[1+2],D", 0, v6 }, +{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI_RS2(~0), "[1],D", 0, v6 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[1+i],D", 0, v6 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[i+1],D", 0, v6 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0, "[i],D", 0, v6 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0), "[1],D", 0, v6 }, /* ldd [rs1+0],d */ +{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsb [rs1+%g0],d */ +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[1+i],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[i+1],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsb [rs1+0],d */ +{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsh [rs1+%g0],d */ +{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[1+i],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[i+1],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsh [rs1+0],d */ +{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldstub [rs1+%g0],d */ +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[1+i],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[i+1],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldub [rs1+%g0],d */ +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[1+i],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[i+1],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldub [rs1+0],d */ +{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* lduh [rs1+%g0],d */ +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[1+i],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[i+1],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* lduh [rs1+0],d */ + + +{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0), "[1+2]A,d", 0, v6 }, +{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldda [rs1+%g0],d */ +{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0), "[1+2]A,d", 0, v6 }, +{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsba [rs1+%g0],d */ +{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0), "[1+2]A,d", 0, v6 }, +{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsha [rs1+%g0],d */ +{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0), "[1+2]A,d", 0, v6 }, +{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldstuba [rs1+%g0],d */ +{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0), "[1+2]A,d", 0, v6 }, +{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduba [rs1+%g0],d */ +{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0), "[1+2]A,d", 0, v6 }, +{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduha [rs1+%g0],d */ + +{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* st d,[rs1+0] */ +{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI(~0), "g,[1+2]", 0, v6 }, +{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI_RS2(~0), "g,[1]", 0, v6 }, /* st d[rs1+%g0] */ +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[1+i]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[i+1]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|RS1_G0, "g,[i]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|SIMM13(~0), "g,[1]", 0, v6 }, /* st d,[rs1+0] */ +{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI(~0), "D,[1+2]", 0, v6 }, +{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI_RS2(~0), "D,[1]", 0, v6 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[1+i]", 0, v6 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[i+1]", 0, v6 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0, "D,[i]", 0, v6 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0), "D,[1]", 0, v6 }, /* st d,[rs1+0] */ +{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI(~0), "C,[1+2]", 0, v6 }, +{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI_RS2(~0), "C,[1]", 0, v6 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[1+i]", 0, v6 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[i+1]", 0, v6 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|RS1_G0, "C,[i]", 0, v6 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|SIMM13(~0), "C,[1]", 0, v6 }, /* st d,[rs1+0] */ + +{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI(~0), "F,[1+2]", 0, v6 }, +{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI_RS2(~0), "F,[1]", 0, v6 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[1+i]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[i+1]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|RS1_G0, "F,[i]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|SIMM13(~0), "F,[1]", 0, v6 }, /* st d,[rs1+0] */ + + + + +{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", 0, v6 }, +{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* sta d,[rs1+%g0] */ + + + + +{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+%g0] */ +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+0] */ + + + +{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", 0, v6 }, +{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stba d,[rs1+%g0] */ + + + +{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[1+i]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[i+1]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* std d,[rs1+0] */ +{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0), "q,[1+2]", 0, v6 }, +{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0), "q,[1]", 0, v6 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[1+i]", 0, v6 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[i+1]", 0, v6 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0, "q,[i]", 0, v6 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0), "q,[1]", 0, v6 }, /* std d,[rs1+0] */ +{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI(~0), "g,[1+2]", 0, v6 }, +{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI_RS2(~0), "g,[1]", 0, v6 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "g,[1+i]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "g,[i+1]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|RS1_G0, "g,[i]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|SIMM13(~0), "g,[1]", 0, v6 }, /* std d,[rs1+0] */ +{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0), "Q,[1+2]", 0, v6 }, +{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0), "Q,[1]", 0, v6 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[1+i]", 0, v6 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[i+1]", 0, v6 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0, "Q,[i]", 0, v6 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0), "Q,[1]", 0, v6 }, /* std d,[rs1+0] */ +{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI(~0), "D,[1+2]", 0, v6 }, +{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI_RS2(~0), "D,[1]", 0, v6 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[1+i]", 0, v6 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[i+1]", 0, v6 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0, "D,[i]", 0, v6 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0), "D,[1]", 0, v6 }, /* std d,[rs1+0] */ + +{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0), "d,[1+2]A", 0, v6 }, +{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stda d,[rs1+%g0] */ + +{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* sth d,[rs1+%g0] */ +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* sth d,[+] */ + + + +{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", 0, v6 }, +{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stha ,[+%] */ + + + + + +{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI(~0), "[1+2],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI_RS2(~0), "[1],d", 0, v7 }, /* swap [rs1+%g0],d */ +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[1+i],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[i+1],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|RS1_G0, "[i],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|SIMM13(~0), "[1],d", 0, v7 }, /* swap [rs1+0],d */ + +{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0), "[1+2]A,d", 0, v7 }, +{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0)|RS2(~0), "[1]A,d", 0, v7 }, /* swapa [rs1+%g0],d */ + +{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "", 0, v6 }, /* restore %g0,%g0,%g0 */ +{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1), "1,i,d", 0, v6 }, +{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1)|RD_G0|RS1_G0|SIMM13(~0), "", 0, v6 }, /* restore %g0,0,%g0 */ + +{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI(~0), "1+2", F_DELAYED, v6 }, /* rett rs1+rs2 */ +{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI_RS2(~0), "1", F_DELAYED, v6 }, /* rett rs1,%g0 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "1+i", F_DELAYED, v6 }, /* rett rs1+X */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "i+1", F_DELAYED, v6 }, /* rett X+rs1 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0,"i", F_DELAYED, v6 }, /* rett X+rs1 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0, "i", F_DELAYED, v6 }, /* rett X */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|SIMM13(~0), "1", F_DELAYED, v6 }, /* rett rs1+0 */ + +{ "save", F3(2, 0x3c, 0), F3(~2, ~0x3c, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "save", F3(2, 0x3c, 1), F3(~2, ~0x3c, ~1), "1,i,d", 0, v6 }, + +{ "ret", F3(2, 0x38, 1)|RS1(0x1f)|SIMM13(8), F3(~2, ~0x38, ~1)|SIMM13(~8), "", F_DELAYED, v6 }, /* jmpl %i7+8,%g0 */ +{ "retl", F3(2, 0x38, 1)|RS1(0x0f)|SIMM13(8), F3(~2, ~0x38, ~1)|RS1(~0x0f)|SIMM13(~8), "", F_DELAYED, v6 }, /* jmpl %o7+8,%g0 */ + +{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI(~0), "1+2,d", F_DELAYED, v6 }, +{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI_RS2(~0), "1,d", F_DELAYED, v6 }, /* jmpl rs1+%g0,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|SIMM13(~0), "1,d", F_DELAYED, v6 }, /* jmpl rs1+0,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RS1_G0, "i,d", F_DELAYED, v6 }, /* jmpl %g0+i,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "1+i,d", F_DELAYED, v6 }, +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "i+1,d", F_DELAYED, v6 }, +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RS1_G0, "i,d", F_DELAYED, v6 }, + + /* The 1<<12 is a long story. It is necessary. For more info, please contact rich@cygnus.com */ +{ "sll", F3(2, 0x25, 0), F3(~2, ~0x25, ~0)|(1<<12)|ASI(~0), "1,2,d", 0, v6 }, +{ "sll", F3(2, 0x25, 1), F3(~2, ~0x25, ~1)|(1<<12), "1,i,d", 0, v6 }, +{ "sra", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0), "1,2,d", 0, v6 }, +{ "sra", F3(2, 0x27, 1), F3(~2, ~0x27, ~1)|(1<<12), "1,i,d", 0, v6 }, +{ "srl", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0), "1,2,d", 0, v6 }, +{ "srl", F3(2, 0x26, 1), F3(~2, ~0x26, ~1)|(1<<12), "1,i,d", 0, v6 }, + + + +{ "mulscc", F3(2, 0x24, 0), F3(~2, ~0x24, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "mulscc", F3(2, 0x24, 1), F3(~2, ~0x24, ~1), "1,i,d", 0, v6 }, + +{ "clr", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "d", F_ALIAS, v6 }, /* or %g0,%g0,d */ +{ "clr", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0|SIMM13(~0), "d", F_ALIAS, v6 }, /* or %g0,0,d */ +{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+%g0] */ +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+0] */ + +{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+%g0] */ +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, + +{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+%g0] */ +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, + +{ "orcc", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "1,i,d", 0, v6 }, +{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "i,1,d", 0, v6 }, + +{ "orncc", F3(2, 0x16, 0), F3(~2, ~0x16, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orncc", F3(2, 0x16, 1), F3(~2, ~0x16, ~1), "1,i,d", 0, v6 }, +{ "orncc", F3(2, 0x16, 1), F3(~2, ~0x16, ~1), "i,1,d", 0, v6 }, + +{ "orn", F3(2, 0x06, 0), F3(~2, ~0x06, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orn", F3(2, 0x06, 1), F3(~2, ~0x06, ~1), "1,i,d", 0, v6 }, +{ "orn", F3(2, 0x06, 1), F3(~2, ~0x06, ~1), "i,1,d", 0, v6 }, + +{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|ASI_RS2(~0), "1", 0, v6 }, /* orcc rs1, %g0, %g0 */ +{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|RS1_G0|ASI(~0), "2", 0, v6 }, /* orcc %g0, rs2, %g0 */ +{ "tst", F3(2, 0x12, 1), F3(~2, ~0x12, ~1)|RD_G0|SIMM13(~0), "1", 0, v6 }, /* orcc rs1, 0, %g0 */ + +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", 0, v8 }, /* wr r,r,%asrX */ +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", 0, v6 }, /* wr r,r,%y */ +{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", 0, v8 }, /* wr r,i,%asrX */ +{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", 0, v6 }, /* wr r,i,%y */ +{ "wr", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", 0, v6 }, /* wr r,r,%psr */ +{ "wr", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", 0, v6 }, /* wr r,i,%psr */ +{ "wr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", 0, v6 }, /* wr r,r,%wim */ +{ "wr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", 0, v6 }, /* wr r,i,%wim */ +{ "wr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", 0, v6 }, /* wr r,r,%tbr */ +{ "wr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", 0, v6 }, /* wr r,i,%tbr */ + + +{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", 0, v8 }, /* rd %asr1,r */ +{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", 0, v6 }, /* rd %y,r */ +{ "rd", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", 0, v6 }, /* rd %tbr,r */ + +{ "rd", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", 0, v6 }, /* rd %psr,r */ +{ "rd", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", 0, v6 }, /* rd %wim,r */ + +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", F_ALIAS, v8 }, /* wr r,r,%asrX */ +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", F_ALIAS, v6 }, /* wr r,r,%y */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", F_ALIAS, v8 }, /* wr r,i,%asrX */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", F_ALIAS, v6 }, /* wr r,i,%y */ +{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", F_ALIAS, v6 }, /* wr r,r,%psr */ +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", F_ALIAS, v6 }, /* wr r,i,%psr */ +{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", F_ALIAS, v6 }, /* wr r,r,%wim */ +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", F_ALIAS, v6 }, /* wr r,i,%wim */ +{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", F_ALIAS, v6 }, /* wr r,r,%tbr */ +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", F_ALIAS, v6 }, /* wr r,i,%tbr */ + +{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", F_ALIAS, v8 }, /* rd %asr1,r */ +{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", F_ALIAS, v6 }, /* rd %y,r */ +{ "mov", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", F_ALIAS, v6 }, /* rd %psr,r */ +{ "mov", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", F_ALIAS, v6 }, /* rd %wim,r */ +{ "mov", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", F_ALIAS, v6 }, /* rd %tbr,r */ + +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "i,y", F_ALIAS, v6 }, +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|SIMM13(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,0,%y */ +{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|ASI_RS2(~0), "1,p", F_ALIAS, v6 }, /* wr rs1,%g0,%psr */ +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1), "i,p", F_ALIAS, v6 }, +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|SIMM13(~0), "1,p", F_ALIAS, v6 }, /* wr rs1,0,%psr */ +{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|ASI_RS2(~0), "1,w", F_ALIAS, v6 }, /* wr rs1,%g0,%wim */ +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "i,w", F_ALIAS, v6 }, +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|SIMM13(~0), "1,w", F_ALIAS, v6 }, /* wr rs1,0,%wim */ +{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|ASI_RS2(~0), "1,t", F_ALIAS, v6 }, /* wr rs1,%g0,%tbr */ +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1), "i,t", F_ALIAS, v6 }, +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|SIMM13(~0), "1,t", F_ALIAS, v6 }, /* wr rs1,0,%tbr */ + +{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RS1_G0|ASI(~0), "2,d", 0, v6 }, /* or %g0,rs2,d */ +{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0, "i,d", 0, v6 }, /* or %g0,i,d */ +{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI_RS2(~0), "1,d", 0, v6 }, /* or rs1,%g0,d */ +{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|SIMM13(~0), "1,d", 0, v6 }, /* or rs1,0,d */ + +{ "or", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "1,i,d", 0, v6 }, +{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,1,d", 0, v6 }, + +{ "bset", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* or rd,rs2,rd */ +{ "bset", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,r", F_ALIAS, v6 }, /* or rd,i,rd */ + +{ "andn", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andn", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "1,i,d", 0, v6 }, +{ "andn", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "i,1,d", 0, v6 }, + +{ "andncc", F3(2, 0x15, 0), F3(~2, ~0x15, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andncc", F3(2, 0x15, 1), F3(~2, ~0x15, ~1), "1,i,d", 0, v6 }, +{ "andncc", F3(2, 0x15, 1), F3(~2, ~0x15, ~1), "i,1,d", 0, v6 }, + +{ "bclr", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* andn rd,rs2,rd */ +{ "bclr", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "i,r", F_ALIAS, v6 }, /* andn rd,i,rd */ + +{ "cmp", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|RD_G0|ASI(~0), "1,2", 0, v6 }, /* subcc rs1,rs2,%g0 */ +{ "cmp", F3(2, 0x14, 1), F3(~2, ~0x14, ~1)|RD_G0, "1,i", 0, v6 }, /* subcc rs1,i,%g0 */ + +{ "sub", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "sub", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "1,i,d", 0, v6 }, + +{ "subcc", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "subcc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "1,i,d", 0, v6 }, + +{ "subx", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "subx", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v6 }, + +{ "subxcc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "subxcc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v6 }, + +{ "and", F3(2, 0x01, 0), F3(~2, ~0x01, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "1,i,d", 0, v6 }, +{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "i,1,d", 0, v6 }, + +{ "andcc", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "1,i,d", 0, v6 }, +{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "i,1,d", 0, v6 }, + +{ "dec", F3(2, 0x04, 1)|SIMM13(0x1), F3(~2, ~0x04, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* sub rd,1,rd */ +{ "dec", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "i,r", F_ALIAS, v6 }, /* sub rd,i,rd */ +{ "deccc", F3(2, 0x14, 1)|SIMM13(0x1), F3(~2, ~0x14, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* subcc rd,1,rd */ +{ "deccc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "i,r", F_ALIAS, v6 }, /* subcc rd,i,rd */ +{ "inc", F3(2, 0x00, 1)|SIMM13(0x1), F3(~2, ~0x00, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* add rs1,1,rsd */ +{ "inc", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,r", F_ALIAS, v6 }, /* add rs1,i,rsd */ +{ "inccc", F3(2, 0x10, 1)|SIMM13(0x1), F3(~2, ~0x10, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* addcc rd,1,rd */ +{ "inccc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,r", F_ALIAS, v6 }, /* addcc rd,i,rd */ + +{ "btst", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|RD_G0|ASI(~0), "1,2", F_ALIAS, v6 }, /* andcc rs1,rs2,%g0 */ +{ "btst", F3(2, 0x11, 1), F3(~2, ~0x11, ~1)|RD_G0, "i,1", F_ALIAS, v6 }, /* andcc rs1,i,%g0 */ + +{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "2,d", F_ALIAS, v6 }, /* sub %g0,rs2,rd */ +{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "x", F_ALIAS, v6 }, /* sub %g0,rd,rd */ + +{ "add", F3(2, 0x00, 0), F3(~2, ~0x00, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "1,i,d", 0, v6 }, +{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,1,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 0), F3(~2, ~0x10, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "1,i,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,1,d", 0, v6 }, +{ "addx", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v6 }, +{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v6 }, +{ "addxcc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v6 }, +{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v6 }, + +{ "smul", F3(2, 0x0b, 0), F3(~2, ~0x0b, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "1,i,d", 0, v8 }, +{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "i,1,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 0), F3(~2, ~0x1b, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "1,i,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "i,1,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 0), F3(~2, ~0x0a, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "1,i,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "i,1,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 0), F3(~2, ~0x1a, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "1,i,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "i,1,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 0), F3(~2, ~0x0f, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "1,i,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "i,1,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 0), F3(~2, ~0x1f, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "1,i,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "i,1,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 0), F3(~2, ~0x0e, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "1,i,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "i,1,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 0), F3(~2, ~0x1e, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "1,i,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "i,1,d", 0, v8 }, + + +{ "call", F1(0x1), F1(~0x1), "L", F_DELAYED, v6 }, +{ "call", F1(0x1), F1(~0x1), "L,#", F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1", F_DELAYED, v6 }, /* jmpl rs1+%g0, %o7 */ +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1,#", F_DELAYED, v6 }, + +/* Conditional instructions. + + Because this part of the table was such a mess earlier, I have + macrofied it so that all the branches and traps are generated from + a single-line description of each condition value. John Gilmore. */ + +/* Define branches -- one annulled, one without, etc. */ +#define br(opcode, mask, lose, flags) \ + { opcode, (mask)|ANNUL, (lose), ",a l", (flags), v6 }, \ + { opcode, (mask) , (lose)|ANNUL, "l", (flags), v6 } + + +/* Define four traps: reg+reg, reg + immediate, immediate alone, reg alone. */ +#define tr(opcode, mask, lose, flags) \ + { opcode, (mask)|IMMED, (lose)|RS1_G0, "i", (flags), v6 }, /* %g0 + imm */ \ + { opcode, (mask)|IMMED, (lose), "1+i", (flags), v6 }, /* rs1 + imm */ \ + { opcode, (mask), IMMED|(lose), "1+2", (flags), v6 }, /* rs1 + rs2 */ \ + { opcode, (mask), IMMED|(lose)|RS2_G0, "1", (flags), v6 } /* rs1 + %g0 */ + +/* Define both branches and traps based on condition mask */ +#define cond(bop, top, mask, flags) \ + br(bop, F2(0, 2)|(mask), F2(~0, ~2)|((~mask)&COND(~0)), F_DELAYED|(flags)), \ + tr(top, F3(2, 0x3a, 0)|(mask), F3(~2, ~0x3a, 0)|((~mask)&COND(~0)), (flags)) + +/* Define all the conditions, all the branches, all the traps. */ + +cond ("b", "t", CONDA, 0), +cond ("ba", "ta", CONDA, F_ALIAS), /* for nothing */ +cond ("bcc", "tcc", CONDCC, 0), +cond ("bcs", "tcs", CONDCS, 0), +cond ("be", "te", CONDE, 0), +cond ("bg", "tg", CONDG, 0), +cond ("bgt", "tgt", CONDG, F_ALIAS), +cond ("bge", "tge", CONDGE, 0), +cond ("bgeu", "tgeu", CONDGEU, F_ALIAS), /* for cc */ +cond ("bgu", "tgu", CONDGU, 0), +cond ("bl", "tl", CONDL, 0), +cond ("blt", "tlt", CONDL, F_ALIAS), +cond ("ble", "tle", CONDLE, 0), +cond ("bleu", "tleu", CONDLEU, 0), +cond ("blu", "tlu", CONDLU, F_ALIAS), /* for cs */ +cond ("bn", "tn", CONDN, 0), +cond ("bne", "tne", CONDNE, 0), +cond ("bneg", "tneg", CONDNEG, 0), +cond ("bnz", "tnz", CONDNZ, F_ALIAS), /* for ne */ +cond ("bpos", "tpos", CONDPOS, 0), +cond ("bvc", "tvc", CONDVC, 0), +cond ("bvs", "tvs", CONDVS, 0), +cond ("bz", "tz", CONDZ, F_ALIAS), /* for e */ + +#undef cond +#undef br +#undef tr + + + + + + + + + + + + + + + + +#define brfc(opcode, mask, lose, flags) \ + { opcode, (mask), ANNUL|(lose), "l", flags|F_DELAYED, v6 }, \ + { opcode, (mask)|ANNUL, (lose), ",a l", flags|F_DELAYED, v6 } + + +#define condfc(fop, cop, mask, flags) \ + brfc(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \ + brfc(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags) \ + +condfc("fb", "cb", 0x8, 0), +condfc("fba", "cba", 0x8, F_ALIAS), +condfc("fbe", "cb0", 0x9, 0), +condfc("fbg", "cb2", 0x6, 0), +condfc("fbge", "cb02", 0xb, 0), +condfc("fbl", "cb1", 0x4, 0), +condfc("fble", "cb01", 0xd, 0), +condfc("fblg", "cb12", 0x2, 0), +condfc("fbn", "cbn", 0x0, 0), +condfc("fbne", "cb123", 0x1, 0), +condfc("fbo", "cb012", 0xf, 0), +condfc("fbu", "cb3", 0x7, 0), +condfc("fbue", "cb03", 0xa, 0), +condfc("fbug", "cb23", 0x5, 0), +condfc("fbuge", "cb023", 0xc, 0), +condfc("fbul", "cb13", 0x3, 0), +condfc("fbule", "cb013", 0xe, 0), + +#undef condfc +#undef brfc + +{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI(~0), "1+2", F_DELAYED, v6 }, /* jmpl rs1+rs2,%g0 */ +{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI_RS2(~0), "1", F_DELAYED, v6 }, /* jmpl rs1+%g0,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "1+i", F_DELAYED, v6 }, /* jmpl rs1+i,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "i+1", F_DELAYED, v6 }, /* jmpl i+rs1,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|RS1_G0, "i", F_DELAYED, v6 }, /* jmpl %g0+i,%g0 */ + +{ "nop", F2(0, 4), 0xfeffffff, "", 0, v6 }, /* sethi 0, %g0 */ + +{ "set", F2(0x0, 0x4), F2(~0x0, ~0x4), "Sh,d", F_ALIAS, v6 }, + +{ "sethi", F2(0x0, 0x4), F2(~0x0, ~0x4), "h,d", 0, v6 }, + +{ "taddcc", F3(2, 0x20, 0), F3(~2, ~0x20, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "1,i,d", 0, v6 }, +{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "i,1,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 0), F3(~2, ~0x22, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "1,i,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "i,1,d", 0, v6 }, + +{ "tsubcc", F3(2, 0x21, 0), F3(~2, ~0x21, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "tsubcc", F3(2, 0x21, 1), F3(~2, ~0x21, ~1), "1,i,d", 0, v6 }, +{ "tsubcctv", F3(2, 0x23, 0), F3(~2, ~0x23, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "tsubcctv", F3(2, 0x23, 1), F3(~2, ~0x23, ~1), "1,i,d", 0, v6 }, + +{ "unimp", F2(0x0, 0x0), 0xffc00000, "n", 0, v6 }, + +{ "iflush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", 0, v6 }, +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "1+i", 0, v6 }, +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "i+1", 0, v6 }, +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0, "i", 0, v6 }, + +{ "xnor", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "1,i,d", 0, v6 }, +{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "i,1,d", 0, v6 }, +{ "xnorcc", F3(2, 0x17, 0), F3(~2, ~0x17, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "1,i,d", 0, v6 }, +{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "i,1,d", 0, v6 }, +{ "xor", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "1,i,d", 0, v6 }, +{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,1,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 0), F3(~2, ~0x13, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "1,i,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "i,1,d", 0, v6 }, + +{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,d", F_ALIAS, v6 }, /* xnor rs1,%0,rd */ +{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "r", F_ALIAS, v6 }, /* xnor rd,%0,rd */ + +{ "btog", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* xor rd,rs2,rd */ +{ "btog", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,r", F_ALIAS, v6 }, /* xor rd,i,rd */ + +{ "fpop1", F3F(2, 0x34, 0), F3F(~2, ~0x34, ~1), "[1+2],d", 0, v6 }, +{ "fpop2", F3F(2, 0x35, 0), F3F(~2, ~0x35, ~1), "[1+2],d", 0, v6 }, + +/* float-start */ +{ "fdtoi", F3F(2, 0x34, 0x0d2), F3F(~2, ~0x34, ~0x0d2)|RS1_G0, "B,g", 0, v6 }, +{ "fstoi", F3F(2, 0x34, 0x0d1), F3F(~2, ~0x34, ~0x0d1)|RS1_G0, "f,g", 0, v6 }, + + /* all of these conversions are confused and probably wrong. */ +{ "fitod", F3F(2, 0x34, 0x0c8), F3F(~2, ~0x34, ~0x0c8)|RS1_G0, "f,H", 0, v6 }, +{ "fitos", F3F(2, 0x34, 0x0c4), F3F(~2, ~0x34, ~0x0c4)|RS1_G0, "f,g", 0, v6 }, + +{ "fitoq", F3F(2, 0x34, 0x0cc), F3F(~2, ~0x34, ~0x0cc)|RS1_G0, "f,J", 0, v8 }, + + +{ "fdtoq", F3F(2, 0x34, 0x0ce), F3F(~2, ~0x34, ~0x0ce)|RS1_G0, "B,J", 0, v8 }, +{ "fdtos", F3F(2, 0x34, 0x0c6), F3F(~2, ~0x34, ~0x0c6)|RS1_G0, "B,g", 0, v6 }, +{ "fqtod", F3F(2, 0x34, 0x0cb), F3F(~2, ~0x34, ~0x0cb)|RS1_G0, "R,H", 0, v8 }, +{ "fqtos", F3F(2, 0x34, 0x0c7), F3F(~2, ~0x34, ~0x0c7)|RS1_G0, "R,g", 0, v8 }, +{ "fstod", F3F(2, 0x34, 0x0c9), F3F(~2, ~0x34, ~0x0c9)|RS1_G0, "f,H", 0, v6 }, +{ "fstoq", F3F(2, 0x34, 0x0cd), F3F(~2, ~0x34, ~0x0cd)|RS1_G0, "f,J", 0, v8 }, + + + + + +{ "fqtoi", F3F(2, 0x34, 0x0d3), F3F(~2, ~0x34, ~0x0d3)|RS1_G0, "R,g", 0, v8 }, + + +{ "fdivd", F3F(2, 0x34, 0x04e), F3F(~2, ~0x34, ~0x04e), "v,B,H", 0, v6 }, +{ "fdivq", F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", 0, v8 }, +{ "fdivs", F3F(2, 0x34, 0x04d), F3F(~2, ~0x34, ~0x04d), "e,f,g", 0, v6 }, +{ "fmuld", F3F(2, 0x34, 0x04a), F3F(~2, ~0x34, ~0x04a), "v,B,H", 0, v6 }, +{ "fmulq", F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", 0, v8 }, +{ "fmuls", F3F(2, 0x34, 0x049), F3F(~2, ~0x34, ~0x049), "e,f,g", 0, v6 }, + +{ "fdmulq", F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", 0, v8 }, +{ "fsmuld", F3F(2, 0x34, 0x069), F3F(~2, ~0x34, ~0x069), "e,f,H", 0, v8 }, + +{ "fsqrtd", F3F(2, 0x34, 0x02a), F3F(~2, ~0x34, ~0x02a)|RS1_G0, "B,H", 0, v7 }, +{ "fsqrtq", F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", 0, v8 }, +{ "fsqrts", F3F(2, 0x34, 0x029), F3F(~2, ~0x34, ~0x029)|RS1_G0, "f,g", 0, v7 }, + +{ "fabsq", F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", 0, v6 }, +{ "fabss", F3F(2, 0x34, 0x009), F3F(~2, ~0x34, ~0x009)|RS1_G0, "f,g", 0, v6 }, +{ "fmovq", F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", 0, v6 }, +{ "fmovs", F3F(2, 0x34, 0x001), F3F(~2, ~0x34, ~0x001)|RS1_G0, "f,g", 0, v6 }, +{ "fnegq", F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", 0, v6 }, +{ "fnegs", F3F(2, 0x34, 0x005), F3F(~2, ~0x34, ~0x005)|RS1_G0, "f,g", 0, v6 }, + + +{ "faddd", F3F(2, 0x34, 0x042), F3F(~2, ~0x34, ~0x042), "v,B,H", 0, v6 }, +{ "faddq", F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", 0, v8 }, +{ "fadds", F3F(2, 0x34, 0x041), F3F(~2, ~0x34, ~0x041), "e,f,g", 0, v6 }, +{ "fsubd", F3F(2, 0x34, 0x046), F3F(~2, ~0x34, ~0x046), "v,B,H", 0, v6 }, +{ "fsubq", F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", 0, v8 }, +{ "fsubs", F3F(2, 0x34, 0x045), F3F(~2, ~0x34, ~0x045), "e,f,g", 0, v6 }, + +#define CMPFCC(x) (((x)&0x3)<<25) + +{ "fcmpd", F3F(2, 0x35, 0x052), F3F(~2, ~0x35, ~0x052)|RS1_G0, "v,B", 0, v6 }, +{ "fcmped", F3F(2, 0x35, 0x056), F3F(~2, ~0x35, ~0x056)|RS1_G0, "v,B", 0, v6 }, +{ "fcmpeq", F3F(2, 0x34, 0x057), F3F(~2, ~0x34, ~0x057), "V,R", 0, v8 }, +{ "fcmpes", F3F(2, 0x35, 0x055), F3F(~2, ~0x35, ~0x055)|RS1_G0, "e,f", 0, v6 }, +{ "fcmpq", F3F(2, 0x34, 0x053), F3F(~2, ~0x34, ~0x053), "V,R", 0, v8 }, +{ "fcmps", F3F(2, 0x35, 0x051), F3F(~2, ~0x35, ~0x051)|RS1_G0, "e,f", 0, v6 }, + +{ "cpop1", F3(2, 0x36, 0), F3(~2, ~0x36, ~1), "[1+2],d", 0, v6 }, +{ "cpop2", F3(2, 0x37, 0), F3(~2, ~0x37, ~1), "[1+2],d", 0, v6 }, + + + +}; + +#define NUMOPCODES ((sizeof sparc_opcodes)/(sizeof sparc_opcodes[0])) + +/* + * Local Variables: + * fill-column: 131 + * comment-column: 0 + * End: + */ + +/* end of sparc-opcode.h */ diff --git a/gnu/usr.bin/as/opcode/tahoe.h b/gnu/usr.bin/as/opcode/tahoe.h new file mode 100644 index 000000000000..27099a4db083 --- /dev/null +++ b/gnu/usr.bin/as/opcode/tahoe.h @@ -0,0 +1,247 @@ +/* tahoe-opcode.h - tahoe-specific + * Not part of GAS yet + * + * Ported by the State University of New York at Buffalo by the Distributed + * Computer Systems Lab, Department of Computer Science, 1991. (And by Dale + * Wiles who was unemployed at the time.) + */ + +struct tot_wot /* tahoe opcode table: wot to do with this */ + /* particular opcode */ +{ + char *args; /* how to compile said opcode */ + tahoe_opcodeT code; /* The opcode. */ +}; + +struct tot /* tahoe opcode text */ +{ + char *name; /* opcode name: lowercase string [key] */ + struct tot_wot detail; /* rest of opcode table [datum] */ +}; + +static struct tot +totstrs[] = +{ +{ "halt", {"", 0x00 } }, +{ "sinf", {"", 0x05 } }, +{ "ldf", {"rl", 0x06 } }, +{ "ldd", {"rq", 0x07 } }, +{ "addb2", {"rbmb", 0x08 } }, +{ "movb", {"rbwb", 0x09 } }, +{ "addw2", {"rwmw", 0x0a } }, +{ "movw", {"rwww", 0x0b } }, +{ "addl2", {"rlml", 0x0c } }, +{ "movl", {"rlwl", 0x0d } }, +{ "bbs", {"rlvlbw", 0x0e } }, +{ "nop", {"", 0x10 } }, +{ "brb", {"bb", 0x11 } }, +{ "brw", {"bw", 0x13 } }, +{ "cosf", {"", 0x15 } }, +{ "lnf", {"rl", 0x16 } }, +{ "lnd", {"rq", 0x17 } }, +{ "addb3", {"rbrbwb", 0x18 } }, + /* cmpb is wrong in the "offical" (what a joke!) text. It's not "rbwb" */ +{ "cmpb", {"rbrb", 0x19 } }, +{ "addw3", {"rwrwww", 0x1a } }, + /* cmpw is wrong in the "offical" text. It's not "rwww" */ +{ "cmpw", {"rwrw", 0x1b } }, +{ "addl3", {"rlrlwl", 0x1c } }, + /* cmpl is wrong in the "offical" text. It's not "rlwl" */ +{ "cmpl", {"rlrl", 0x1d } }, +{ "bbc", {"rlvlbw", 0x1e } }, +{ "rei", {"", 0x20 } }, +{ "bneq", {"bb", 0x21 } }, +{ "bnequ", {"bb", 0x21 } }, +{ "cvtwl", {"rwwl", 0x23 } }, +{ "stf", {"wl", 0x26 } }, +{ "std", {"wq", 0x27 } }, +{ "subb2", {"rbmb", 0x28 } }, +{ "mcomb", {"rbwb", 0x29 } }, +{ "subw2", {"rwmw", 0x2a } }, +{ "mcomw", {"rwww", 0x2b } }, +{ "subl2", {"rlml", 0x2c } }, +{ "mcoml", {"rlwl", 0x2d } }, +{ "emul", {"rlrlrlwq", 0x2e } }, +{ "aoblss", {"rlmlbw", 0x2f } }, +{ "bpt", {"", 0x30 } }, +{ "beql", {"bb", 0x31 } }, +{ "beqlu", {"bb", 0x31 } }, +{ "cvtwb", {"rwwb", 0x33 } }, +{ "logf", {"", 0x35 } }, +{ "cmpf", {"rl", 0x36 } }, +{ "cmpd", {"rq", 0x37 } }, +{ "subb3", {"rbrbwb", 0x38 } }, +{ "bitb", {"rbrb", 0x39 } }, +{ "subw3", {"rwrwww", 0x3a } }, +{ "bitw", {"rwrw", 0x3b } }, +{ "subl3", {"rlrlwl", 0x3c } }, +{ "bitl", {"rlrl", 0x3d } }, +{ "ediv", {"rlrqwlwl", 0x3e } }, +{ "aobleq", {"rlmlbw", 0x3f } }, +{ "ret", {"", 0x40 } }, +{ "bgtr", {"bb", 0x41 } }, +{ "sqrtf", {"", 0x45 } }, +{ "cmpf2", {"rlrl", 0x46 } }, +{ "cmpd2", {"rqrq", 0x47 } }, +{ "shll", {"rbrlwl", 0x48 } }, +{ "clrb", {"wb", 0x49 } }, +{ "shlq", {"rbrqwq", 0x4a } }, +{ "clrw", {"ww", 0x4b } }, +{ "mull2", {"rlml", 0x4c } }, +{ "clrl", {"wl", 0x4d } }, +{ "shal", {"rbrlwl", 0x4e } }, +{ "bleq", {"bb", 0x51 } }, +{ "expf", {"", 0x55 } }, +{ "tstf", {"", 0x56 } }, +{ "tstd", {"", 0x57 } }, +{ "shrl", {"rbrlwl", 0x58 } }, +{ "tstb", {"rb", 0x59 } }, +{ "shrq", {"rbrqwq", 0x5a } }, +{ "tstw", {"rw", 0x5b } }, +{ "mull3", {"rlrlwl", 0x5c } }, +{ "tstl", {"rl", 0x5d } }, +{ "shar", {"rbrlwl", 0x5e } }, +{ "bbssi", {"rlmlbw", 0x5f } }, +{ "ldpctx", {"", 0x60 } }, +{ "pushd", {"", 0x67 } }, +{ "incb", {"mb", 0x69 } }, +{ "incw", {"mw", 0x6b } }, +{ "divl2", {"rlml", 0x6c } }, +{ "incl", {"ml", 0x6d } }, +{ "cvtlb", {"rlwb", 0x6f } }, +{ "svpctx", {"", 0x70 } }, +{ "jmp", {"ab", 0x71 } }, +{ "cvlf", {"rl", 0x76 } }, +{ "cvld", {"rl", 0x77 } }, +{ "decb", {"mb", 0x79 } }, +{ "decw", {"mw", 0x7b } }, +{ "divl3", {"rlrlwl", 0x7c } }, +{ "decl", {"ml", 0x7d } }, +{ "cvtlw", {"rlww", 0x7f } }, +{ "bgeq", {"bb", 0x81 } }, +{ "movs2", {"abab", 0x82 } }, +{ "cvfl", {"wl", 0x86 } }, +{ "cvdl", {"wl", 0x87 } }, +{ "orb2", {"rbmb", 0x88 } }, +{ "cvtbl", {"rbwl", 0x89 } }, +{ "orw2", {"rwmw", 0x8a } }, +{ "bispsw", {"rw", 0x8b } }, +{ "orl2", {"rlml", 0x8c } }, +{ "adwc", {"rlml", 0x8d } }, +{ "adda", {"rlml", 0x8e } }, +{ "blss", {"bb", 0x91 } }, +{ "cmps2", {"abab", 0x92 } }, +{ "ldfd", {"rl", 0x97 } }, +{ "orb3", {"rbrbwb", 0x98 } }, +{ "cvtbw", {"rbww", 0x99 } }, +{ "orw3", {"rwrwww", 0x9a } }, +{ "bicpsw", {"rw", 0x9b } }, +{ "orl3", {"rlrlwl", 0x9c } }, +{ "sbwc", {"rlml", 0x9d } }, +{ "suba", {"rlml", 0x9e } }, +{ "bgtru", {"bb", 0xa1 } }, +{ "cvdf", {"", 0xa6 } }, +{ "andb2", {"rbmb", 0xa8 } }, +{ "movzbl", {"rbwl", 0xa9 } }, +{ "andw2", {"rwmw", 0xaa } }, +{ "loadr", {"rwal", 0xab } }, +{ "andl2", {"rlml", 0xac } }, +{ "mtpr", {"rlrl", 0xad } }, +{ "ffs", {"rlwl", 0xae } }, +{ "blequ", {"bb", 0xb1 } }, +{ "negf", {"", 0xb6 } }, +{ "negd", {"", 0xb7 } }, +{ "andb3", {"rbrbwb", 0xb8 } }, +{ "movzbw", {"rbww", 0xb9 } }, +{ "andw3", {"rwrwww", 0xba } }, +{ "storer", {"rwal", 0xbb } }, +{ "andl3", {"rlrlwl", 0xbc } }, +{ "mfpr", {"rlwl", 0xbd } }, +{ "ffc", {"rlwl", 0xbe } }, +{ "calls", {"rbab", 0xbf } }, +{ "prober", {"rbabrl", 0xc0 } }, +{ "bvc", {"bb", 0xc1 } }, +{ "movs3", {"ababrw", 0xc2 } }, +{ "movzwl", {"rwwl", 0xc3 } }, +{ "addf", {"rl", 0xc6 } }, +{ "addd", {"rq", 0xc7 } }, +{ "xorb2", {"rbmb", 0xc8 } }, +{ "movob", {"rbwb", 0xc9 } }, +{ "xorw2", {"rwmw", 0xca } }, +{ "movow", {"rwww", 0xcb } }, +{ "xorl2", {"rlml", 0xcc } }, +{ "movpsl", {"wl", 0xcd } }, +{ "kcall", {"rw", 0xcf } }, +{ "probew", {"rbabrl", 0xd0 } }, +{ "bvs", {"bb", 0xd1 } }, +{ "cmps3", {"ababrw", 0xd2 } }, +{ "subf", {"rq", 0xd6 } }, +{ "subd", {"rq", 0xd7 } }, +{ "xorb3", {"rbrbwb", 0xd8 } }, +{ "pushb", {"rb", 0xd9 } }, +{ "xorw3", {"rwrwww", 0xda } }, +{ "pushw", {"rw", 0xdb } }, +{ "xorl3", {"rlrlwl", 0xdc } }, +{ "pushl", {"rl", 0xdd } }, +{ "insque", {"abab", 0xe0 } }, +{ "bcs", {"bb", 0xe1 } }, +{ "bgequ", {"bb", 0xe1 } }, +{ "mulf", {"rq", 0xe6 } }, +{ "muld", {"rq", 0xe7 } }, +{ "mnegb", {"rbwb", 0xe8 } }, +{ "movab", {"abwl", 0xe9 } }, +{ "mnegw", {"rwww", 0xea } }, +{ "movaw", {"awwl", 0xeb } }, +{ "mnegl", {"rlwl", 0xec } }, +{ "moval", {"alwl", 0xed } }, +{ "remque", {"ab", 0xf0 } }, +{ "bcc", {"bb", 0xf1 } }, +{ "blssu", {"bb", 0xf1 } }, +{ "divf", {"rq", 0xf6 } }, +{ "divd", {"rq", 0xf7 } }, + /* movblk is really "alalrw" but 'as' won't accept it, + 'cc' and 'gcc' also produce code this way. */ +{ "movblk", {"", 0xf8 } }, +{ "pushab", {"ab", 0xf9 } }, +{ "pushaw", {"aw", 0xfb } }, +{ "casel", {"rlrlrl", 0xfc } }, +{ "pushal", {"al", 0xfd } }, +{ "callf", {"rbab", 0xfe } }, +{ "", "" } /* empty is end sentinel */ +}; + +/* These are synthetic instructions, where the assembler will munge + the addressings modes for you. */ +static struct tot +synthetic_totstrs[] = +{ +{ "jr", {"b-", 0x11 } }, +{ "jbr", {"b-", 0x11 } }, + +{ "jneq", {"b?", 0x21 } }, +{ "jnequ", {"b?", 0x21 } }, +{ "jeql", {"b?", 0x31 } }, +{ "jeqlu", {"b?", 0x31 } }, +{ "jgtr", {"b?", 0x41 } }, +{ "jleq", {"b?", 0x51 } }, +{ "jgeq", {"b?", 0x81 } }, +{ "jlss", {"b?", 0x91 } }, +{ "jgtru", {"b?", 0xa1 } }, +{ "jlequ", {"b?", 0xb1 } }, +{ "jvc", {"b?", 0xc1 } }, +{ "jvs", {"b?", 0xd1 } }, +{ "jcs", {"b?", 0xe1 } }, +{ "jgequ", {"b?", 0xe1 } }, +{ "jcc", {"b?", 0xf1 } }, +{ "jlssu", {"b?", 0xf1 } }, + +{ "jbs", {"rlvlb!", 0x0e } }, +{ "jbc", {"rlvlb!", 0x1e } }, + +{ "aojlss", {"rlmlb:", 0x2f } }, +{ "jaoblss", {"rlmlb:", 0x2f } }, +{ "aojleq", {"rlmlb:", 0x3f } }, +{ "jaobleq", {"rlmlb:", 0x3f } }, +{ "jbssi", {"rlmlb:", 0x5f } }, + { "", "" } /* empty is end sentinel */ +}; diff --git a/gnu/usr.bin/as/opcode/vax.h b/gnu/usr.bin/as/opcode/vax.h new file mode 100644 index 000000000000..d604e3f9c651 --- /dev/null +++ b/gnu/usr.bin/as/opcode/vax.h @@ -0,0 +1,382 @@ +/* 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 */ diff --git a/gnu/usr.bin/as/output-file.c b/gnu/usr.bin/as/output-file.c new file mode 100644 index 000000000000..95b23ea6a52b --- /dev/null +++ b/gnu/usr.bin/as/output-file.c @@ -0,0 +1,122 @@ +/* output-file.c - Deal with the output file + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 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! + */ + +/* note that we do need config info. xoxorich. */ + +#ifndef lint +static char rcsid[] = "$Id: output-file.c,v 1.2 1993/11/03 00:52:08 paul Exp $"; +#endif + +#include <stdio.h> + +#include "as.h" + +#include "output-file.h" +#ifdef BFD_HEADERS +#include "bfd.h" +bfd *stdoutput; +void output_file_create(name) +char *name; +{ + if (name[0] == '-' && name[1] == '\0') { + as_perror("FATAL: Can't open a bfd on stdout %s ", name); + } + else if ( ! (stdoutput = bfd_openw( name, TARGET_FORMAT )) ) + { + as_perror ("FATAL: Can't create %s", name); + exit(42); + } + bfd_set_format(stdoutput, bfd_object); +} +/* output_file_create() */ + + +void output_file_close(filename) +char *filename; +{ + /* Close the bfd without getting bfd to write out anything by itself */ + if ( bfd_close_all_done( stdoutput ) == 0 ) + { + as_perror ("FATAL: Can't close %s\n", filename); + exit(42); + } + stdoutput = NULL; /* Trust nobody! */ +} /* output_file_close() */ + +void output_file_append(where, length, filename) +char *where; +long length; +char *filename; +{ + abort(); /* Never do this */ +} + +#else + +static FILE *stdoutput; + +void output_file_create(name) +char *name; +{ + if (name[0] == '-' && name[1] == '\0') + stdoutput=stdout; + else if (!(stdoutput = fopen(name, "wb"))) { + as_perror("FATAL: Can't create %s", name); + exit(42); + } +} /* output_file_create() */ + + + +void output_file_close(filename) +char *filename; +{ + if (EOF == fclose(stdoutput)) { + as_perror ("FATAL: Can't close %s", filename); + exit(42); + } + stdoutput = NULL; /* Trust nobody! */ +} /* output_file_close() */ + +void output_file_append(where, length, filename) +char *where; +long length; +char *filename; +{ + + for (; length; length--, where++) { + (void) putc(*where, stdoutput); + if (ferror(stdoutput)) + /* if ( EOF == (putc( *where, stdoutput )) ) */ + { + as_perror("Failed to emit an object byte", filename); + as_fatal("Can't continue"); + } + } +} /* output_file_append() */ +#endif + +/* end of output-file.c */ diff --git a/gnu/usr.bin/as/output-file.h b/gnu/usr.bin/as/output-file.h new file mode 100644 index 000000000000..0e85aa665025 --- /dev/null +++ b/gnu/usr.bin/as/output-file.h @@ -0,0 +1,40 @@ +/* This file is output-file.h + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: output-file.h,v 1.1 1993/11/03 00:52:10 paul Exp $ + */ + + +#ifdef __STDC__ + +void output_file_append(char *where, long length, char *filename); +void output_file_close(char *filename); +void output_file_create(char *name); + +#else /* __STDC__ */ + +void output_file_append(); +void output_file_close(); +void output_file_create(); + +#endif /* __STDC__ */ + + +/* end of output-file.h */ diff --git a/gnu/usr.bin/as/read.c b/gnu/usr.bin/as/read.c new file mode 100644 index 000000000000..f43faacb9d64 --- /dev/null +++ b/gnu/usr.bin/as/read.c @@ -0,0 +1,2347 @@ +/* read.c - read a source file - + + Copyright (C) 1986, 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef lint +static char rcsid[] = "$Id: read.c,v 1.4 1993/12/12 17:01:16 jkh Exp $"; +#endif + +#define MASK_CHAR (0xFF) /* If your chars aren't 8 bits, you will + change this a bit. But then, GNU isn't + spozed to run on your machine anyway. + (RMS is so shortsighted sometimes.) + */ + +#define MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT (16) +/* This is the largest known floating point */ +/* format (for now). It will grow when we */ +/* do 4361 style flonums. */ + + +/* Routines that read assembler source text to build spagetti in memory. */ +/* Another group of these functions is in the as-expr.c module */ + +#include "as.h" + +#include "obstack.h" + +char *input_line_pointer; /*->next char of source file to parse. */ + +#ifndef NOP_OPCODE +# define NOP_OPCODE 0x00 +#endif + +#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 + +#ifdef ALLOW_ATSIGN +#define AT 2 +#else +#define AT 0 +#endif + +#ifndef PIC + const +#endif + 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:;<=>? */ + AT, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, /* PQRSTUVWXYZ[\]^_ */ + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, /* pqrstuvwxyz{|}~. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + +/* + * In: a character. + * Out: 1 if this character ends a line. + */ +#define _ (0) +char is_end_of_line[256] = { +#ifdef CR_EOL + _, _, _, _, _, _, _, _, _, _,99, _, _, 99, _, _,/* @abcdefghijklmno */ +#else + _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, _, /* @abcdefghijklmno */ +#endif + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, /* 0123456789:;<=>? */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ /* */ + }; +#undef _ + +/* Functions private to this file. */ + +extern const char line_comment_chars[]; +const char line_separator_chars[1]; + +static char *buffer; /* 1st char of each buffer of lines is here. */ +static char *buffer_limit; /*->1 + last char in buffer. */ + +static char *bignum_low; /* Lowest char of bignum. */ +static char *bignum_limit; /* 1st illegal address of bignum. */ +static char *bignum_high; /* Highest char of bignum. */ +/* May point to (bignum_start-1). */ +/* Never >= bignum_limit. */ +static char *old_buffer = 0; /* JF a hack */ +static char *old_input; +static char *old_limit; + +/* Variables for handling include file directory list. */ + +char **include_dirs; /* List of pointers to directories to + search for .include's */ +int include_dir_count; /* How many are in the list */ +int include_dir_maxlen = 1; /* Length of longest in list */ + +#ifndef WORKING_DOT_WORD +struct broken_word *broken_words; +int new_broken_words = 0; +#endif + +#if __STDC__ == 1 + +static char *demand_copy_string(int *lenP); +int is_it_end_of_statement(void); +unsigned int next_char_of_string(void); +static segT get_known_segmented_expression(expressionS *expP); +static void grow_bignum(void); +static void pobegin(void); +void stringer(int append_zero); + +#else /* __STDC__ */ + +static char *demand_copy_string(); +int is_it_end_of_statement(); +unsigned int next_char_of_string(); +static segT get_known_segmented_expression(); +static void grow_bignum(); +static void pobegin(); +void stringer(); + +#endif /* not __STDC__ */ + +extern int listing; + + +void + read_begin() +{ + const char *p; + + pobegin(); + obj_read_begin_hook(); + + obstack_begin(¬es, 5000); + obstack_begin(&cond_obstack, 960); + +#define BIGNUM_BEGIN_SIZE (16) + bignum_low = xmalloc((long)BIGNUM_BEGIN_SIZE); + bignum_limit = bignum_low + BIGNUM_BEGIN_SIZE; + + /* Use machine dependent syntax */ + for (p = line_separator_chars; *p; p++) + is_end_of_line[*p] = 1; + /* Use more. FIXME-SOMEDAY. */ +} + +/* set up pseudo-op tables */ + +struct hash_control * + po_hash = NULL; /* use before set up: NULL->address error */ + +static const pseudo_typeS + potable[] = +{ + { "abort", s_abort, 0 }, + { "align", s_align_ptwo, 0 }, + { "ascii", stringer, 0 }, + { "asciz", stringer, 1 }, + /* block */ + { "byte", cons, 1 }, + { "comm", s_comm, 0 }, + { "data", s_data, 0 }, + /* dim */ + { "double", float_cons, 'd' }, + /* dsect */ +#ifdef NO_LISTING + { "eject", s_ignore, 0 }, /* Formfeed listing */ +#else + { "eject", listing_eject, 0 }, /* Formfeed listing */ +#endif /* NO_LISTING */ + { "else", s_else, 0 }, + { "end", s_end, 0 }, + { "endif", s_endif, 0 }, + /* endef */ + { "equ", s_set, 0 }, + /* err */ + /* extend */ + { "extern", s_ignore, 0 }, /* We treat all undef as ext */ + { "app-file", s_app_file, 0 }, + { "file", s_app_file, 0 }, + { "fill", s_fill, 0 }, + { "float", float_cons, 'f' }, + { "global", s_globl, 0 }, + { "globl", s_globl, 0 }, + { "hword", cons, 2 }, + { "if", s_if, 0 }, + { "ifdef", s_ifdef, 0 }, + { "ifeqs", s_ifeqs, 0 }, + { "ifndef", s_ifdef, 1 }, + { "ifnes", s_ifeqs, 1 }, + { "ifnotdef", s_ifdef, 1 }, + { "include", s_include, 0 }, + { "int", cons, 4 }, + { "lcomm", s_lcomm, 0 }, +#ifdef NO_LISTING + { "lflags", s_ignore, 0 }, /* Listing flags */ + { "list", s_ignore, 1 }, /* Turn listing on */ +#else + { "lflags", listing_flags, 0 }, /* Listing flags */ + { "list", listing_list, 1 }, /* Turn listing on */ +#endif /* NO_LISTING */ + { "long", cons, 4 }, + { "lsym", s_lsym, 0 }, +#ifdef NO_LISTING + { "nolist", s_ignore, 0 }, /* Turn listing off */ +#else + { "nolist", listing_list, 0 }, /* Turn listing off */ +#endif /* NO_LISTING */ + { "octa", big_cons, 16 }, + { "org", s_org, 0 }, +#ifdef NO_LISTING + { "psize", s_ignore, 0 }, /* set paper size */ +#else + { "psize", listing_psize, 0 }, /* set paper size */ +#endif /* NO_LISTING */ + /* print */ + { "quad", big_cons, 8 }, +#ifdef NO_LISTING + { "sbttl", s_ignore, 1 }, /* Subtitle of listing */ +#else + { "sbttl", listing_title, 1 }, /* Subtitle of listing */ +#endif /* NO_LISTING */ + /* scl */ + /* sect */ +#ifndef TC_M88K + { "set", s_set, 0 }, +#endif /* TC_M88K */ + { "short", cons, 2 }, + { "single", float_cons, 'f' }, + /* size */ + { "space", s_space, 0 }, + /* tag */ + { "text", s_text, 0 }, +#ifdef NO_LISTING + { "title", s_ignore, 0 }, /* Listing title */ +#else + { "title", listing_title, 0 }, /* Listing title */ +#endif /* NO_LISTING */ + /* type */ + /* use */ + /* val */ + { "word", cons, 2 }, + { NULL} /* end sentinel */ +}; + +static void pobegin() { + char *errtxt; /* error text */ + const pseudo_typeS * pop; + + po_hash = hash_new(); + + /* Do the target-specific pseudo ops. */ + for (pop = md_pseudo_table; pop->poc_name; pop++) { + errtxt = hash_insert(po_hash, pop->poc_name, (char *)pop); + if (errtxt && *errtxt) { + as_fatal("error constructing md pseudo-op table"); + } /* on error */ + } /* for each op */ + + /* Now object specific. Skip any that were in the target table. */ + for (pop = obj_pseudo_table; pop->poc_name; pop++) { + errtxt = hash_insert(po_hash, pop->poc_name, (char *) pop); + if (errtxt && *errtxt) { + if (!strcmp(errtxt, "exists")) { +#ifdef DIE_ON_OVERRIDES + as_fatal("pseudo op \".%s\" overridden.\n", pop->poc_name); +#endif /* DIE_ON_OVERRIDES */ + continue; /* OK if target table overrides. */ + } else { + as_fatal("error constructing obj pseudo-op table"); + } /* if overridden */ + } /* on error */ + } /* for each op */ + + /* Now portable ones. Skip any that we've seen already. */ + for (pop = potable; pop->poc_name; pop++) { + errtxt = hash_insert(po_hash, pop->poc_name, (char *) pop); + if (errtxt && *errtxt) { + if (!strcmp (errtxt, "exists")) { +#ifdef DIE_ON_OVERRIDES + as_fatal("pseudo op \".%s\" overridden.\n", pop->poc_name); +#endif /* DIE_ON_OVERRIDES */ + continue; /* OK if target table overrides. */ + } else { + as_fatal("error constructing obj pseudo-op table"); + } /* if overridden */ + } /* on error */ + } /* for each op */ + + return; +} /* pobegin() */ + +#define HANDLE_CONDITIONAL_ASSEMBLY() \ + if (ignore_input ()) \ +{ \ + while (! is_end_of_line[*input_line_pointer++]) \ + if (input_line_pointer == buffer_limit) \ + break; \ + continue; \ + } + + +/* read_a_source_file() + * + * We read the file, putting things into a web that + * represents what we have been reading. + */ +void read_a_source_file(name) +char *name; +{ + register char c; + register char * s; /* string of symbol, '\0' appended */ + register int temp; + pseudo_typeS *pop = NULL; + + buffer = input_scrub_new_file(name); + + listing_file(name); + listing_newline(""); + + while ((buffer_limit = input_scrub_next_buffer(&input_line_pointer)) != 0) { /* We have another line to parse. */ + know(buffer_limit[-1] == '\n'); /* Must have a sentinel. */ + contin: /* JF this goto is my fault I admit it. Someone brave please re-write + the whole input section here? Pleeze??? */ + while (input_line_pointer < buffer_limit) { /* We have more of this buffer to parse. */ + + /* + * We now have input_line_pointer->1st char of next line. + * If input_line_pointer[-1] == '\n' then we just + * scanned another line: so bump line counters. + */ + if (input_line_pointer[-1] == '\n') { + bump_line_counters(); + } /* just passed a newline */ + + + + /* + * We are at the begining of a line, or similar place. + * We expect a well-formed assembler statement. + * A "symbol-name:" is a statement. + * + * Depending on what compiler is used, the order of these tests + * may vary to catch most common case 1st. + * Each test is independent of all other tests at the (top) level. + * PLEASE make a compiler that doesn't use this assembler. + * It is crufty to waste a compiler's time encoding things for this + * assembler, which then wastes more time decoding it. + * (And communicating via (linear) files is silly! + * If you must pass stuff, please pass a tree!) + */ + if ((c = *input_line_pointer++) == '\t' || c == ' ' || c == '\f' || c == 0) { + c = *input_line_pointer++; + } + know(c != ' '); /* No further leading whitespace. */ + LISTING_NEWLINE(); + /* + * C is the 1st significant character. + * Input_line_pointer points after that character. + */ + if (is_name_beginner(c)) { /* want user-defined label or pseudo/opcode */ + HANDLE_CONDITIONAL_ASSEMBLY(); + + s = input_line_pointer - 1; + 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 == '.' +#ifdef NO_DOT_PSEUDOS + || (pop= (pseudo_typeS *) hash_find(po_hash, s)) +#endif + ) { + /* + * 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 '.'. + */ + +#ifdef NO_DOT_PSEUDOS + if (*s == '.') +#endif + pop = (pseudo_typeS *) hash_find(po_hash, s+1); + + /* Print the error msg now, while we still can */ + if (!pop) { + as_bad("Unknown pseudo-op: `%s'",s); + *input_line_pointer = c; + s_ignore(0); + break; + } + + /* Put it back for error messages etc. */ + *input_line_pointer = c; + /* The following skip of whitespace is compulsory. */ + /* A well shaped space is sometimes all that separates keyword from operands. */ + if (c == ' ' || c == '\t') { + input_line_pointer++; + } /* Skip seperator after keyword. */ + /* + * Input_line is restored. + * Input_line_pointer->1st non-blank char + * after pseudo-operation. + */ + if (!pop) { + ignore_rest_of_line(); + break; + } else { + (*pop->poc_handler)(pop->poc_val); + } /* if we have one */ + } else { /* machine instruction */ + /* WARNING: c has char, which may be end-of-line. */ + /* Also: input_line_pointer->`\0` where c was. */ + * input_line_pointer = c; + while (!is_end_of_line[*input_line_pointer]) { + input_line_pointer++; + } + c = *input_line_pointer; + *input_line_pointer = '\0'; + md_assemble(s); /* Assemble 1 instruction. */ + *input_line_pointer++ = c; + /* We resume loop AFTER the end-of-line from this instruction */ + } /* if (*s == '.') */ + + } /* if c == ':' */ + continue; + } /* if (is_name_beginner(c) */ + + + if (is_end_of_line[c]) { + continue; + } /* empty statement */ + + + if (isdigit(c)) { /* local label ("4:") */ + HANDLE_CONDITIONAL_ASSEMBLY (); + + temp = c - '0'; +#ifdef LOCAL_LABELS_DOLLAR + if (*input_line_pointer == '$') + input_line_pointer++; +#endif + if (*input_line_pointer++ == ':') { + local_colon (temp); + } else { + as_bad("Spurious digit %d.", temp); + input_line_pointer -- ; + ignore_rest_of_line(); + } + continue; + } /* local label ("4:") */ + + if (c && strchr(line_comment_chars, c)) { /* Its a comment. Better say APP or NO_APP */ + char *ends; + char *new_buf; + char *new_tmp; + int new_length; + char *tmp_buf = 0; + extern char *scrub_string, *scrub_last_string; + + bump_line_counters(); + s = input_line_pointer; + if (strncmp(s,"APP\n",4)) + continue; /* We ignore it */ + s += 4; + + ends = strstr(s,"#NO_APP\n"); + + if (!ends) { + int tmp_len; + int num; + + /* The end of the #APP wasn't in this buffer. We + keep reading in buffers until we find the #NO_APP + that goes with this #APP There is one. The specs + guarentee it... */ + tmp_len = buffer_limit - s; + tmp_buf = xmalloc(tmp_len); + memcpy(tmp_buf, s, tmp_len); + do { + new_tmp = input_scrub_next_buffer(&buffer); + if (!new_tmp) + break; + else + buffer_limit = new_tmp; + input_line_pointer = buffer; + ends = strstr(buffer,"#NO_APP\n"); + if (ends) + num = ends - buffer; + else + num = buffer_limit - buffer; + + tmp_buf = xrealloc(tmp_buf, tmp_len + num); + memcpy(tmp_buf + tmp_len, buffer, num); + tmp_len += num; + } while (!ends); + + input_line_pointer = ends ? ends + 8 : NULL; + + s = tmp_buf; + ends = s + tmp_len; + + } else { + input_line_pointer = ends + 8; + } + new_buf=xmalloc(100); + new_length=100; + new_tmp=new_buf; + + scrub_string = s; + scrub_last_string = ends; + for (;;) { + int ch; + + ch = do_scrub_next_char(scrub_from_string, scrub_to_string); + if (ch == EOF) break; + *new_tmp++ = ch; + if (new_tmp == new_buf + new_length) { + new_buf = xrealloc(new_buf, new_length + 100); + new_tmp = new_buf + new_length; + new_length += 100; + } + } + + if (tmp_buf) + free(tmp_buf); + old_buffer = buffer; + old_input = input_line_pointer; + old_limit = buffer_limit; + buffer = new_buf; + input_line_pointer = new_buf; + buffer_limit = new_tmp; + continue; + } + + HANDLE_CONDITIONAL_ASSEMBLY(); + + /* as_warn("Junk character %d.",c); Now done by ignore_rest */ + input_line_pointer--; /* Report unknown char as ignored. */ + ignore_rest_of_line(); + } /* while (input_line_pointer<buffer_limit) */ + if (old_buffer) { + bump_line_counters(); + if (old_input != 0) { + buffer=old_buffer; + input_line_pointer=old_input; + buffer_limit=old_limit; + old_buffer = 0; + goto contin; + } + } + } /* while (more buffers to scan) */ + input_scrub_close(); /* Close the input file */ + +} /* read_a_source_file() */ + +void s_abort() { + as_fatal(".abort detected. Abandoning ship."); +} /* s_abort() */ + +/* For machines where ".align 4" means align to a 4 byte boundary. */ +void s_align_bytes(arg) +int arg; +{ + register unsigned int temp; + register long temp_fill; + unsigned int i = 0; + unsigned long max_alignment = 1 << 15; + + if (is_end_of_line[*input_line_pointer]) + temp = arg; /* Default value from pseudo-op table */ + else + temp = get_absolute_expression(); + + if (temp > max_alignment) { + as_bad("Alignment too large: %d. assumed.", temp = max_alignment); + } + + /* + * For the sparc, `.align (1<<n)' actually means `.align n' + * so we have to convert it. + */ + if (temp != 0) { + for (i = 0; (temp & 1) == 0; temp >>= 1, ++i) + ; + } + if (temp != 1) + as_bad("Alignment not a power of 2"); + + temp = i; + if (*input_line_pointer == ',') { + input_line_pointer ++; + temp_fill = get_absolute_expression(); + } else { + temp_fill = NOP_OPCODE; + } + /* Only make a frag if we HAVE to... */ + if (temp && ! need_pass_2) + frag_align(temp, (int)temp_fill); + + demand_empty_rest_of_line(); +} /* s_align_bytes() */ + +/* For machines where ".align 4" means align to 2**4 boundary. */ +void s_align_ptwo() { + register int temp; + register long temp_fill; + long max_alignment = 15; + + temp = get_absolute_expression(); + if (temp > max_alignment) + as_bad("Alignment too large: %d. assumed.", temp = max_alignment); + else if (temp < 0) { + as_bad("Alignment negative. 0 assumed."); + temp = 0; + } + if (*input_line_pointer == ',') { + input_line_pointer ++; + temp_fill = get_absolute_expression(); + } else + temp_fill = NOP_OPCODE; + /* Only make a frag if we HAVE to... */ + if (temp && ! need_pass_2) + frag_align (temp, (int)temp_fill); + + record_alignment(now_seg, temp); + + demand_empty_rest_of_line(); +} /* s_align_ptwo() */ + +void s_comm() { + register char *name; + register char c; + register char *p; + register int temp; + register symbolS *symbolP; + + name = input_line_pointer; + c = get_symbol_end(); + /* just after name is now '\0' */ + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE(); + if (*input_line_pointer != ',') { + as_bad("Expected comma after symbol-name: rest of line ignored."); + ignore_rest_of_line(); + return; + } + input_line_pointer ++; /* skip ',' */ + if ((temp = get_absolute_expression()) < 0) { + as_warn(".COMMon length (%d.) <0! Ignored.", temp); + ignore_rest_of_line(); + return; + } + *p = 0; + symbolP = symbol_find_or_make(name); + *p = c; + if (S_IS_DEFINED(symbolP)) { + as_bad("Ignoring attempt to re-define symbol"); + ignore_rest_of_line(); + return; + } + if (S_GET_VALUE(symbolP)) { + if (S_GET_VALUE(symbolP) != temp) + as_bad("Length of .comm \"%s\" is already %d. Not changed to %d.", + S_GET_NAME(symbolP), + S_GET_VALUE(symbolP), + temp); + } else { + S_SET_VALUE(symbolP, temp); + S_SET_EXTERNAL(symbolP); + } +#ifdef OBJ_VMS + if ( (!temp) || !flagseen['1']) + S_GET_OTHER(symbolP) = const_flag; +#endif /* not OBJ_VMS */ + know(symbolP->sy_frag == &zero_address_frag); + demand_empty_rest_of_line(); +} /* s_comm() */ + +void + s_data() +{ + register int temp; + + temp = get_absolute_expression(); +#ifdef MANY_SEGMENTS + subseg_new (SEG_E1, (subsegT)temp); +#else + subseg_new (SEG_DATA, (subsegT)temp); +#endif + +#ifdef OBJ_VMS + const_flag = 0; +#endif /* not OBJ_VMS */ + demand_empty_rest_of_line(); +} + +void s_app_file() { + register char *s; + int length; + + /* Some assemblers tolerate immediately following '"' */ + if ((s = demand_copy_string(&length)) != 0) { + new_logical_line(s, -1); + demand_empty_rest_of_line(); + } +#ifdef OBJ_COFF + c_dot_file_symbol(s); +#endif /* OBJ_COFF */ +} /* s_app_file() */ + +void s_fill() { + long temp_repeat; + long temp_size; + register long temp_fill; + char *p; + + if (get_absolute_expression_and_terminator(& temp_repeat) != ',') { + input_line_pointer --; /* Backup over what was not a ','. */ + as_bad("Expect comma after rep-size in .fill:"); + ignore_rest_of_line(); + return; + } + if (get_absolute_expression_and_terminator(& temp_size) != ',') { + input_line_pointer --; /* Backup over what was not a ','. */ + as_bad("Expected comma after size in .fill"); + ignore_rest_of_line(); + return; + } + /* + * This is to be compatible with BSD 4.2 AS, not for any rational reason. + */ +#define BSD_FILL_SIZE_CROCK_8 (8) + if (temp_size > BSD_FILL_SIZE_CROCK_8) { + as_bad(".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8); + temp_size = BSD_FILL_SIZE_CROCK_8 ; + } if (temp_size < 0) { + as_warn("Size negative: .fill ignored."); + temp_size = 0; + } else if (temp_repeat <= 0) { + as_warn("Repeat < 0, .fill ignored"); + temp_size = 0; + } + temp_fill = get_absolute_expression(); + if (temp_size && !need_pass_2) { + p = frag_var(rs_fill, (int)temp_size, (int)temp_size, (relax_substateT)0, (symbolS *)0, temp_repeat, (char *)0); + memset(p, '\0', (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(); +} + +void s_globl() { + register char *name; + register int c; + register symbolS * symbolP; + + do { + name = input_line_pointer; + c = get_symbol_end(); + symbolP = symbol_find_or_make(name); + * input_line_pointer = c; + SKIP_WHITESPACE(); + S_SET_EXTERNAL(symbolP); + if (c == ',') { + input_line_pointer++; + SKIP_WHITESPACE(); + if (*input_line_pointer == '\n') + c='\n'; + } + } while (c == ','); + demand_empty_rest_of_line(); +} /* s_globl() */ + +void s_lcomm(needs_align) +int needs_align; /* 1 if this was a ".bss" directive, which may require + * a 3rd argument (alignment). + * 0 if it was an ".lcomm" (2 args only) + */ +{ + register char *name; + register char c; + register char *p; + register int temp; + register symbolS * symbolP; + const int max_alignment = 15; + int align = 0; + + name = input_line_pointer; + c = get_symbol_end(); + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE(); + if (*input_line_pointer != ',') { + as_bad("Expected comma after name"); + ignore_rest_of_line(); + return; + } + + ++input_line_pointer; + + if (*input_line_pointer == '\n') { + as_bad("Missing size expression"); + return; + } + + if ((temp = get_absolute_expression()) < 0) { + as_warn("BSS length (%d.) <0! Ignored.", temp); + ignore_rest_of_line(); + return; + } + + if (needs_align) { + align = 0; + SKIP_WHITESPACE(); + if (*input_line_pointer != ',') { + as_bad("Expected comma after size"); + ignore_rest_of_line(); + return; + } + input_line_pointer++; + SKIP_WHITESPACE(); + if (*input_line_pointer == '\n') { + as_bad("Missing alignment"); + return; + } + align = get_absolute_expression(); + if (align > max_alignment){ + align = max_alignment; + as_warn("Alignment too large: %d. assumed.", align); + } else if (align < 0) { + align = 0; + as_warn("Alignment negative. 0 assumed."); + } +#ifdef MANY_SEGMENTS +#define SEG_BSS SEG_E2 + record_alignment(SEG_E2, align); +#else + record_alignment(SEG_BSS, align); +#endif + } /* if needs align */ + + *p = 0; + symbolP = symbol_find_or_make(name); + *p = c; + + if ( +#if defined(OBJ_AOUT) | defined(OBJ_BOUT) + S_GET_OTHER(symbolP) == 0 && + S_GET_DESC(symbolP) == 0 && +#endif /* OBJ_AOUT or OBJ_BOUT */ + (((S_GET_SEGMENT(symbolP) == SEG_BSS) && (S_GET_VALUE(symbolP) == local_bss_counter)) + || (!S_IS_DEFINED(symbolP) && S_GET_VALUE(symbolP) == 0))) { + if (needs_align){ + /* Align */ + align = ~ ((~0) << align); /* Convert to a mask */ + local_bss_counter = + (local_bss_counter + align) & (~align); + } + + S_SET_VALUE(symbolP, local_bss_counter); + S_SET_SEGMENT(symbolP, SEG_BSS); +#ifdef OBJ_COFF + /* The symbol may already have been created with a preceding + * ".globl" directive -- be careful not to step on storage + * class in that case. Otherwise, set it to static. + */ + if (S_GET_STORAGE_CLASS(symbolP) != C_EXT){ + S_SET_STORAGE_CLASS(symbolP, C_STAT); + } +#endif /* OBJ_COFF */ + symbolP->sy_frag = &bss_address_frag; + local_bss_counter += temp; + } else { + as_bad("Ignoring attempt to re-define symbol from %d. to %d.", + S_GET_VALUE(symbolP), local_bss_counter); + } + demand_empty_rest_of_line(); + + return; +} /* s_lcomm() */ + +void + s_long() +{ + cons(4); +} + +void + s_int() +{ + cons(4); +} + +void s_lsym() { + register char *name; + register char c; + register char *p; + register segT segment; + expressionS exp; + register symbolS *symbolP; + + /* we permit ANY defined expression: BSD4.2 demands constants */ + name = input_line_pointer; + c = get_symbol_end(); + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE(); + if (* input_line_pointer != ',') { + *p = 0; + as_bad("Expected comma after name \"%s\"", name); + *p = c; + ignore_rest_of_line(); + return; + } + input_line_pointer ++; + segment = expression(& exp); + if (segment != SEG_ABSOLUTE +#ifdef MANY_SEGMENTS + && ! ( segment >= SEG_E0 && segment <= SEG_UNKNOWN) +#else + && segment != SEG_DATA + && segment != SEG_TEXT + && segment != SEG_BSS +#endif + && segment != SEG_REGISTER) { + as_bad("Bad expression: %s", segment_name(segment)); + ignore_rest_of_line(); + return; + } + *p = 0; + symbolP = symbol_find_or_make(name); + + /* FIXME-SOON I pulled a (&& symbolP->sy_other == 0 + && symbolP->sy_desc == 0) out of this test + because coff doesn't have those fields, and I + can't see when they'd ever be tripped. I don't + think I understand why they were here so I may + have introduced a bug. As recently as 1.37 didn't + have this test anyway. xoxorich. */ + + if (S_GET_SEGMENT(symbolP) == SEG_UNKNOWN + && S_GET_VALUE(symbolP) == 0) { + /* The name might be an undefined .global symbol; be + sure to keep the "external" bit. */ + S_SET_SEGMENT(symbolP, segment); + S_SET_VALUE(symbolP, (valueT)(exp.X_add_number)); + } else { + as_bad("Symbol %s already defined", name); + } + *p = c; + demand_empty_rest_of_line(); +} /* s_lsym() */ + +void s_org() { + register segT segment; + expressionS exp; + register long temp_fill; + register char *p; + /* + * Don't believe the documentation of BSD 4.2 AS. + * There is no such thing as a sub-segment-relative origin. + * Any absolute origin is given a warning, then assumed to be segment-relative. + * Any segmented origin expression ("foo+42") had better be in the right + * segment or the .org is ignored. + * + * BSD 4.2 AS warns if you try to .org backwards. We cannot because we + * never know sub-segment sizes when we are reading code. + * BSD will crash trying to emit -ve numbers of filler bytes in certain + * .orgs. We don't crash, but see as-write for that code. + */ + /* + * Don't make frag if need_pass_2 == 1. + */ + segment = get_known_segmented_expression(&exp); + if (*input_line_pointer == ',') { + input_line_pointer ++; + temp_fill = get_absolute_expression(); + } else + temp_fill = 0; + if (! need_pass_2) { + if (segment != now_seg && segment != SEG_ABSOLUTE) + as_bad("Invalid segment \"%s\". Segment \"%s\" assumed.", + segment_name(segment), segment_name(now_seg)); + p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol, + exp.X_add_number, (char *)0); + * p = temp_fill; + } /* if (ok to make frag) */ + demand_empty_rest_of_line(); +} /* s_org() */ + +void s_set() { + register char *name; + register char delim; + register char *end_name; + register symbolS *symbolP; + + /* + * Especial apologies for the random logic: + * this just grew, and could be parsed much more simply! + * Dean in haste. + */ + name = input_line_pointer; + delim = get_symbol_end(); + end_name = input_line_pointer; + *end_name = delim; + SKIP_WHITESPACE(); + + if (*input_line_pointer != ',') { + *end_name = 0; + as_bad("Expected comma after name \"%s\"", name); + *end_name = delim; + ignore_rest_of_line(); + return; + } + + input_line_pointer ++; + *end_name = 0; + + if (name[0] == '.' && name[1] == '\0') { + /* Turn '. = mumble' into a .org mumble */ + register segT segment; + expressionS exp; + register char *ptr; + + segment = get_known_segmented_expression(& exp); + + if (!need_pass_2) { + if (segment != now_seg && segment != SEG_ABSOLUTE) + as_bad("Invalid segment \"%s\". Segment \"%s\" assumed.", + segment_name(segment), + segment_name (now_seg)); + ptr = frag_var(rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol, + exp.X_add_number, (char *)0); + *ptr= 0; + } /* if (ok to make frag) */ + + *end_name = delim; + return; + } + + if ((symbolP = symbol_find(name)) == NULL + && (symbolP = md_undefined_symbol(name)) == NULL) { + symbolP = symbol_new(name, + SEG_UNKNOWN, + 0, + &zero_address_frag); +#ifdef OBJ_COFF + /* "set" symbols are local unless otherwise specified. */ + SF_SET_LOCAL(symbolP); +#endif /* OBJ_COFF */ + + } /* make a new symbol */ + + symbol_table_insert(symbolP); + + *end_name = delim; + pseudo_set(symbolP); + demand_empty_rest_of_line(); +} /* s_set() */ + +void s_size() { + register char *name; + register char c; + register char *p; + register int temp; + register symbolS *symbolP; + expressionS *exp; + segT seg; + + SKIP_WHITESPACE(); + name = input_line_pointer; + c = get_symbol_end(); + /* just after name is now '\0' */ + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE(); + if (*input_line_pointer != ',') { + as_bad("Expected comma after symbol-name: rest of line ignored."); + ignore_rest_of_line(); + return; + } + input_line_pointer ++; /* skip ',' */ + if ((exp = (expressionS *)malloc(sizeof(expressionS))) == NULL) { + as_bad("Virtual memory exhausted"); + return; + } + switch (get_known_segmented_expression(exp)) { + case SEG_ABSOLUTE: + break; + case SEG_DIFFERENCE: + if (exp->X_add_symbol == NULL || exp->X_subtract_symbol == NULL + || S_GET_SEGMENT(exp->X_add_symbol) != + S_GET_SEGMENT(exp->X_subtract_symbol)) { + as_bad("Illegal .size expression"); + ignore_rest_of_line(); + return; + } + break; + default: + as_bad("Illegal .size expression"); + ignore_rest_of_line(); + return; + } + *p = 0; + symbolP = symbol_find_or_make(name); + *p = c; + if (symbolP->sy_sizexp) { + as_warn("\"%s\" already has a size", S_GET_NAME(symbolP)); + } else + symbolP->sy_sizexp = (void *)exp; + + demand_empty_rest_of_line(); +} /* s_size() */ + +void s_type() { + register char *name, *type; + register char c, c1; + register char *p; + register symbolS *symbolP; + int aux; + + SKIP_WHITESPACE(); + name = input_line_pointer; + c = get_symbol_end(); + /* just after name is now '\0' */ + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE(); + if (*input_line_pointer != ',') { + as_bad("Expected comma after symbol-name: rest of line ignored."); + ignore_rest_of_line(); + return; + } + input_line_pointer ++; /* skip ',' */ + SKIP_WHITESPACE(); + if (*input_line_pointer != TYPE_OPERAND_FMT) { + as_bad("Expected `%c' as start of operand: rest of line ignored.", TYPE_OPERAND_FMT); + ignore_rest_of_line(); + return; + } + input_line_pointer ++; /* skip '@' */ + type = input_line_pointer; + c1 = get_symbol_end(); + if (strcmp(type, "function") == 0) { + aux = AUX_FUNC; + } else if (strcmp(type, "object") == 0) { + aux = AUX_OBJECT; + } else { + as_warn("Unrecognized .type operand: \"%s\": rest of line ignored.", + type); + ignore_rest_of_line(); + return; + } + *input_line_pointer = c1; + + *p = 0; + symbolP = symbol_find_or_make(name); + *p = c; + + if (symbolP->sy_aux && symbolP->sy_aux != aux) { + as_bad("Type of \"%s\" is already %d. Not changed to %d.", + S_GET_NAME(symbolP), symbolP->sy_aux, aux); + } else + symbolP->sy_aux = aux; + + demand_empty_rest_of_line(); +} /* s_type() */ + +void s_space() { + long temp_repeat; + register long temp_fill; + register char *p; + + /* Just like .fill, but temp_size = 1 */ + if (get_absolute_expression_and_terminator(& temp_repeat) == ',') { + temp_fill = get_absolute_expression(); + } else { + input_line_pointer --; /* Backup over what was not a ','. */ + temp_fill = 0; + } + if (temp_repeat <= 0) { + as_warn("Repeat < 0, .space ignored"); + ignore_rest_of_line(); + return; + } + if (! need_pass_2) { + p = frag_var (rs_fill, 1, 1, (relax_substateT)0, (symbolS *)0, + temp_repeat, (char *)0); + * p = temp_fill; + } + demand_empty_rest_of_line(); +} /* s_space() */ + +void + s_text() +{ + register int temp; + + temp = get_absolute_expression(); +#ifdef MANY_SEGMENTS + subseg_new (SEG_E0, (subsegT)temp); +#else + subseg_new (SEG_TEXT, (subsegT)temp); +#endif + demand_empty_rest_of_line(); +} /* s_text() */ + + +/*(JF was static, but can't be if machine dependent pseudo-ops are to use it */ + +void demand_empty_rest_of_line() { + SKIP_WHITESPACE(); + if (is_end_of_line[*input_line_pointer]) { + input_line_pointer++; + } else { + ignore_rest_of_line(); + } + /* Return having already swallowed end-of-line. */ +} /* Return pointing just after end-of-line. */ + +void + ignore_rest_of_line() /* For suspect lines: gives warning. */ +{ + if (!is_end_of_line[*input_line_pointer]) + { + if (isprint(*input_line_pointer)) + as_bad("Rest of line ignored. First ignored character is `%c'.", + *input_line_pointer); + else + as_bad("Rest of line ignored. First ignored character valued 0x%x.", + *input_line_pointer); + while (input_line_pointer < buffer_limit + && !is_end_of_line[*input_line_pointer]) + { + input_line_pointer ++; + } + } + input_line_pointer ++; /* Return pointing just after end-of-line. */ + know(is_end_of_line[input_line_pointer[-1]]); +} + +/* + * pseudo_set() + * + * In: Pointer to a symbol. + * Input_line_pointer->expression. + * + * Out: Input_line_pointer->just after any whitespace after expression. + * Tried to set symbol to value of expression. + * Will change symbols type, value, and frag; + * May set need_pass_2 == 1. + */ +void + pseudo_set (symbolP) +symbolS * symbolP; +{ + expressionS exp; + register segT segment; +#if defined(OBJ_AOUT) | defined(OBJ_BOUT) + int ext; +#endif /* OBJ_AOUT or OBJ_BOUT */ + + know(symbolP); /* NULL pointer is logic error. */ +#if defined(OBJ_AOUT) | defined(OBJ_BOUT) + ext=S_IS_EXTERNAL(symbolP); +#endif /* OBJ_AOUT or OBJ_BOUT */ + + if ((segment = expression(& exp)) == SEG_ABSENT) + { + as_bad("Missing expression: absolute 0 assumed"); + exp.X_seg = SEG_ABSOLUTE; + exp.X_add_number = 0; + } + + switch (segment) + { + case SEG_BIG: + as_bad("%s number invalid. Absolute 0 assumed.", + exp.X_add_number > 0 ? "Bignum" : "Floating-Point"); + S_SET_SEGMENT(symbolP, SEG_ABSOLUTE); +#if defined(OBJ_AOUT) | defined(OBJ_BOUT) + ext ? S_SET_EXTERNAL(symbolP) : + S_CLEAR_EXTERNAL(symbolP); +#endif /* OBJ_AOUT or OBJ_BOUT */ + S_SET_VALUE(symbolP, 0); + symbolP->sy_frag = & zero_address_frag; + break; + + case SEG_ABSENT: + as_warn("No expression: Using absolute 0"); + S_SET_SEGMENT(symbolP, SEG_ABSOLUTE); +#if defined(OBJ_AOUT) | defined(OBJ_BOUT) + ext ? S_SET_EXTERNAL(symbolP) : + S_CLEAR_EXTERNAL(symbolP); +#endif /* OBJ_AOUT or OBJ_BOUT */ + S_SET_VALUE(symbolP, 0); + symbolP->sy_frag = & zero_address_frag; + break; + + case SEG_DIFFERENCE: + if (exp.X_add_symbol && exp.X_subtract_symbol + && (S_GET_SEGMENT(exp.X_add_symbol) == + S_GET_SEGMENT(exp.X_subtract_symbol))) { + if (exp.X_add_symbol->sy_frag != exp.X_subtract_symbol->sy_frag) { + as_bad("Unknown expression: symbols %s and %s are in different frags.", + S_GET_NAME(exp.X_add_symbol), S_GET_NAME(exp.X_subtract_symbol)); + need_pass_2++; + } + exp.X_add_number+=S_GET_VALUE(exp.X_add_symbol) - + S_GET_VALUE(exp.X_subtract_symbol); + } else + as_bad("Complex expression. Absolute segment assumed."); + case SEG_ABSOLUTE: + S_SET_SEGMENT(symbolP, SEG_ABSOLUTE); +#if defined(OBJ_AOUT) | defined(OBJ_BOUT) + ext ? S_SET_EXTERNAL(symbolP) : + S_CLEAR_EXTERNAL(symbolP); +#endif /* OBJ_AOUT or OBJ_BOUT */ + S_SET_VALUE(symbolP, exp.X_add_number); + symbolP->sy_frag = & zero_address_frag; + break; + + default: +#ifdef MANY_SEGMENTS + S_SET_SEGMENT(symbolP, segment); +#else + switch (segment) { + case SEG_DATA: S_SET_SEGMENT(symbolP, SEG_DATA); break; + case SEG_TEXT: S_SET_SEGMENT(symbolP, SEG_TEXT); break; + case SEG_BSS: S_SET_SEGMENT(symbolP, SEG_BSS); break; + default: as_fatal("failed sanity check."); + } /* switch on segment */ +#endif +#if defined(OBJ_AOUT) | defined(OBJ_BOUT) + if (ext) { + S_SET_EXTERNAL(symbolP); + } else { + S_CLEAR_EXTERNAL(symbolP); + } /* if external */ +#endif /* OBJ_AOUT or OBJ_BOUT */ + + S_SET_VALUE(symbolP, exp.X_add_number + S_GET_VALUE(exp.X_add_symbol)); + symbolP->sy_frag = exp.X_add_symbol->sy_frag; + break; + + case SEG_PASS1: /* Not an error. Just try another pass. */ + symbolP->sy_forward=exp.X_add_symbol; + as_bad("Unknown expression"); + know(need_pass_2 == 1); + break; + + case SEG_UNKNOWN: + symbolP->sy_forward=exp.X_add_symbol; + /* as_warn("unknown symbol"); */ + /* need_pass_2 = 1; */ + break; + + + + } +} + +/* + * cons() + * + * CONStruct more frag of .bytes, or .words etc. + * Should need_pass_2 be 1 then emit no frag(s). + * This understands EXPRESSIONS, as opposed to big_cons(). + * + * Bug (?) + * + * This has a split personality. We use expression() to read the + * value. We can detect if the value won't fit in a byte or word. + * But we can't detect if expression() discarded significant digits + * in the case of a long. Not worth the crocks required to fix it. + */ + +/* worker to do .byte etc statements */ +/* clobbers input_line_pointer, checks */ +/* end-of-line. */ +void cons(nbytes) +register unsigned int nbytes; /* 1=.byte, 2=.word, 4=.long */ +{ + register char c; + register long mask; /* High-order bits we will left-truncate, */ + /* but includes sign bit also. */ + register long get; /* what we get */ + register long use; /* get after truncation. */ + register long unmask; /* what bits we will store */ + register char * p; + register segT segment; + expressionS exp; + + /* + * Input_line_pointer->1st char after pseudo-op-code and could legally + * be a end-of-line. (Or, less legally an eof - which we cope with.) + */ + /* JF << of >= number of bits in the object is undefined. In particular + SPARC (Sun 4) has problems */ + + if (nbytes >= sizeof(long)) { + mask = 0; + } else { + mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */ + } /* bigger than a long */ + + unmask = ~mask; /* Do store these bits. */ + +#ifdef NEVER + "Do this mod if you want every overflow check to assume SIGNED 2's complement data."; + mask = ~ (unmask >> 1); /* Includes sign bit now. */ +#endif + + /* + * The following awkward logic is to parse ZERO or more expressions, + * comma seperated. Recall an expression includes its leading & + * trailing blanks. We fake a leading ',' if there is (supposed to + * be) a 1st expression, and keep demanding 1 expression for each ','. + */ + if (is_it_end_of_statement()) { + c = 0; /* Skip loop. */ + input_line_pointer++; /* Matches end-of-loop 'correction'. */ + } else { + c = ','; + } /* if the end else fake it */ + + /* Do loop. */ + while (c == ',') { +#ifdef WANT_BITFIELDS + unsigned int bits_available = BITS_PER_CHAR * nbytes; + /* used for error messages and rescanning */ + char *hold = input_line_pointer; +#endif /* WANT_BITFIELDS */ + + /* At least scan over the expression. */ + segment = expression(&exp); + +#ifdef WANT_BITFIELDS + /* Some other assemblers, (eg, asm960), allow + bitfields after ".byte" as w:x,y:z, where w and + y are bitwidths and x and y are values. They + then pack them all together. We do a little + better in that we allow them in words, longs, + etc. and we'll pack them in target byte order + for you. + + The rules are: pack least significat bit first, + if a field doesn't entirely fit, put it in the + next unit. Overflowing the bitfield is + explicitly *not* even a warning. The bitwidth + should be considered a "mask". + + FIXME-SOMEDAY: If this is considered generally + useful, this logic should probably be reworked. + xoxorich. */ + + if (*input_line_pointer == ':') { /* bitfields */ + long value = 0; + + for (;;) { + unsigned long width; + + if (*input_line_pointer != ':') { + input_line_pointer = hold; + break; + } /* next piece is not a bitfield */ + + /* In the general case, we can't allow + full expressions with symbol + differences and such. The relocation + entries for symbols not defined in this + assembly would require arbitrary field + widths, positions, and masks which most + of our current object formats don't + support. + + In the specific case where a symbol + *is* defined in this assembly, we + *could* build fixups and track it, but + this could lead to confusion for the + backends. I'm lazy. I'll take any + SEG_ABSOLUTE. I think that means that + you can use a previous .set or + .equ type symbol. xoxorich. */ + + if (segment == SEG_ABSENT) { + as_warn("Using a bit field width of zero."); + exp.X_add_number = 0; + segment = SEG_ABSOLUTE; + } /* implied zero width bitfield */ + + if (segment != SEG_ABSOLUTE) { + *input_line_pointer = '\0'; + as_bad("Field width \"%s\" too complex for a bitfield.\n", hold); + *input_line_pointer = ':'; + demand_empty_rest_of_line(); + return; + } /* too complex */ + + if ((width = exp.X_add_number) > (BITS_PER_CHAR * nbytes)) { + as_warn("Field width %d too big to fit in %d bytes: truncated to %d bits.", + width, nbytes, (BITS_PER_CHAR * nbytes)); + width = BITS_PER_CHAR * nbytes; + } /* too big */ + + if (width > bits_available) { + /* FIXME-SOMEDAY: backing up and + reparsing is wasteful */ + input_line_pointer = hold; + exp.X_add_number = value; + break; + } /* won't fit */ + + hold = ++input_line_pointer; /* skip ':' */ + + if ((segment = expression(&exp)) != SEG_ABSOLUTE) { + char cache = *input_line_pointer; + + *input_line_pointer = '\0'; + as_bad("Field value \"%s\" too complex for a bitfield.\n", hold); + *input_line_pointer = cache; + demand_empty_rest_of_line(); + return; + } /* too complex */ + + value |= (~(-1 << width) & exp.X_add_number) + << ((BITS_PER_CHAR * nbytes) - bits_available); + + if ((bits_available -= width) == 0 + || is_it_end_of_statement() + || *input_line_pointer != ',') { + break; + } /* all the bitfields we're gonna get */ + + hold = ++input_line_pointer; + segment = expression(&exp); + } /* forever loop */ + + exp.X_add_number = value; + segment = SEG_ABSOLUTE; + } /* if looks like a bitfield */ +#endif /* WANT_BITFIELDS */ + + if (!need_pass_2) { /* Still worthwhile making frags. */ + + /* Don't call this if we are going to junk this pass anyway! */ + know(segment != SEG_PASS1); + + if (segment == SEG_DIFFERENCE && exp.X_add_symbol == NULL) { + as_bad("Subtracting symbol \"%s\"(segment\"%s\") is too hard. Absolute segment assumed.", + S_GET_NAME(exp.X_subtract_symbol), + segment_name(S_GET_SEGMENT(exp.X_subtract_symbol))); + segment = SEG_ABSOLUTE; + /* Leave exp.X_add_number alone. */ + } + + p = frag_more(nbytes); + + switch (segment) { + case SEG_BIG: + as_bad("%s number invalid. Absolute 0 assumed.", + exp.X_add_number > 0 ? "Bignum" : "Floating-Point"); + md_number_to_chars (p, (long)0, nbytes); + break; + + case SEG_ABSENT: + as_warn("0 assumed for missing expression"); + exp.X_add_number = 0; + know(exp.X_add_symbol == NULL); + /* fall into SEG_ABSOLUTE */ + case SEG_ABSOLUTE: + get = exp.X_add_number; + use = get & unmask; + if ((get & mask) && (get & mask) != mask) + { /* Leading bits contain both 0s & 1s. */ + as_warn("Value 0x%x truncated to 0x%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 + default: + case SEG_UNKNOWN: +#ifdef TC_NS32K + fix_new_ns32k(frag_now, p - frag_now->fr_literal, nbytes, + exp.X_add_symbol, exp.X_subtract_symbol, + exp.X_add_number, 0, 0, 2, 0, 0); +#else +#ifdef PIC + 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, + exp.X_got_symbol); +#else + fix_new(frag_now, p - frag_now->fr_literal, nbytes, + exp.X_add_symbol, exp.X_subtract_symbol, + exp.X_add_number, 0, RELOC_32); +#endif +#endif /* TC_NS32K */ + 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 == 1, generate no frag. + * This understands only bignums, not expressions. Cons() understands + * expressions. + * + * Constants recognised are '0...'(octal) '0x...'(hex) '...'(decimal). + * + * This creates objects with struct obstack_control objs, destroying + * any context objs held about a partially completed object. Beware! + * + * + * I think it sucks to have 2 different types of integers, with 2 + * routines to read them, store them etc. + * It would be nicer to permit bignums in expressions and only + * complain if the result overflowed. However, due to "efficiency"... + */ +/* worker to do .quad etc statements */ +/* clobbers input_line_pointer, checks */ +/* end-of-line. */ +/* 8=.quad 16=.octa ... */ + +void big_cons(nbytes) +register int nbytes; +{ + register char c; /* input_line_pointer->c. */ + register int radix; + register long length; /* Number of chars in an object. */ + register int digit; /* Value of 1 digit. */ + register int carry; /* For multi-precision arithmetic. */ + register int work; /* For multi-precision arithmetic. */ + register char * p; /* For multi-precision arithmetic. */ + + extern const char hex_value[]; /* In hex_value.c. */ + + /* + * The following awkward logic is to parse ZERO or more strings, + * comma seperated. Recall an expression includes its leading & + * trailing blanks. We fake a leading ',' if there is (supposed to + * be) a 1st expression, and keep demanding 1 expression for each ','. + */ + if (is_it_end_of_statement()) + { + c = 0; /* Skip loop. */ + } + else + { + c = ','; /* Do loop. */ + -- input_line_pointer; + } + while (c == ',') + { + ++ input_line_pointer; + SKIP_WHITESPACE(); + c = * input_line_pointer; + /* C contains 1st non-blank character of what we hope is a number. */ + if (c == '0') + { + c = * ++ input_line_pointer; + if (c == 'x' || c == 'X') + { + c = * ++ input_line_pointer; + radix = 16; + } + else + { + radix = 8; + } + } + else + { + radix = 10; + } + /* + * This feature (?) is here to stop people worrying about + * mysterious zero constants: which is what they get when + * they completely omit digits. + */ + if (hex_value[c] >= radix) { + as_bad("Missing digits. 0 assumed."); + } + bignum_high = bignum_low - 1; /* Start constant with 0 chars. */ + for (; (digit = hex_value[c]) < radix; c = *++input_line_pointer) + { + /* Multiply existing number by radix, then add digit. */ + carry = digit; + for (p=bignum_low; p <= bignum_high; p++) + { + work = (*p & MASK_CHAR) * radix + carry; + *p = work & MASK_CHAR; + carry = work >> BITS_PER_CHAR; + } + if (carry) + { + grow_bignum(); + * bignum_high = carry & MASK_CHAR; + know((carry & ~ MASK_CHAR) == 0); + } + } + length = bignum_high - bignum_low + 1; + if (length > nbytes) + { + as_warn("Most significant bits truncated in integer constant."); + } + else + { + register long leading_zeroes; + + for (leading_zeroes = nbytes - length; + leading_zeroes; + leading_zeroes --) + { + grow_bignum(); + * bignum_high = 0; + } + } + if (! need_pass_2) + { + p = frag_more (nbytes); + memcpy(p, bignum_low, (int) nbytes); + } + /* C contains character after number. */ + SKIP_WHITESPACE(); + c = *input_line_pointer; + /* C contains 1st non-blank character after number. */ + } + demand_empty_rest_of_line(); +} /* big_cons() */ + +/* Extend bignum by 1 char. */ +static void grow_bignum() { + register long length; + + bignum_high ++; + if (bignum_high >= bignum_limit) + { + length = bignum_limit - bignum_low; + bignum_low = xrealloc(bignum_low, length + length); + bignum_high = bignum_low + length; + bignum_limit = bignum_low + length + length; + } +} /* grow_bignum(); */ + +/* + * float_cons() + * + * CONStruct some more frag chars of .floats .ffloats etc. + * Makes 0 or more new frags. + * If need_pass_2 == 1, no frags are emitted. + * This understands only floating literals, not expressions. Sorry. + * + * A floating constant is defined by atof_generic(), except it is preceded + * by 0d 0f 0g or 0h. After observing the STRANGE way my BSD AS does its + * reading, I decided to be incompatible. This always tries to give you + * rounded bits to the precision of the pseudo-op. Former AS did premature + * truncatation, restored noisy bits instead of trailing 0s AND gave you + * a choice of 2 flavours of noise according to which of 2 floating-point + * scanners you directed AS to use. + * + * In: input_line_pointer->whitespace before, or '0' of flonum. + * + */ + +void /* JF was static, but can't be if VAX.C is goning to use it */ + float_cons(float_type) /* Worker to do .float etc statements. */ +/* Clobbers input_line-pointer, checks end-of-line. */ +register int float_type; /* 'f':.ffloat ... 'F':.float ... */ +{ + register char * p; + register char c; + int length; /* Number of chars in an object. */ + register char * err; /* Error from scanning floating literal. */ + char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT]; + + /* + * The following awkward logic is to parse ZERO or more strings, + * comma seperated. Recall an expression includes its leading & + * trailing blanks. We fake a leading ',' if there is (supposed to + * be) a 1st expression, and keep demanding 1 expression for each ','. + */ + if (is_it_end_of_statement()) + { + c = 0; /* Skip loop. */ + ++ input_line_pointer; /*->past termintor. */ + } + else + { + c = ','; /* Do loop. */ + } + while (c == ',') { + /* input_line_pointer->1st char of a flonum (we hope!). */ + SKIP_WHITESPACE(); + /* Skip any 0{letter} that may be present. Don't even check if the + * letter is legal. Someone may invent a "z" format and this routine + * has no use for such information. Lusers beware: you get + * diagnostics if your input is ill-conditioned. + */ + + if (input_line_pointer[0] == '0' && isalpha(input_line_pointer[1])) + input_line_pointer+=2; + + err = md_atof (float_type, temp, &length); + know(length <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT); + know(length > 0); + if (* err) { + as_bad("Bad floating literal: %s", err); + ignore_rest_of_line(); + /* Input_line_pointer->just after end-of-line. */ + c = 0; /* Break out of loop. */ + } else { + if (! need_pass_2) { + p = frag_more (length); + memcpy(p, temp, 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() Worker to do .ascii etc statements. Checks end-of-line. + * + * We read 0 or more ',' seperated, double-quoted strings. + * + * Caller should have checked need_pass_2 is FALSE because we don't check it. + */ + +void stringer(append_zero) +int append_zero; /* 0: don't append '\0', else 1 */ +{ + unsigned int c; + + /* + * The following awkward logic is to parse ZERO or more strings, + * comma seperated. Recall a string expression includes spaces + * before the opening '\"' and spaces after the closing '\"'. + * We fake a leading ',' if there is (supposed to be) + * a 1st, expression. We keep demanding expressions for each + * ','. + */ + if (is_it_end_of_statement()) { + c = 0; /* Skip loop. */ + ++ input_line_pointer; /* Compensate for end of loop. */ + } else { + c = ','; /* Do loop. */ + } + + while (c == ',' || c == '<' || c == '"' || ('0' <= c && c <= '9')) { + int i; + + SKIP_WHITESPACE(); + switch (*input_line_pointer) { + case '\"': + ++input_line_pointer; /* ->1st char of string. */ + while (is_a_char(c = next_char_of_string())) { + FRAG_APPEND_1_CHAR(c); + } + if (append_zero) { + FRAG_APPEND_1_CHAR(0); + } + know(input_line_pointer[-1] == '\"'); + break; + + case '<': + input_line_pointer++; + c = get_single_number(); + FRAG_APPEND_1_CHAR(c); + if (*input_line_pointer != '>') { + as_bad("Expected <nn>"); + } + input_line_pointer++; + break; + + case ',': + input_line_pointer++; + break; + + default: + i = get_absolute_expression(); + FRAG_APPEND_1_CHAR(i); + break; + } /* switch on next char */ + + SKIP_WHITESPACE(); + c = *input_line_pointer; + } + + demand_empty_rest_of_line(); +} /* stringer() */ + +/* FIXME-SOMEDAY: I had trouble here on characters with the + high bits set. We'll probably also have trouble with + multibyte chars, wide chars, etc. Also be careful about + returning values bigger than 1 byte. xoxorich. */ + +unsigned int next_char_of_string() { + register unsigned int c; + + c = *input_line_pointer++ & CHAR_MASK; + switch (c) { + case '\"': + c = NOT_A_CHAR; + break; + + case '\\': + switch (c = *input_line_pointer++) { + case 'b': + c = '\b'; + break; + + case 'f': + c = '\f'; + break; + + case 'n': + c = '\n'; + break; + + case 'r': + c = '\r'; + break; + + case 't': + c = '\t'; + break; + +#ifdef BACKSLASH_V + case 'v': + c = '\013'; + break; +#endif + + case '\\': + case '"': + break; /* As itself. */ + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + long number; + + for (number = 0; isdigit(c); c = *input_line_pointer++) { + number = number * 8 + c - '0'; + } + c = number & 0xff; + } + --input_line_pointer; + break; + + case '\n': + /* To be compatible with BSD 4.2 as: give the luser a linefeed!! */ + as_warn("Unterminated string: Newline inserted."); + c = '\n'; + break; + + default: + +#ifdef ONLY_STANDARD_ESCAPES + as_bad("Bad escaped character in string, '?' assumed"); + c = '?'; +#endif /* ONLY_STANDARD_ESCAPES */ + + break; + } /* switch on escaped char */ + break; + + default: + break; + } /* switch on char */ + return(c); +} /* next_char_of_string() */ + +static segT + get_segmented_expression (expP) +register expressionS * expP; +{ + register segT retval; + + if ((retval = expression(expP)) == SEG_PASS1 || retval == SEG_ABSENT || retval == SEG_BIG) + { + as_bad("Expected address expression: absolute 0 assumed"); + retval = expP->X_seg = SEG_ABSOLUTE; + expP->X_add_number = 0; + expP->X_add_symbol = expP->X_subtract_symbol = 0; + } + return (retval); /* SEG_ ABSOLUTE,UNKNOWN,DATA,TEXT,BSS */ +} + +static segT get_known_segmented_expression(expP) +register expressionS *expP; +{ + register segT retval; + register char * name1; + register char * name2; + + if ((retval = get_segmented_expression (expP)) == SEG_UNKNOWN) + { + name1 = expP->X_add_symbol ? S_GET_NAME(expP->X_add_symbol) : ""; + name2 = expP->X_subtract_symbol ? + S_GET_NAME(expP->X_subtract_symbol) : + ""; + if (name1 && name2) + { + as_warn("Symbols \"%s\" \"%s\" are undefined: absolute 0 assumed.", + name1, name2); + } + else + { + as_warn("Symbol \"%s\" undefined: absolute 0 assumed.", + name1 ? name1 : name2); + } + retval = expP->X_seg = SEG_ABSOLUTE; + expP->X_add_number = 0; + expP->X_add_symbol = expP->X_subtract_symbol = NULL; + } +#ifndef MANY_SEGMENTS + know(retval == SEG_ABSOLUTE || retval == SEG_DATA || retval == SEG_TEXT || retval == SEG_BSS || retval == SEG_DIFFERENCE); +#endif + return (retval); + +} /* get_known_segmented_expression() */ + + + +/* static */ long /* JF was static, but can't be if the MD pseudos are to use it */ + get_absolute_expression() +{ + expressionS exp; + register segT s; + + if ((s = expression(&exp)) != SEG_ABSOLUTE) { + if (s != SEG_ABSENT) { + as_bad("Bad Absolute Expression, absolute 0 assumed."); + } + exp.X_add_number = 0; + } + return(exp.X_add_number); +} /* get_absolute_expression() */ + +char /* return terminator */ + get_absolute_expression_and_terminator(val_pointer) +long * val_pointer; /* return value of expression */ +{ + *val_pointer = get_absolute_expression(); + return (*input_line_pointer++); +} + +/* + * demand_copy_C_string() + * + * Like demand_copy_string, but return NULL if the string contains any '\0's. + * Give a warning if that happens. + */ +char * + demand_copy_C_string (len_pointer) +int *len_pointer; +{ + register char *s; + + if ((s = demand_copy_string(len_pointer)) != 0) { + register int len; + + for (len = *len_pointer; + len > 0; + len--) { + if (*s == 0) { + s = 0; + len = 1; + *len_pointer = 0; + as_bad("This string may not contain \'\\0\'"); + } + } + } + return(s); +} + +/* + * demand_copy_string() + * + * Demand string, but return a safe (=private) copy of the string. + * Return NULL if we can't read a string here. + */ +static char *demand_copy_string(lenP) +int *lenP; +{ + register unsigned int c; + register int len; + char *retval; + + len = 0; + SKIP_WHITESPACE(); + if (*input_line_pointer == '\"') { + input_line_pointer++; /* Skip opening quote. */ + + while (is_a_char(c = next_char_of_string())) { + obstack_1grow(¬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); +} /* demand_copy_string() */ + +/* + * is_it_end_of_statement() + * + * In: Input_line_pointer->next character. + * + * Do: Skip input_line_pointer over all whitespace. + * + * Out: 1 if input_line_pointer->end-of-line. + */ +int is_it_end_of_statement() { + SKIP_WHITESPACE(); + return(is_end_of_line[*input_line_pointer]); +} /* is_it_end_of_statement() */ + +void equals(sym_name) +char *sym_name; +{ + register symbolS *symbolP; /* symbol we are working with */ + + input_line_pointer++; + if (*input_line_pointer == '=') + input_line_pointer++; + + while (*input_line_pointer == ' ' || *input_line_pointer == '\t') + input_line_pointer++; + + if (sym_name[0] == '.' && sym_name[1] == '\0') { + /* Turn '. = mumble' into a .org mumble */ + register segT segment; + expressionS exp; + register char *p; + + segment = get_known_segmented_expression(& exp); + if (! need_pass_2) { + if (segment != now_seg && segment != SEG_ABSOLUTE) + as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.", + segment_name(segment), + segment_name(now_seg)); + p = frag_var(rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol, + exp.X_add_number, (char *)0); + * p = 0; + } /* if (ok to make frag) */ + } else { + symbolP=symbol_find_or_make(sym_name); + pseudo_set(symbolP); + } +} /* equals() */ + +/* .include -- include a file at this point. */ + +/* ARGSUSED */ +void s_include(arg) +int arg; +{ + char *newbuf; + char *filename; + int i; + FILE *try; + char *path; + + filename = demand_copy_string(&i); + demand_empty_rest_of_line(); + path = xmalloc(i + include_dir_maxlen + 5 /* slop */); + for (i = 0; i < include_dir_count; i++) { + strcpy(path, include_dirs[i]); + strcat(path, "/"); + strcat(path, filename); + if (0 != (try = fopen(path, "r"))) + { + fclose (try); + goto gotit; + } + } + free(path); + path = filename; + gotit: + /* malloc Storage leak when file is found on path. FIXME-SOMEDAY. */ + newbuf = input_scrub_include_file (path, input_line_pointer); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} /* s_include() */ + +void add_include_dir(path) +char *path; +{ + int i; + + if (include_dir_count == 0) + { + include_dirs = (char **)xmalloc (2 * sizeof (*include_dirs)); + include_dirs[0] = "."; /* Current dir */ + include_dir_count = 2; + } + else + { + include_dir_count++; + include_dirs = (char **) realloc(include_dirs, + include_dir_count*sizeof (*include_dirs)); + } + + include_dirs[include_dir_count-1] = path; /* New one */ + + i = strlen (path); + if (i > include_dir_maxlen) + include_dir_maxlen = i; +} /* add_include_dir() */ + +void s_ignore(arg) +int arg; +{ + while (!is_end_of_line[*input_line_pointer]) { + ++input_line_pointer; + } + ++input_line_pointer; + + return; +} /* s_ignore() */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of read.c */ diff --git a/gnu/usr.bin/as/read.h b/gnu/usr.bin/as/read.h new file mode 100644 index 000000000000..c2fab2d99e02 --- /dev/null +++ b/gnu/usr.bin/as/read.h @@ -0,0 +1,149 @@ +/* read.h - of read.c + + Copyright (C) 1986, 1990, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: read.h,v 1.3 1993/11/30 20:55:45 jkh Exp $ + */ + + +extern char *input_line_pointer; /* -> char we are parsing now. */ + +#define PERMIT_WHITESPACE /* Define to make whitespace be allowed in */ +/* many syntactically unnecessary places. */ +/* Normally undefined. For compatibility */ +/* with ancient GNU cc. */ +/* #undef PERMIT_WHITESPACE */ + +#ifdef PERMIT_WHITESPACE +#define SKIP_WHITESPACE() {if (* input_line_pointer == ' ') ++ input_line_pointer;} +#else +#define SKIP_WHITESPACE() know(*input_line_pointer != ' ' ) +#endif + + +#define LEX_NAME (1) /* may continue a name */ +#define LEX_BEGIN_NAME (2) /* may begin a name */ + +#define is_name_beginner(c) ( lex_type[c] & LEX_BEGIN_NAME ) +#define is_part_of_name(c) ( lex_type[c] & LEX_NAME ) + +#ifndef is_a_char +#define CHAR_MASK (0xff) +#define NOT_A_CHAR (CHAR_MASK+1) +#define is_a_char(c) (((unsigned)(c)) <= CHAR_MASK) +#endif /* is_a_char() */ + +#ifdef PIC +/* We change some of the entries in lex_type on some archs */ +extern char lex_type[]; +#else +extern const char lex_type[]; +#endif +extern char is_end_of_line[]; + +#if __STDC__ == 1 + +char *demand_copy_C_string(int *len_pointer); +char get_absolute_expression_and_terminator(long *val_pointer); +long get_absolute_expression(void); +void add_include_dir(char *path); +void big_cons(int nbytes); +void cons(unsigned int nbytes); +void demand_empty_rest_of_line(void); +void equals(char *sym_name); +void float_cons(int float_type); +void ignore_rest_of_line(void); +void pseudo_set(symbolS *symbolP); +void read_a_source_file(char *name); +void read_begin(void); +void s_abort(void); +void s_align_bytes(int arg); +void s_align_ptwo(void); +void s_app_file(void); +void s_comm(void); +void s_data(void); +void s_else(int arg); +void s_end(int arg); +void s_endif(int arg); +void s_fill(void); +void s_globl(void); +void s_if(int arg); +void s_ifdef(int arg); +void s_ifeqs(int arg); +void s_ignore(int arg); +void s_include(int arg); +void s_lcomm(int needs_align); +void s_lsym(void); +void s_org(void); +void s_set(void); +void s_size(void); +void s_space(void); +void s_text(void); +void s_type(void); + +#else /* not __STDC__ */ + +char *demand_copy_C_string(); +char get_absolute_expression_and_terminator(); +long get_absolute_expression(); +void add_include_dir(); +void big_cons(); +void cons(); +void demand_empty_rest_of_line(); +void equals(); +void float_cons(); +void ignore_rest_of_line(); +void pseudo_set(); +void read_a_source_file(); +void read_begin(); +void s_abort(); +void s_align_bytes(); +void s_align_ptwo(); +void s_app_file(); +void s_comm(); +void s_data(); +void s_else(); +void s_end(); +void s_endif(); +void s_fill(); +void s_globl(); +void s_if(); +void s_ifdef(); +void s_ifeqs(); +void s_ignore(); +void s_include(); +void s_lcomm(); +void s_lsym(); +void s_org(); +void s_set(); +void s_size(); +void s_space(); +void s_text(); +void s_type(); + +#endif /* not __STDC__ */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of read.h */ diff --git a/gnu/usr.bin/as/struc-symbol.h b/gnu/usr.bin/as/struc-symbol.h new file mode 100644 index 000000000000..0961d2bebc02 --- /dev/null +++ b/gnu/usr.bin/as/struc-symbol.h @@ -0,0 +1,132 @@ +/* struct_symbol.h - Internal symbol structure + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + oYou should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: struc-symbol.h,v 1.3 1993/11/30 20:55:46 jkh Exp $ + */ + + +#ifndef __struc_symbol_h__ +#define __struc_symbol_h__ + +struct symbol /* our version of an nlist node */ +{ + obj_symbol_type sy_symbol; /* what we write in .o file (if permitted) */ + unsigned long sy_name_offset; /* 4-origin position of sy_name in symbols */ + /* part of object file. */ + /* 0 for (nameless) .stabd symbols. */ + /* Not used until write_object_file() time. */ + long sy_number; /* 24 bit symbol number. */ + /* Symbol numbers start at 0 and are */ + /* unsigned. */ + struct symbol *sy_next; /* forward chain, or NULL */ +#ifdef SYMBOLS_NEED_BACKPOINTERS + struct symbol *sy_previous; /* backward chain, or NULL */ +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + struct frag *sy_frag; /* NULL or -> frag this symbol attaches to. */ + struct symbol *sy_forward; /* value is really that of this other symbol */ + /* We will probably want to add a sy_segment here soon. */ + +#ifdef PIC + /* Force symbol into symbol table, even if local */ + int sy_forceout; +#endif + /* Size of symbol as given by the .size directive */ + void *sy_sizexp; /* (expressionS *) */ + + /* Auxiliary type information as given by the .type directive */ + int sy_aux; +#define AUX_OBJECT 1 +#define AUX_FUNC 2 +}; + +typedef struct symbol symbolS; + +#ifdef PIC +symbolS *GOT_symbol; /* Pre-defined "__GLOBAL_OFFSET_TABLE" */ +int got_referenced; +#endif + +typedef unsigned valueT; /* The type of n_value. Helps casting. */ + +#ifndef WORKING_DOT_WORD +struct broken_word { + struct broken_word *next_broken_word;/* One of these strucs per .word x-y */ + fragS *frag; /* Which frag its in */ + char *word_goes_here;/* Where in the frag it is */ + fragS *dispfrag; /* where to add the break */ + symbolS *add; /* symbol_x */ + symbolS *sub; /* - symbol_y */ + long addnum; /* + addnum */ + int added; /* nasty thing happend yet? */ + /* 1: added and has a long-jump */ + /* 2: added but uses someone elses long-jump */ + struct broken_word *use_jump; /* points to broken_word with a similar + long-jump */ +}; +extern struct broken_word *broken_words; +#endif /* ndef WORKING_DOT_WORD */ + +#define SEGMENT_TO_SYMBOL_TYPE(seg) (seg_N_TYPE[(int) (seg)]) +extern const short seg_N_TYPE[]; /* subseg.c */ + +#define N_REGISTER 30 /* Fake N_TYPE value for SEG_REGISTER */ + +#ifdef SYMBOLS_NEED_BACKPOINTERS +#if __STDC__ == 1 + +void symbol_clear_list_pointers(symbolS *symbolP); +void symbol_insert(symbolS *addme, symbolS *target, symbolS **rootP, symbolS **lastP); +void symbol_remove(symbolS *symbolP, symbolS **rootP, symbolS **lastP); +void verify_symbol_chain(symbolS *rootP, symbolS *lastP); + +#else /* not __STDC__ */ + +void symbol_clear_list_pointers(); +void symbol_insert(); +void symbol_remove(); +void verify_symbol_chain(); + +#endif /* not __STDC__ */ + +#define symbol_previous(s) ((s)->sy_previous) + +#else /* SYMBOLS_NEED_BACKPOINTERS */ + +#define symbol_clear_list_pointers(clearme) {clearme->sy_next = NULL;} + +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + +#if __STDC__ == 1 +void symbol_append(symbolS *addme, symbolS *target, symbolS **rootP, symbolS **lastP); +#else /* not __STDC__ */ +void symbol_append(); +#endif /* not __STDC__ */ + +#define symbol_next(s) ((s)->sy_next) + +#endif /* __struc_symbol_h__ */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of struc-symbol.h */ diff --git a/gnu/usr.bin/as/subsegs.c b/gnu/usr.bin/as/subsegs.c new file mode 100644 index 000000000000..8edca4c74e02 --- /dev/null +++ b/gnu/usr.bin/as/subsegs.c @@ -0,0 +1,308 @@ +/* subsegs.c - subsegments - + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Segments & sub-segments. + */ + +#ifndef lint +static char rcsid[] = "$Id: subsegs.c,v 1.2 1993/11/03 00:52:19 paul Exp $"; +#endif + +#include "as.h" + +#include "subsegs.h" +#include "obstack.h" + +#ifdef MANY_SEGMENTS +segment_info_type segment_info[SEG_MAXIMUM_ORDINAL]; + +frchainS* frchain_root, + * frchain_now; + +#else +frchainS* frchain_root, + * frchain_now, /* Commented in "subsegs.h". */ + * data0_frchainP; + +#endif +char * const /* in: segT out: char* */ + seg_name[] = { + "absolute", +#ifdef MANY_SEGMENTS + "e0","e1","e2","e3","e4","e5","e6","e7","e8","e9", +#else + "text", + "data", + "bss", +#endif + "unknown", + "absent", + "pass1", + "ASSEMBLER-INTERNAL-LOGIC-ERROR!", + "bignum/flonum", + "difference", + "debug", + "transfert vector preload", + "transfert vector postload", + "register", + "", + }; /* Used by error reporters, dumpers etc. */ + + +void + subsegs_begin() +{ + /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */ +#ifdef MANY_SEGMENTS +#else + know(SEG_ABSOLUTE == 0); + know(SEG_TEXT == 1); + know(SEG_DATA == 2); + know(SEG_BSS == 3); + know(SEG_UNKNOWN == 4); + know(SEG_ABSENT == 5); + know(SEG_PASS1 == 6); + know(SEG_GOOF == 7); + know(SEG_BIG == 8); + know(SEG_DIFFERENCE == 9); + know(SEG_DEBUG == 10); + know(SEG_NTV == 11); + know(SEG_PTV == 12); + know(SEG_REGISTER == 13); + know(SEG_MAXIMUM_ORDINAL == SEG_REGISTER ); + /* know(segment_name(SEG_MAXIMUM_ORDINAL + 1)[0] == 0);*/ +#endif + + 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); + memset(frag_now, SIZEOF_STRUCT_FRAG, 0); + /* 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. */ +#ifdef MANY_SEGMENTS + { + int i; + for (i = SEG_E0; i < SEG_UNKNOWN; i++) { + subseg_new(i, 0); + segment_info[i].frchainP = frchain_now; + } + } +#else + subseg_new(SEG_DATA, 0); /* .data 0 */ + data0_frchainP = frchain_now; +#endif + +} + +/* + * 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; +#ifdef MANY_SEGMENTS + seg_fix_rootP = &segment_info[seg].fix_root; + seg_fix_tailP = &segment_info[seg].fix_tail; +#else + if (seg == SEG_DATA) { + seg_fix_rootP = &data_fix_root; + seg_fix_tailP = &data_fix_tail; + } else { + know (seg == SEG_TEXT); + seg_fix_rootP = &text_fix_root; + seg_fix_tailP = &text_fix_tail; + } +#endif +} + +/* + * 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 */ +#ifndef MANY_SEGMENTS + know(seg == SEG_DATA || seg == SEG_TEXT); +#endif + 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)); + memset(newP, sizeof(frchainS), 0); + /* This begines on a good boundary */ + /* because a obstack_done() preceeded it. */ + /* It implies an obstack_done(), so we */ + /* expect the next object allocated to */ + /* begin on a correct boundary. */ + *lastPP = newP; + newP->frch_next = frcP; /* perhaps NULL */ + (frcP = newP)->frch_subseg = subseg; + newP->frch_seg = seg; + newP->frch_last = NULL; + } + /* + * Here with frcP->ing to the frchainS for subseg. + */ + frchain_now = frcP; + /* + * Make a fresh frag for the subsegment. + */ + /* We expect this to happen on a correct */ + /* boundary since it was proceeded by a */ + /* obstack_done(). */ + tmp=obstack_alignment_mask(&frags); /* JF disable alignment */ + obstack_alignment_mask(&frags)=0; + frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG); + obstack_alignment_mask(&frags)=tmp; + /* know(frags.obstack_c_next_free == frag_now->fr_literal); */ + /* But we want any more chars to come */ + /* immediately after the structure we just made. */ + new_fragP = frag_now; + new_fragP->fr_next = NULL; + /* + * Append new frag to current frchain. + */ + former_last_fragP = frcP->frch_last; + if (former_last_fragP) + { + know( former_last_fragP->fr_next == NULL ); + know( frchain_now->frch_root ); + former_last_fragP->fr_next = new_fragP; + } + else + { + frcP->frch_root = new_fragP; + } + frcP->frch_last = new_fragP; + } /* if (changing subsegments) */ +} /* subseg_new() */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of subsegs.c */ diff --git a/gnu/usr.bin/as/subsegs.h b/gnu/usr.bin/as/subsegs.h new file mode 100644 index 000000000000..3ca625ec79a0 --- /dev/null +++ b/gnu/usr.bin/as/subsegs.h @@ -0,0 +1,93 @@ +/* subsegs.h -> subsegs.c + + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: subsegs.h,v 1.2 1993/11/03 00:52:20 paul Exp $ + */ + + +/* + * 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. */ + + +#ifdef MANY_SEGMENTS +typedef struct +{ + frchainS *frchainP; + int hadone; + int user_stuff; + /* struct frag *frag_root;*/ + /* struct frag *last_frag;*/ + fixS *fix_root; + fixS *fix_tail; + struct internal_scnhdr scnhdr; + symbolS *dot; + + struct lineno_list *lineno_list_head; + struct lineno_list *lineno_list_tail; + +} segment_info_type; +segment_info_type segment_info[]; +#else +extern frchainS * data0_frchainP; +extern frchainS * bss0_frchainP; +/* Sentinel for frchain crawling. */ +/* Points to the 1st data-segment frchain. */ +/* (Which is pointed to by the last text- */ +/* segment frchain.) */ + +#endif + +/* end of subsegs.h */ diff --git a/gnu/usr.bin/as/symbols.c b/gnu/usr.bin/as/symbols.c new file mode 100644 index 000000000000..46761e64b0c6 --- /dev/null +++ b/gnu/usr.bin/as/symbols.c @@ -0,0 +1,658 @@ +/* symbols.c -symbol table- + + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef lint +static char rcsid[] = "$Id: symbols.c,v 1.2 1993/11/03 00:52:22 paul Exp $"; +#endif + +#include "as.h" + +#include "obstack.h" /* For "symbols.h" */ +#include "subsegs.h" + +#ifndef WORKING_DOT_WORD +extern int new_broken_words; +#endif + +static + struct hash_control * + sy_hash; /* symbol-name => struct symbol pointer */ + +/* Below are commented in "symbols.h". */ +unsigned int local_bss_counter; +symbolS * symbol_rootP; +symbolS * symbol_lastP; +symbolS abs_symbol; + +symbolS* dot_text_symbol; +symbolS* dot_data_symbol; +symbolS* dot_bss_symbol; + +struct obstack notes; + +/* + * Un*x idea of local labels. They are made by "n:" where n + * is any decimal digit. Refer to them with + * "nb" for previous (backward) n: + * or "nf" for next (forward) n:. + * + * Like Un*x AS, we have one set of local label counters for entire assembly, + * not one set per (sub)segment like in most assemblers. This implies that + * one can refer to a label in another segment, and indeed some crufty + * compilers have done just that. + * + * I document the symbol names here to save duplicating words elsewhere. + * The mth occurence of label n: is turned into the symbol "Ln^Am" where + * n is a digit and m is a decimal number. "L" makes it a label discarded + * unless debugging and "^A"('\1') ensures no ordinary symbol SHOULD get the + * same name as a local label symbol. The first "4:" is "L4^A1" - the m + * numbers begin at 1. + */ + +typedef short unsigned int + local_label_countT; + +static local_label_countT + local_label_counter[10]; + +static /* Returned to caller, then copied. */ + char symbol_name_build[12]; /* used for created names ("4f") */ + +#ifdef LOCAL_LABELS_DOLLAR +int local_label_defined[10]; +#endif + + +void + symbol_begin() +{ + symbol_lastP = NULL; + symbol_rootP = NULL; /* In case we have 0 symbols (!!) */ + sy_hash = hash_new(); + memset((char *)(& abs_symbol), '\0', sizeof(abs_symbol)); + S_SET_SEGMENT(&abs_symbol, SEG_ABSOLUTE); /* Can't initialise a union. Sigh. */ + memset((char *)(local_label_counter), '\0', 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 ++ = 1; /* ^A */ + * p ++ = 'L'; + * p ++ = n + '0'; /* Make into ASCII */ + n = local_label_counter[ n ] + augend; + /* version number of this local label */ + /* + * Next code just does sprintf( {}, "%d", n); + * It is more elegant to do the next part recursively, but a procedure + * call for each digit emitted is considered too costly. + */ + q = symbol_name_temporary; + for (*q++=0; n; q++) /* emits NOTHING if n starts as 0 */ + { + know(n>0); /* We expect n > 0 always */ + *q = n % 10 + '0'; + n /= 10; + } + while (( * p ++ = * -- q ) != '\0') ;; + + /* The label, as a '\0' ended string, starts at symbol_name_build. */ + return(symbol_name_build); +} /* local_label_name() */ + + +void local_colon (n) +int n; /* just saw "n:" */ +{ + local_label_counter[n] ++; +#ifdef LOCAL_LABELS_DOLLAR + local_label_defined[n]=1; +#endif + colon (local_label_name (n, 0)); +} + +/* + * symbol_new() + * + * Return a pointer to a new symbol. + * Die if we can't make a new symbol. + * Fill in the symbol's values. + * Add symbol to end of symbol chain. + * + * + * Please always call this to create a new symbol. + * + * Changes since 1985: Symbol names may not contain '\0'. Sigh. + * 2nd argument is now a SEG rather than a TYPE. The mapping between + * segments and types is mostly encapsulated herein (actually, we inherit it + * from macros in struc-symbol.h). + */ + +symbolS *symbol_new(name, segment, value, frag) +char *name; /* It is copied, the caller can destroy/modify */ +segT segment; /* Segment identifier (SEG_<something>) */ +long value; /* Symbol value */ +fragS *frag; /* Associated fragment */ +{ + unsigned int name_length; + char *preserved_copy_of_name; + symbolS *symbolP; + + name_length = strlen(name) + 1; /* +1 for \0 */ + obstack_grow(¬es, name, name_length); + preserved_copy_of_name = obstack_finish(¬es); + symbolP = (symbolS *) obstack_alloc(¬es, sizeof(symbolS)); + + /* symbol must be born in some fixed state. This seems as good as any. */ + memset(symbolP, 0, sizeof(symbolS)); + +#ifdef STRIP_UNDERSCORE + S_SET_NAME(symbolP, (*preserved_copy_of_name == '_' + ? preserved_copy_of_name + 1 + : preserved_copy_of_name)); +#else /* STRIP_UNDERSCORE */ + S_SET_NAME(symbolP, preserved_copy_of_name); +#endif /* STRIP_UNDERSCORE */ + + S_SET_SEGMENT(symbolP, segment); + S_SET_VALUE(symbolP, value); + /* symbol_clear_list_pointers(symbolP); uneeded if symbol is born zeroed. */ + + symbolP->sy_frag = frag; + /* krm: uneeded if symbol is born zeroed. + symbolP->sy_forward = NULL; */ /* JF */ + symbolP->sy_number = ~0; + symbolP->sy_name_offset = ~0; + + /* + * Link to end of symbol chain. + */ + symbol_append(symbolP, symbol_lastP, &symbol_rootP, &symbol_lastP); + + obj_symbol_new_hook(symbolP); + +#ifdef DEBUG + /* verify_symbol_chain(symbol_rootP, symbol_lastP); */ +#endif /* DEBUG */ + + return(symbolP); +} /* symbol_new() */ + + +/* + * colon() + * + * We have just seen "<name>:". + * Creates a struct symbol unless it already exists. + * + * Gripes if we are redefining a symbol incompatibly (and ignores it). + * + */ +void colon(sym_name) /* just seen "x:" - rattle symbols & frags */ +register char * sym_name; /* symbol name, as a cannonical string */ +/* We copy this string: OK to alter later. */ +{ + register symbolS * symbolP; /* symbol we are working with */ + +#ifdef LOCAL_LABELS_DOLLAR + /* Sun local labels go out of scope whenever a non-local symbol is defined. */ + + if (*sym_name != 'L') + memset((void *) local_label_defined, '\0', 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 const md_short_jump_size; + extern const md_long_jump_size; + possible_bytes=md_short_jump_size + new_broken_words * md_long_jump_size; + + frag_tmp=frag_now; + frag_opcode=frag_var(rs_broken_word, + possible_bytes, + possible_bytes, + (relax_substateT) 0, + (symbolS *) broken_words, + 0L, + NULL); + + /* We want to store the pointer to where to insert the jump table in the + fr_opcode of the rs_broken_word frag. This requires a little hackery */ + while (frag_tmp && (frag_tmp->fr_type != rs_broken_word || frag_tmp->fr_opcode)) + frag_tmp=frag_tmp->fr_next; + know(frag_tmp); + frag_tmp->fr_opcode=frag_opcode; + new_broken_words = 0; + + for (a=broken_words;a && a->dispfrag == 0;a=a->next_broken_word) + a->dispfrag=frag_tmp; + } +#endif + if ((symbolP = symbol_find(sym_name)) != 0) { +#ifdef OBJ_VMS + /* + * If the new symbol is .comm AND it has a size of zero, + * we ignore it (i.e. the old symbol overrides it) + */ + if ((SEGMENT_TO_SYMBOL_TYPE((int) now_seg) == (N_UNDF | N_EXT)) && + ((obstack_next_free(& frags) - frag_now->fr_literal) == 0)) + return; + /* + * If the old symbol is .comm and it has a size of zero, + * we override it with the new symbol value. + */ + if (S_IS_EXTERNAL(symbolP) && S_IS_DEFINED(symbolP) + && (S_GET_VALUE(symbolP) == 0)) { + symbolP->sy_frag = frag_now; + S_GET_OTHER(symbolP) = const_flag; + S_SET_VALUE(symbolP, obstack_next_free(& frags) - frag_now->fr_literal); + symbolP->sy_symbol.n_type |= + SEGMENT_TO_SYMBOL_TYPE((int) now_seg); /* keep N_EXT bit */ + return; + } +#endif /* OBJ_VMS */ + /* + * Now check for undefined symbols + */ + if (!S_IS_DEFINED(symbolP)) { + if (S_GET_VALUE(symbolP) == 0) { + symbolP->sy_frag = frag_now; +#ifdef OBJ_VMS + S_GET_OTHER(symbolP) = const_flag; +#endif + S_SET_VALUE(symbolP, obstack_next_free(&frags) - frag_now->fr_literal); + S_SET_SEGMENT(symbolP, now_seg); +#ifdef N_UNDF + know(N_UNDF == 0); +#endif /* if we have one, it better be zero. */ + + } else { + /* + * There are still several cases to check: + * A .comm/.lcomm symbol being redefined as + * initialized data is OK + * A .comm/.lcomm symbol being redefined with + * a larger size is also OK + * + * This only used to be allowed on VMS gas, but Sun cc + * on the sparc also depends on it. + */ + /* char New_Type = SEGMENT_TO_SYMBOL_TYPE((int) now_seg); */ +#ifdef MANY_SEGMENTS +#define SEG_BSS SEG_E2 +#define SEG_DATA SEG_E1 +#endif + + if (((!S_IS_DEBUG(symbolP) && !S_IS_DEFINED(symbolP) && S_IS_EXTERNAL(symbolP)) + || (S_GET_SEGMENT(symbolP) == SEG_BSS)) + && ((now_seg == SEG_DATA) + || (now_seg == S_GET_SEGMENT(symbolP)))) { + /* + * Select which of the 2 cases this is + */ + if (now_seg != SEG_DATA) { + /* + * New .comm for prev .comm symbol. + * If the new size is larger we just + * change its value. If the new size + * is smaller, we ignore this symbol + */ + if (S_GET_VALUE(symbolP) + < ((unsigned) (obstack_next_free(& frags) - frag_now->fr_literal))) { + S_SET_VALUE(symbolP, + obstack_next_free(& frags) - + frag_now->fr_literal); + } + } else { + /* + * It is a .comm/.lcomm being converted + * to initialized data. + */ + symbolP->sy_frag = frag_now; +#ifdef OBJ_VMS + S_GET_OTHER(symbolP) = const_flag; +#endif /* OBJ_VMS */ + S_SET_VALUE(symbolP, obstack_next_free(& frags) - frag_now->fr_literal); + S_SET_SEGMENT(symbolP, now_seg); /* keep N_EXT bit */ + } + } else { +#ifdef OBJ_COFF + as_fatal("Symbol \"%s\" is already defined as \"%s\"/%d.", + sym_name, + segment_name(S_GET_SEGMENT(symbolP)), + S_GET_VALUE(symbolP)); +#else /* OBJ_COFF */ + as_fatal("Symbol \"%s\" is already defined as \"%s\"/%d.%d.%d.", + sym_name, + segment_name(S_GET_SEGMENT(symbolP)), + S_GET_OTHER(symbolP), S_GET_DESC(symbolP), + S_GET_VALUE(symbolP)); +#endif /* OBJ_COFF */ + } + } /* if the undefined symbol has no value */ + } else + { + /* Don't blow up if the definition is the same */ + if (!(frag_now == symbolP->sy_frag + && S_GET_VALUE(symbolP) == obstack_next_free(&frags) - frag_now->fr_literal + && S_GET_SEGMENT(symbolP) == now_seg) ) + as_fatal("Symbol %s already defined.", sym_name); + } /* if this symbol is not yet defined */ + + } else { + symbolP = symbol_new(sym_name, + now_seg, + (valueT)(obstack_next_free(&frags)-frag_now->fr_literal), + frag_now); +#ifdef OBJ_VMS + S_SET_OTHER(symbolP, const_flag); +#endif /* OBJ_VMS */ + + symbol_table_insert(symbolP); + } /* if we have seen this symbol before */ + + return; +} /* colon() */ + + +/* + * symbol_table_insert() + * + * Die if we can't insert the symbol. + * + */ + +void symbol_table_insert(symbolP) +symbolS *symbolP; +{ + register char *error_string; + + know(symbolP); + know(S_GET_NAME(symbolP)); + + if (*(error_string = hash_jam(sy_hash, S_GET_NAME(symbolP), (char *)symbolP))) { + as_fatal("Inserting \"%s\" into symbol table failed: %s", + S_GET_NAME(symbolP), error_string); + } /* on error */ +} /* symbol_table_insert() */ + +/* + * symbol_find_or_make() + * + * If a symbol name does not exist, create it as undefined, and insert + * it into the symbol table. Return a pointer to it. + */ +symbolS *symbol_find_or_make(name) +char *name; +{ + register symbolS *symbolP; + + symbolP = symbol_find(name); + + if (symbolP == NULL) { + symbolP = symbol_make(name); + + symbol_table_insert(symbolP); + } /* if symbol wasn't found */ + + return(symbolP); +} /* symbol_find_or_make() */ + +symbolS *symbol_make(name) +char *name; +{ + symbolS *symbolP; + + /* Let the machine description default it, e.g. for register names. */ + symbolP = md_undefined_symbol(name); + + if (!symbolP) { + symbolP = symbol_new(name, + SEG_UNKNOWN, + 0, + &zero_address_frag); + } /* if md didn't build us a symbol */ + + return(symbolP); +} /* symbol_make() */ + +/* + * symbol_find() + * + * Implement symbol table lookup. + * In: A symbol's name as a string: '\0' can't be part of a symbol name. + * Out: NULL if the name was not in the symbol table, else the address + * of a struct symbol associated with that name. + */ + +symbolS *symbol_find(name) +char *name; +{ +#ifdef STRIP_UNDERSCORE + return(symbol_find_base(name, 1)); +#else /* STRIP_UNDERSCORE */ + return(symbol_find_base(name, 0)); +#endif /* STRIP_UNDERSCORE */ +} /* symbol_find() */ + +symbolS *symbol_find_base(name, strip_underscore) +char *name; +int strip_underscore; +{ + if (strip_underscore && *name == '_') name++; + return ( (symbolS *) hash_find( sy_hash, name )); +} + +/* + * Once upon a time, symbols were kept in a singly linked list. At + * least coff needs to be able to rearrange them from time to time, for + * which a doubly linked list is much more convenient. Loic did these + * as macros which seemed dangerous to me so they're now functions. + * xoxorich. + */ + +/* Link symbol ADDME after symbol TARGET in the chain. */ +void symbol_append(addme, target, rootPP, lastPP) +symbolS *addme; +symbolS *target; +symbolS **rootPP; +symbolS **lastPP; +{ + if (target == NULL) { + know(*rootPP == NULL); + know(*lastPP == NULL); + *rootPP = addme; + *lastPP = addme; + return; + } /* if the list is empty */ + + if (target->sy_next != NULL) { +#ifdef SYMBOLS_NEED_BACKPOINTERS + target->sy_next->sy_previous = addme; +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + } else { + know(*lastPP == target); + *lastPP = addme; + } /* if we have a next */ + + addme->sy_next = target->sy_next; + target->sy_next = addme; + +#ifdef SYMBOLS_NEED_BACKPOINTERS + addme->sy_previous = target; +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + +#ifdef DEBUG + /* verify_symbol_chain(*rootPP, *lastPP); */ +#endif /* DEBUG */ + + return; +} /* symbol_append() */ + +#ifdef SYMBOLS_NEED_BACKPOINTERS +/* Remove SYMBOLP from the list. */ +void symbol_remove(symbolP, rootPP, lastPP) +symbolS *symbolP; +symbolS **rootPP; +symbolS **lastPP; +{ + if (symbolP == *rootPP) { + *rootPP = symbolP->sy_next; + } /* if it was the root */ + + if (symbolP == *lastPP) { + *lastPP = symbolP->sy_previous; + } /* if it was the tail */ + + if (symbolP->sy_next != NULL) { + symbolP->sy_next->sy_previous = symbolP->sy_previous; + } /* if not last */ + + if (symbolP->sy_previous != NULL) { + symbolP->sy_previous->sy_next = symbolP->sy_next; + } /* if not first */ + +#ifdef DEBUG + verify_symbol_chain(*rootPP, *lastPP); +#endif /* DEBUG */ + + return; +} /* symbol_remove() */ + +/* Set the chain pointers of SYMBOL to null. */ +void symbol_clear_list_pointers(symbolP) +symbolS *symbolP; +{ + symbolP->sy_next = NULL; + symbolP->sy_previous = NULL; +} /* symbol_clear_list_pointers() */ + +/* Link symbol ADDME before symbol TARGET in the chain. */ +void symbol_insert(addme, target, rootPP, lastPP) +symbolS *addme; +symbolS *target; +symbolS **rootPP; +symbolS **lastPP; +{ + if (target->sy_previous != NULL) { + target->sy_previous->sy_next = addme; + } else { + know(*rootPP == target); + *rootPP = addme; + } /* if not first */ + + addme->sy_previous = target->sy_previous; + target->sy_previous = addme; + addme->sy_next = target; + +#ifdef DEBUG + verify_symbol_chain(*rootPP, *lastPP); +#endif /* DEBUG */ + + return; +} /* symbol_insert() */ +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + +void verify_symbol_chain(rootP, lastP) +symbolS *rootP; +symbolS *lastP; +{ + symbolS *symbolP = rootP; + + if (symbolP == NULL) { + return; + } /* empty chain */ + + for ( ; symbol_next(symbolP) != NULL; symbolP = symbol_next(symbolP)) { +#ifdef SYMBOLS_NEED_BACKPOINTERS + /*$if (symbolP->sy_previous) { + know(symbolP->sy_previous->sy_next == symbolP); + } else { + know(symbolP == rootP); + }$*/ /* both directions */ + know(symbolP->sy_next->sy_previous == symbolP); +#else /* SYMBOLS_NEED_BACKPOINTERS */ + ; +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + } /* verify pointers */ + + know(lastP == symbolP); + + return; +} /* verify_symbol_chain() */ + + +/* + * decode name that may have been generated by local_label_name() above. If + * the name wasn't generated by local_label_name(), then return it unaltered. + * This is used for error messages. + */ + +char *decode_local_label_name(s) +char *s; +{ + char *symbol_decode; + int label_number; + /* int label_version; */ + char *message_format = "\"%d\" (instance number %s of a local label)"; + + if (s[0] != 'L' + || s[2] != 1) { + return(s); + } /* not a local_label_name() generated name. */ + + label_number = s[1] - '0'; + + (void) sprintf(symbol_decode = obstack_alloc(¬es, strlen(s + 3) + strlen(message_format) + 10), + message_format, label_number, s + 3); + + return(symbol_decode); +} /* decode_local_label_name() */ + + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of symbols.c */ diff --git a/gnu/usr.bin/as/symbols.h b/gnu/usr.bin/as/symbols.h new file mode 100644 index 000000000000..4247c6bf90c7 --- /dev/null +++ b/gnu/usr.bin/as/symbols.h @@ -0,0 +1,82 @@ +/* symbols.h - + + Copyright (C) 1987, 1990, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: symbols.h,v 1.2 1993/11/03 00:52:23 paul Exp $ + */ + + +extern struct obstack notes; /* eg FixS live here. */ + +extern struct obstack cond_obstack; /* this is where we track .ifdef/.endif + (if we do that at all). */ + +extern unsigned int local_bss_counter; /* Zeroed before a pass. */ +/* Only used by .lcomm directive. */ + +extern symbolS *symbol_rootP; /* all the symbol nodes */ +extern symbolS *symbol_lastP; /* last struct symbol we made, or NULL */ + +extern symbolS abs_symbol; + +extern symbolS *dot_text_symbol; +extern symbolS *dot_data_symbol; +extern symbolS *dot_bss_symbol; + +#if __STDC__ == 1 + +char *decode_local_label_name(char *s); +char *local_label_name(int n, int augend); +symbolS *symbol_find(char *name); +symbolS *symbol_find_base(char *name, int strip_underscore); +symbolS *symbol_find_or_make(char *name); +symbolS *symbol_make(char *name); +symbolS *symbol_new(char *name, segT segment, long value, fragS *frag); +void colon(char *sym_name); +void local_colon(int n); +void symbol_begin(void); +void symbol_table_insert(symbolS *symbolP); +void verify_symbol_chain(symbolS *rootP, symbolS *lastP); + +#else /* not __STDC__ */ + +char *decode_local_label_name(); +char *local_label_name(); +symbolS *symbol_find(); +symbolS *symbol_find_base(); +symbolS *symbol_find_or_make(); +symbolS *symbol_make(); +symbolS *symbol_new(); +void colon(); +void local_colon(); +void symbol_begin(); +void symbol_table_insert(); +void verify_symbol_chain(); + +#endif /* not __STDC__ */ + + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of symbols.h */ diff --git a/gnu/usr.bin/as/tc.h b/gnu/usr.bin/as/tc.h new file mode 100644 index 000000000000..fd5640128209 --- /dev/null +++ b/gnu/usr.bin/as/tc.h @@ -0,0 +1,112 @@ +/* tc.h - target cpu dependent + + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * $Id: tc.h,v 1.1 1993/11/03 00:52:25 paul Exp $ + */ + + +/* In theory (mine, at least!) the machine dependent part of the assembler + should only have to include one file. This one. -- JF */ + +extern const pseudo_typeS md_pseudo_table[]; + +/* JF moved this here from as.h under the theory that nobody except MACHINE.c + and write.c care about it anyway. */ + +typedef struct +{ + long rlx_forward; /* Forward reach. Signed number. > 0. */ + long rlx_backward; /* Backward reach. Signed number. < 0. */ + unsigned char rlx_length; /* Bytes length of this address. */ + relax_substateT rlx_more; /* Next longer relax-state. */ + /* 0 means there is no 'next' relax-state. */ +} +relax_typeS; + +extern const relax_typeS md_relax_table[]; /* Define it in MACHINE.c */ + +extern int md_reloc_size; /* Size of a relocation record */ + +extern void (*md_emit_relocations)(); + +#if __STDC__ == 1 + +char *md_atof(int what_statement_type, char *literalP, int *sizeP); +int md_estimate_size_before_relax(fragS *fragP, segT segment); +int md_parse_option(char **argP, int *cntP, char ***vecP); +long md_pcrel_from(fixS *fixP); +long md_section_align(segT seg, long align); +short tc_coff_fix2rtype(fixS *fixP); +symbolS *md_undefined_symbol(char *name); +void md_apply_fix(fixS *fixP, long val); +void md_assemble(char *str); +void md_begin(void); +void md_convert_frag(object_headers *headers, fragS *fragP); +void md_create_long_jump(char *ptr, long from_addr, long to_addr, fragS *frag, symbolS *to_symbol); +void md_create_short_jump(char *ptr, long from_addr, long to_addr, fragS *frag, symbolS *to_symbol); +void md_end(void); +void md_number_to_chars(char *buf, long val, int n); +void md_operand(expressionS *expressionP); + +#ifndef tc_crawl_symbol_chain +void tc_crawl_symbol_chain(object_headers *headers); +#endif /* tc_crawl_symbol_chain */ + +#ifndef tc_headers_hook +void tc_headers_hook(object_headers *headers); +#endif /* tc_headers_hook */ + +#else + +char *md_atof(); +int md_estimate_size_before_relax(); +int md_parse_option(); +long md_pcrel_from(); +long md_section_align(); +short tc_coff_fix2rtype(); +symbolS *md_undefined_symbol(); +void md_apply_fix(); +void md_assemble(); +void md_begin(); +void md_convert_frag(); +void md_create_long_jump(); +void md_create_short_jump(); +void md_end(); +void md_number_to_chars(); +void md_operand(); + +#ifndef tc_headers_hook +void tc_headers_hook(); +#endif /* tc_headers_hook */ + +#ifndef tc_crawl_symbol_chain +void tc_crawl_symbol_chain(); +#endif /* tc_crawl_symbol_chain */ + +#endif /* __STDC_ */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of tc.h */ diff --git a/gnu/usr.bin/as/testscripts/doboth b/gnu/usr.bin/as/testscripts/doboth new file mode 100755 index 000000000000..dc379e93d3fb --- /dev/null +++ b/gnu/usr.bin/as/testscripts/doboth @@ -0,0 +1,20 @@ +#!/bin/sh +# $Id: doboth,v 1.1 1993/11/03 00:56:17 paul Exp $ + +x=$1 ; shift +y=$1 ; shift + +rm tmp.0 > /dev/null 2>&1 +ln -s $x tmp.0 +$* tmp.0 > tmp.1 + +rm tmp.0 +ln -s $y tmp.0 +$* tmp.0 > tmp.2 + +rm tmp.0 + +diff -c tmp.1 tmp.2 +exit + +#eof diff --git a/gnu/usr.bin/as/testscripts/doobjcmp b/gnu/usr.bin/as/testscripts/doobjcmp new file mode 100755 index 000000000000..9fe6d907558e --- /dev/null +++ b/gnu/usr.bin/as/testscripts/doobjcmp @@ -0,0 +1,89 @@ +#!/bin/sh +# $Id: doobjcmp,v 1.1 1993/11/03 00:56:18 paul Exp $ +# compare two object files, in depth. + +x=$1 +y=$2 +BOTH="$1 $2" + + +# if they cmp, we're fine. +if (cmp $BOTH > /dev/null) +then + exit 0 +fi + +# otherwise, we must look closer. +if (doboth $BOTH size) +then + echo Sizes ok. +else + echo Sizes differ: + size $BOTH +# exit 1 +fi + +if (doboth $BOTH objdump +header) +then + echo Headers ok. +else + echo Header differences. +# exit 1 +fi + +if (doboth $BOTH objdump +text > /dev/null) +then + echo Text ok. +else + echo Text differences. +# doboth $BOTH objdump +text +# exit 1 +fi + +if (doboth $BOTH objdump +data > /dev/null) +then + echo Data ok. +else + echo Data differences. +# doboth $BOTH objdump +data +# exit 1 +fi + +if (doboth $BOTH objdump +symbols > /dev/null) +then + echo Symbols ok. +else + echo -n Symbol differences... + + if (doboth $BOTH dounsortsymbols) + then + echo but symbols are simply ordered differently. +# echo Now what to do about relocs'?' +# exit 1 + else + echo and symbols differ in content. + exit 1 + fi +fi + +# of course, if there were symbol diffs, then the reloc symbol indexes +# will be off. + +if (doboth $BOTH objdump -r > /dev/null) +then + echo Reloc ok. +else + echo -n Reloc differences... + + if (doboth $BOTH dounsortreloc) + then + echo but relocs are simply ordered differently. + else + echo and relocs differ in content. + exit 1 + fi +fi + +exit + +# eof diff --git a/gnu/usr.bin/as/testscripts/dostriptest b/gnu/usr.bin/as/testscripts/dostriptest new file mode 100755 index 000000000000..6f0c2918aeed --- /dev/null +++ b/gnu/usr.bin/as/testscripts/dostriptest @@ -0,0 +1,15 @@ +#!/bin/sh +# $Id: dostriptest,v 1.1 1993/11/03 00:56:19 paul Exp $ + +x=striptest.xx.$$ +y=striptest.yy.$$ + +cp $1 $x +strip $x +cp $2 $y +strip $y + +doobjcmp $x $y +exit + +#eof diff --git a/gnu/usr.bin/as/testscripts/dotest b/gnu/usr.bin/as/testscripts/dotest new file mode 100755 index 000000000000..ff39433d32b9 --- /dev/null +++ b/gnu/usr.bin/as/testscripts/dotest @@ -0,0 +1,44 @@ +#!/bin/sh +# ad hoc debug tool +# $Id: dotest,v 1.1 1993/11/03 00:56:21 paul Exp $ + +x=$1 +y=$2 + +xout=`basename $x`.xxx.$$ +yout=`basename $x`.yyy.$$ + +mkdir $xout +mkdir $yout + +for i in *.s +do + echo Testing $i... + object=`basename $i .s`.o + $x $i -o $xout/$object + $y $i -o $yout/$object + +# if they cmp, we're ok. Otherwise we have to look closer. + + if (cmp $xout/$object $yout/$object) + then + echo $i is ok. + else + if (doobjcmp $xout/$object $yout/$object) + then + echo Not the same but objcmp ok. + else + exit 1 + fi + fi + + echo +done + +rm -rf $xout $yout + +exit 0 + +# EOF + + diff --git a/gnu/usr.bin/as/testscripts/dounsortreloc b/gnu/usr.bin/as/testscripts/dounsortreloc new file mode 100755 index 000000000000..b990553fa6e7 --- /dev/null +++ b/gnu/usr.bin/as/testscripts/dounsortreloc @@ -0,0 +1,9 @@ +#!/bin/sh +# $Id: dounsortreloc,v 1.1 1993/11/03 00:56:22 paul Exp $ +# objdump the reloc table, but strip off the headings and reloc +# numbers and sort the result. Intended for use in comparing reloc +# tables that may not be in the same order. + +objdump +reloc +omit-relocation-numbers +omit-symbol-numbers $1 \ + | sort +#eof diff --git a/gnu/usr.bin/as/testscripts/dounsortsymbols b/gnu/usr.bin/as/testscripts/dounsortsymbols new file mode 100755 index 000000000000..480fe555317e --- /dev/null +++ b/gnu/usr.bin/as/testscripts/dounsortsymbols @@ -0,0 +1,9 @@ +#!/bin/sh +# $Id: dounsortsymbols,v 1.1 1993/11/03 00:56:24 paul Exp $ +# objdump the symbol table, but strip off the headings and symbol +# numbers and sort the result. Intended for use in comparing symbol +# tables that may not be in the same order. + +objdump +symbols +omit-symbol-numbers $1 \ + | sort +#eof diff --git a/gnu/usr.bin/as/version.c b/gnu/usr.bin/as/version.c new file mode 100644 index 000000000000..54462ec2dc0b --- /dev/null +++ b/gnu/usr.bin/as/version.c @@ -0,0 +1,30 @@ +#if (__STDC__ == 1) || defined(const) +const +#endif + +/* 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. + */ + +#ifndef lint +static char rcsid[] = "$Id: version.c,v 1.3 1994/02/14 21:18:05 nate Exp $"; +#endif + +char version_string[] = "GNU assembler version 1.92.3, FreeBSD $Revision: 1.3 $\n"; + +#ifdef HO_VMS +dummy3() +{ +} +#endif + +/* end of version.c */ diff --git a/gnu/usr.bin/as/write.c b/gnu/usr.bin/as/write.c new file mode 100644 index 000000000000..477ead3d57d5 --- /dev/null +++ b/gnu/usr.bin/as/write.c @@ -0,0 +1,1213 @@ +/* write.c - emit .o file + + Copyright (C) 1986, 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This thing should be set up to do byteordering correctly. But... */ + +#ifndef lint +static char rcsid[] = "$Id: write.c,v 1.5 1994/02/20 16:06:12 rgrimes Exp $"; +#endif + +#include "as.h" +#include "subsegs.h" +#include "obstack.h" +#include "output-file.h" + +/* The NOP_OPCODE is for the alignment fill value. + * fill it a nop instruction so that the disassembler does not choke + * on it + */ +#ifndef NOP_OPCODE +#define NOP_OPCODE 0x00 +#endif + +#ifndef MANY_SEGMENTS +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. */ +#endif + +#ifndef WORKING_DOT_WORD +extern const int md_short_jump_size; +extern const int md_long_jump_size; +#endif + +static object_headers headers; + +long string_byte_count; + +static char *the_object_file; + +char *next_object_file_charP; /* Tracks object file bytes. */ + +/* static long length; JF unused */ /* String length, including trailing '\0'. */ + + +#if __STDC__ == 1 + +static int is_dnrange(struct frag *f1, struct frag *f2); +static long fixup_segment(fixS *fixP, segT this_segment_type); +static relax_addressT relax_align(relax_addressT address, long alignment); +void relax_segment(struct frag *segment_frag_root, segT segment_type); + +#else + +static int is_dnrange(); +static long fixup_segment(); +static relax_addressT relax_align(); +void relax_segment(); + +#endif /* not __STDC__ */ + +/* + * fix_new() + * + * Create a fixS in obstack 'notes'. + */ +#ifdef PIC +fixS *fix_new(frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type, got_symbol) +#else +fixS *fix_new(frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type) +#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. */ +#ifdef PIC +symbolS *got_symbol; /* X_got. */ +#endif +long offset; /* X_add_number. */ +int pcrel; /* TRUE if PC-relative relocation. */ +enum reloc_type r_type; /* Relocation type */ +{ + 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; +#ifdef PIC + fixP->fx_gotsy = got_symbol; + if (got_symbol) + pcrel = 1; +#endif + fixP->fx_offset = offset; + fixP->fx_pcrel = pcrel; + fixP->fx_r_type = r_type; + + /* 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; + + /* usually, we want relocs sorted numerically, but while + comparing to older versions of gas that have relocs + reverse sorted, it is convenient to have this compile + time option. xoxorich. */ + +#ifdef REVERSE_SORT_RELOCS + + fixP->fx_next = *seg_fix_rootP; + *seg_fix_rootP = fixP; + +#else /* REVERSE_SORT_RELOCS */ + + fixP->fx_next = NULL; + + if (*seg_fix_tailP) + (*seg_fix_tailP)->fx_next = fixP; + else + *seg_fix_rootP = fixP; + *seg_fix_tailP = fixP; + +#endif /* REVERSE_SORT_RELOCS */ + + fixP->fx_callj = 0; + return(fixP); +} /* fix_new() */ + +#ifndef BFD +void write_object_file() +{ + register struct frchain * frchainP; /* Track along all frchains. */ + register fragS * fragP; /* Track along all frags. */ + register struct frchain * next_frchainP; + register fragS * * prev_fragPP; + /* register char * name; */ + /* symbolS *symbolP; */ + /* register symbolS ** symbolPP; */ + /* register fixS * fixP; JF unused */ + unsigned int data_siz; + + long object_file_size; + +#ifdef OBJ_VMS + /* + * Under VMS we try to be compatible with VAX-11 "C". Thus, we + * call a routine to check for the definition of the procedure + * "_main", and if so -- fix it up so that it can be program + * entry point. + */ + VMS_Check_For_Main(); +#endif /* OBJ_VMS */ + /* + * After every sub-segment, we fake an ".align ...". This conforms to BSD4.2 + * brane-damage. We then fake ".fill 0" because that is the kind of frag + * that requires least thought. ".align" frags like to have a following + * frag since that makes calculating their intended length trivial. + */ +#ifndef SUB_SEGMENT_ALIGN +#define SUB_SEGMENT_ALIGN (2) +#endif + for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next) { +#ifdef OBJ_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 /* OBJ_VMS */ + subseg_new (frchainP->frch_seg, frchainP->frch_subseg); + frag_align (SUB_SEGMENT_ALIGN, NOP_OPCODE); + /* frag_align will have left a new frag. */ + /* Use this last frag for an empty ".fill". */ + /* + * For this segment ... + * Create a last frag. Do not leave a "being filled in frag". + */ + frag_wane (frag_now); + frag_now->fr_fix = 0; + know( frag_now->fr_next == NULL ); + /* know(frags.obstack_c_base == frags.obstack_c_next_free); */ + /* Above shows we haven't left a half-completed object on obstack. */ + } /* walk the frag chain */ + + /* + * From now on, we don't care about sub-segments. + * Build one frag chain for each segment. Linked thru fr_next. + * We know that there is at least 1 text frchain & at least 1 data frchain. + */ + prev_fragPP = &text_frag_root; + for (frchainP = frchain_root; frchainP; frchainP = next_frchainP) { + know( frchainP->frch_root ); + *prev_fragPP = frchainP->frch_root; + prev_fragPP = & frchainP->frch_last->fr_next; + + if (((next_frchainP = frchainP->frch_next) == NULL) + || next_frchainP == data0_frchainP) { + prev_fragPP = &data_frag_root; + if (next_frchainP) { + text_last_frag = frchainP->frch_last; + } else { + data_last_frag = frchainP->frch_last; + } + } + } /* walk the frag chain */ + + /* + * We have two segments. If user gave -R flag, then we must put the + * data frags into the text segment. Do this before relaxing so + * we know to take advantage of -R and make shorter addresses. + */ + if (flagseen[ 'R' ]) { + fixS *tmp; + + text_last_frag->fr_next = data_frag_root; + text_last_frag = data_last_frag; + data_last_frag = NULL; + data_frag_root = NULL; + if (text_fix_root) { + for (tmp = text_fix_root; tmp->fx_next; tmp = tmp->fx_next) ;; + tmp->fx_next = data_fix_root; + } else + text_fix_root = data_fix_root; + data_fix_root = NULL; + } + + relax_segment(text_frag_root, SEG_TEXT); + relax_segment(data_frag_root, SEG_DATA); + /* + * Now the addresses of frags are correct within the segment. + */ + + know(text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0); + H_SET_TEXT_SIZE(&headers, text_last_frag->fr_address); + text_last_frag->fr_address = H_GET_TEXT_SIZE(&headers); + + /* + * Join the 2 segments into 1 huge segment. + * To do this, re-compute every rn_address in the SEG_DATA frags. + * Then join the data frags after the text frags. + * + * Determine a_data [length of data segment]. + */ + if (data_frag_root) { + register relax_addressT slide; + + know((text_last_frag->fr_type == rs_fill) && (text_last_frag->fr_offset == 0)); + + H_SET_DATA_SIZE(&headers, data_last_frag->fr_address); + data_last_frag->fr_address = H_GET_DATA_SIZE(&headers); + slide = H_GET_TEXT_SIZE(&headers); /* & in file of the data segment. */ + + for (fragP = data_frag_root; fragP; fragP = fragP->fr_next) { + fragP->fr_address += slide; + } /* for each data frag */ + + know(text_last_frag != 0); + text_last_frag->fr_next = data_frag_root; + } else { + H_SET_DATA_SIZE(&headers,0); + data_siz = 0; + } + + bss_address_frag.fr_address = (H_GET_TEXT_SIZE(&headers) + + H_GET_DATA_SIZE(&headers)); + + H_SET_BSS_SIZE(&headers,local_bss_counter); + + /* + * + * Crawl the symbol chain. + * + * For each symbol whose value depends on a frag, take the address of + * that frag and subsume it into the value of the symbol. + * After this, there is just one way to lookup a symbol value. + * Values are left in their final state for object file emission. + * We adjust the values of 'L' local symbols, even if we do + * not intend to emit them to the object file, because their values + * are needed for fix-ups. + * + * Unless we saw a -L flag, remove all symbols that begin with 'L' + * from the symbol chain. (They are still pointed to by the fixes.) + * + * Count the remaining symbols. + * Assign a symbol number to each symbol. + * Count the number of string-table chars we will emit. + * Put this info into the headers as appropriate. + * + */ + know(zero_address_frag.fr_address == 0); + string_byte_count = sizeof(string_byte_count); + + obj_crawl_symbol_chain(&headers); + + if (string_byte_count == sizeof(string_byte_count)) { + string_byte_count = 0; + } /* if no strings, then no count. */ + + H_SET_STRING_SIZE(&headers, string_byte_count); + + /* + * Addresses of frags now reflect addresses we use in the object file. + * Symbol values are correct. + * Scan the frags, converting any ".org"s and ".align"s to ".fill"s. + * Also converting any machine-dependent frags using md_convert_frag(); + */ + subseg_change(SEG_TEXT, 0); + + for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) { + switch (fragP->fr_type) { + case rs_align: + case rs_org: + fragP->fr_type = rs_fill; + know(fragP->fr_var == 1); + know(fragP->fr_next != NULL); + + 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(&headers, fragP); + + know((fragP->fr_next == NULL) || ((fragP->fr_next->fr_address - fragP->fr_address) == fragP->fr_fix)); + + /* + * After md_convert_frag, we make the frag into a ".space 0". + * Md_convert_frag() should set up any fixSs and constants + * required. + */ + frag_wane(fragP); + break; + +#ifndef WORKING_DOT_WORD + case rs_broken_word: { + struct broken_word *lie; + + if (fragP->fr_subtype) { + fragP->fr_fix+=md_short_jump_size; + for (lie=(struct broken_word *)(fragP->fr_symbol);lie && lie->dispfrag == fragP;lie=lie->next_broken_word) + if (lie->added == 1) + fragP->fr_fix+=md_long_jump_size; + } + frag_wane(fragP); + } + break; +#endif + + default: + BAD_CASE( fragP->fr_type ); + break; + } /* switch (fr_type) */ + + know((fragP->fr_next == NULL) + || ((fragP->fr_next->fr_address - fragP->fr_address) + == (fragP->fr_fix + (fragP->fr_offset * fragP->fr_var)))); + } /* for each frag. */ + +#ifndef WORKING_DOT_WORD + { + struct broken_word *lie; + struct broken_word **prevP; + + prevP = &broken_words; + for (lie = broken_words; lie; lie = lie->next_broken_word) + if (!lie->added) { +#ifdef TC_NS32K + fix_new_ns32k(lie->frag, + lie->word_goes_here - lie->frag->fr_literal, + 2, + lie->add, + lie->sub, + lie->addnum, + 0, 0, 2, 0, 0); +#else /* TC_NS32K */ +#ifdef PIC + fix_new(lie->frag, lie->word_goes_here - lie->frag->fr_literal, + 2, lie->add, + lie->sub, lie->addnum, + 0, NO_RELOC, (symbolS *)0); +#else + fix_new(lie->frag, lie->word_goes_here - lie->frag->fr_literal, + 2, lie->add, + lie->sub, lie->addnum, + 0, NO_RELOC); +#endif +#endif /* TC_NS32K */ + /* md_number_to_chars(lie->word_goes_here, + S_GET_VALUE(lie->add) + + lie->addnum + - S_GET_VALUE(lie->sub), + 2); */ + *prevP = lie->next_broken_word; + } else + prevP = &(lie->next_broken_word); + + for (lie = broken_words; lie;) { + struct broken_word *untruth; + char *table_ptr; + long table_addr; + long from_addr, + to_addr; + int n, + m; + + fragP = lie->dispfrag; + + /* Find out how many broken_words go here */ + n=0; + for (untruth = lie; untruth && untruth->dispfrag == fragP; untruth = untruth->next_broken_word) + if (untruth->added == 1) + n++; + + table_ptr = lie->dispfrag->fr_opcode; + table_addr = lie->dispfrag->fr_address + (table_ptr - lie->dispfrag->fr_literal); + /* Create the jump around the long jumps */ + /* This is a short jump from table_ptr+0 to table_ptr+n*long_jump_size */ + from_addr = table_addr; + to_addr = table_addr + md_short_jump_size + n * md_long_jump_size; + md_create_short_jump(table_ptr, from_addr, to_addr, lie->dispfrag, lie->add); + table_ptr += md_short_jump_size; + table_addr += md_short_jump_size; + + for (m = 0; lie && lie->dispfrag == fragP; m++, lie = lie->next_broken_word) { + if (lie->added == 2) + continue; + /* Patch the jump table */ + /* This is the offset from ??? to table_ptr+0 */ + to_addr = table_addr + - S_GET_VALUE(lie->sub); + md_number_to_chars(lie->word_goes_here, to_addr, 2); + for (untruth = lie->next_broken_word; + untruth && untruth->dispfrag == fragP; + untruth = untruth->next_broken_word) { + if (untruth->use_jump == lie) + md_number_to_chars(untruth->word_goes_here, to_addr, 2); + } + + /* Install the long jump */ + /* this is a long jump from table_ptr+0 to the final target */ + from_addr = table_addr; + to_addr = S_GET_VALUE(lie->add) + lie->addnum; + md_create_long_jump(table_ptr, from_addr, to_addr, lie->dispfrag, lie->add); + table_ptr += md_long_jump_size; + table_addr += md_long_jump_size; + } + } + } +#endif /* not WORKING_DOT_WORD */ + +#ifndef OBJ_VMS + { /* not vms */ + /* + * Scan every FixS performing fixups. We had to wait until now to do + * this because md_convert_frag() may have made some fixSs. + */ + + H_SET_RELOCATION_SIZE(&headers, + md_reloc_size * fixup_segment(text_fix_root, SEG_TEXT), + md_reloc_size * fixup_segment(data_fix_root, SEG_DATA)); + + + obj_pre_write_hook(&headers); + + if ((had_warnings() && flagseen['Z']) + || had_errors() > 0) { + if (flagseen['Z']) { + as_warn("%d error%s, %d warning%s, generating bad object file.\n", + had_errors(), had_errors() == 1 ? "" : "s", + had_warnings(), had_warnings() == 1 ? "" : "s"); + } else { + as_fatal("%d error%s, %d warning%s, no object file generated.\n", + had_errors(), had_errors() == 1 ? "" : "s", + had_warnings(), had_warnings() == 1 ? "" : "s"); + } /* on want output */ + } /* on error condition */ + + object_file_size = H_GET_FILE_SIZE(&headers); + next_object_file_charP = the_object_file = xmalloc(object_file_size); + + output_file_create(out_file_name); + + obj_header_append(&next_object_file_charP, &headers); + + know((next_object_file_charP - the_object_file) == H_GET_HEADER_SIZE(&headers)); + + /* + * Emit code. + */ + for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) { + register long count; + register char *fill_literal; + register long fill_size; + + know(fragP->fr_type == rs_fill); + append(&next_object_file_charP, fragP->fr_literal, (unsigned long) fragP->fr_fix); + fill_literal = fragP->fr_literal + fragP->fr_fix; + fill_size = fragP->fr_var; + know(fragP->fr_offset >= 0); + + for (count = fragP->fr_offset; count; count--) { + append(&next_object_file_charP, fill_literal, (unsigned long) fill_size); + } /* for each */ + + } /* for each code frag. */ + + know((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE(&headers) + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers))); + + /* + * Emit relocations. + */ + obj_emit_relocations(&next_object_file_charP, text_fix_root, (relax_addressT)0); + know((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE(&headers) + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers) + H_GET_TEXT_RELOCATION_SIZE(&headers))); +#ifdef TC_I960 + /* Make addresses in data relocation directives relative to beginning of + * first data fragment, not end of last text fragment: alignment of the + * start of the data segment may place a gap between the segments. + */ + obj_emit_relocations(&next_object_file_charP, data_fix_root, data0_frchainP->frch_root->fr_address); +#else /* TC_I960 */ + obj_emit_relocations(&next_object_file_charP, data_fix_root, text_last_frag->fr_address); +#endif /* TC_I960 */ + + know((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE(&headers) + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers) + H_GET_TEXT_RELOCATION_SIZE(&headers) + H_GET_DATA_RELOCATION_SIZE(&headers))); + + /* + * Emit line number entries. + */ + OBJ_EMIT_LINENO(&next_object_file_charP, lineno_rootP, the_object_file); + know((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE(&headers) + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers) + H_GET_TEXT_RELOCATION_SIZE(&headers) + H_GET_DATA_RELOCATION_SIZE(&headers) + H_GET_LINENO_SIZE(&headers))); + + /* + * Emit symbols. + */ + obj_emit_symbols(&next_object_file_charP, symbol_rootP); + know((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE(&headers) + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers) + H_GET_TEXT_RELOCATION_SIZE(&headers) + H_GET_DATA_RELOCATION_SIZE(&headers) + H_GET_LINENO_SIZE(&headers) + H_GET_SYMBOL_TABLE_SIZE(&headers))); + + /* + * Emit strings. + */ + + if (string_byte_count > 0) { + obj_emit_strings(&next_object_file_charP); + } /* only if we have a string table */ + + /* know((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE(&headers) + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers) + H_GET_TEXT_RELOCATION_SIZE(&headers) + H_GET_DATA_RELOCATION_SIZE(&headers) + H_GET_LINENO_SIZE(&headers) + H_GET_SYMBOL_TABLE_SIZE(&headers) + H_GET_STRING_SIZE(&headers))); + */ + /* know(next_object_file_charP == the_object_file + object_file_size);*/ + +#ifdef BFD_HEADERS + bfd_seek(stdoutput, 0, 0); + bfd_write(the_object_file, 1, object_file_size, stdoutput); +#else + + /* Write the data to the file */ + output_file_append(the_object_file, object_file_size, out_file_name); +#endif + + output_file_close(out_file_name); + } /* non vms output */ +#else /* OBJ_VMS */ + /* + * Now do the VMS-dependent part of writing the object file + */ + VMS_write_object_file(H_GET_TEXT_SIZE(&headers), H_GET_DATA_SIZE(&headers), + text_frag_root, data_frag_root); +#endif /* OBJ_VMS */ +} /* write_object_file() */ +#else +#endif + +/* + * 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. + */ + + + +void relax_segment(segment_frag_root, segment) +struct frag * segment_frag_root; +segT segment; /* SEG_DATA or SEG_TEXT */ +{ + register struct frag * fragP; + register relax_addressT address; + /* register relax_addressT old_address; JF unused */ + /* register relax_addressT new_address; JF unused */ +#ifndef MANY_SEGMENTS + know(segment == SEG_DATA || segment == SEG_TEXT); +#endif + /* In case md_estimate_size_before_relax() wants to make fixSs. */ + subseg_change(segment, 0); + + /* + * For each frag in segment: count and store (a 1st guess of) fr_address. + */ + address = 0; + for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) { + fragP->fr_address = address; + address += fragP->fr_fix; + + switch (fragP->fr_type) { + case rs_fill: + address += fragP->fr_offset * fragP->fr_var ; + break; + + case rs_align: + address += relax_align(address, fragP->fr_offset); + break; + + case rs_org: + /* + * Assume .org is nugatory. It will grow with 1st relax. + */ + break; + + case rs_machine_dependent: + address += md_estimate_size_before_relax(fragP, segment); + 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 stretch; /* May be any size, 0 or negative. */ + /* Cumulative number of addresses we have */ + /* relaxed this pass. */ + /* We may have relaxed more than one address. */ + register long stretched; /* Have we stretched on this pass? */ + /* This is 'cuz stretch may be zero, when, + in fact some piece of code grew, and + another shrank. If a branch instruction + doesn't fit anymore, we could be scrod */ + + do { + stretch = stretched = 0; + for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) { + register long growth = 0; + register unsigned long was_address; + register long offset; + register symbolS *symbolP; + register long target; + register long after; + register long aim; + + was_address = fragP->fr_address; + address = fragP->fr_address += stretch; + symbolP = fragP->fr_symbol; + offset = fragP->fr_offset; + + switch (fragP->fr_type) { + case rs_fill: /* .fill never relaxes. */ + growth = 0; + break; + +#ifndef WORKING_DOT_WORD + /* JF: This is RMS's idea. I do *NOT* want to be blamed + for it I do not want to write it. I do not want to have + anything to do with it. This is not the proper way to + implement this misfeature. */ + case rs_broken_word: { + struct broken_word *lie; + struct broken_word *untruth; + + /* Yes this is ugly (storing the broken_word pointer + in the symbol slot). Still, this whole chunk of + code is ugly, and I don't feel like doing anything + about it. Think of it as stubbornness in action */ + growth=0; + for (lie=(struct broken_word *)(fragP->fr_symbol); + lie && lie->dispfrag == fragP; + lie=lie->next_broken_word) { + + if (lie->added) + continue; + + offset = lie->add->sy_frag->fr_address+ S_GET_VALUE(lie->add) + lie->addnum - + (lie->sub->sy_frag->fr_address+ S_GET_VALUE(lie->sub)); + if (offset <= -32768 || offset >= 32767) { + if (flagseen['K']) + as_warn(".word %s-%s+%ld didn't fit", + S_GET_NAME(lie->add), + S_GET_NAME(lie->sub), + lie->addnum); + lie->added=1; + if (fragP->fr_subtype == 0) { + fragP->fr_subtype++; + growth+=md_short_jump_size; + } + for (untruth=lie->next_broken_word;untruth && untruth->dispfrag == lie->dispfrag;untruth=untruth->next_broken_word) + if ((untruth->add->sy_frag == lie->add->sy_frag) + && S_GET_VALUE(untruth->add) == S_GET_VALUE(lie->add)) { + untruth->added=2; + untruth->use_jump=lie; + } + growth += md_long_jump_size; + } + } + + break; + } /* case rs_broken_word */ +#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) { +#ifdef MANY_SEGMENTS +#else + know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) || (S_GET_SEGMENT(symbolP) == SEG_DATA) || (S_GET_SEGMENT(symbolP) == SEG_TEXT)); + know(symbolP->sy_frag); + know(!(S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) || (symbolP->sy_frag == &zero_address_frag)); +#endif + target += S_GET_VALUE(symbolP) + + symbolP->sy_frag->fr_address; + } /* if we have a symbol */ + + know(fragP->fr_next); + after = fragP->fr_next->fr_address; + growth = ((target - after ) > 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) { +#ifndef MANY_SEGMENTS + know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) || (S_GET_SEGMENT(symbolP) == SEG_DATA) || (S_GET_SEGMENT(symbolP) == SEG_TEXT)); +#endif + know(symbolP->sy_frag); + know(!(S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) || symbolP->sy_frag == &zero_address_frag ); + target += + S_GET_VALUE(symbolP) + + symbolP->sy_frag->fr_address; + + /* If frag has yet to be reached on this pass, + assume it will move by STRETCH just as we did. + If this is not so, it will be because some frag + between grows, and that will force another pass. */ + + /* JF was just address */ + /* JF also added is_dnrange hack */ + /* There's gotta be a better/faster/etc way + to do this... */ + /* gnu@cygnus.com: I changed this from > to >= + because I ran into a zero-length frag (fr_fix=0) + which was created when the obstack needed a new + chunk JUST AFTER the opcode of a branch. Since + fr_fix is zero, fr_address of this frag is the same + as fr_address of the next frag. This + zero-length frag was variable and jumped to .+2 + (in the next frag), but since the > comparison + below failed (the two were =, not >), "stretch" + was not added to the target. Stretch was 178, so + the offset appeared to be .-176 instead, which did + not fit into a byte branch, so the assembler + relaxed the branch to a word. This didn't compare + with what happened when the same source file was + assembled on other machines, which is how I found it. + You might want to think about what other places have + trouble with zero length frags... */ + + if (symbolP->sy_frag->fr_address >= was_address + && is_dnrange(fragP,symbolP->sy_frag)) { + target += stretch; + } /* */ + + } /* if there's a symbol attached */ + + aim = target - address - fragP->fr_fix; + /* The displacement is affected by the instruction size + * for the 32k architecture. I think we ought to be able + * to add fragP->fr_pcrel_adjust in all cases (it should be + * zero if not used), but just in case it breaks something + * else we'll put this inside #ifdef NS32K ... #endif + */ +#ifdef TC_NS32K + aim += fragP->fr_pcrel_adjust; +#endif /* TC_NS32K */ + + if (aim < 0) { + /* Look backwards. */ + for (next_state = this_type->rlx_more; next_state; ) { + if (aim >= this_type->rlx_backward) { + next_state = 0; + } else { /* Grow to next state. */ + this_type = md_relax_table + (this_state = next_state); + next_state = this_type->rlx_more; + } + } + } else { +#ifdef DONTDEF + /* JF these next few lines of code are for the mc68020 which can't handle short + offsets of zero in branch instructions. What a kludge! */ + if (aim == 0 && this_state == (1<<2+0)) { /* FOO hard encoded from m.c */ + aim=this_type->rlx_forward+1; /* Force relaxation into word mode */ + } +#endif +#ifdef M68K_AIM_KLUDGE + M68K_AIM_KLUDGE(aim, this_state, this_type); +#endif + /* JF end of 68020 code */ + /* Look forwards. */ + for (next_state = this_type->rlx_more; next_state; ) { + if (aim <= this_type->rlx_forward) { + next_state = 0; + } else { /* Grow to next state. */ + this_type = md_relax_table + (this_state = next_state); + next_state = this_type->rlx_more; + } + } + } + + if ((growth = this_type->rlx_length - start_type->rlx_length) != 0) + fragP->fr_subtype = this_state; + + break; + } /* case rs_machine_dependent */ + + default: + BAD_CASE( fragP->fr_type ); + break; + } + if (growth) { + stretch += growth; + stretched++; + } + } /* For each frag in the segment. */ + } while (stretched); /* Until nothing further to relax. */ + } /* do_relax */ + + /* + * We now have valid fr_address'es for each frag. + */ + + /* + * All fr_address's are correct, relative to their own segment. + * We have made all the fixS we will ever make. + */ +} /* relax_segment() */ + +/* + * Relax_align. Advance location counter to next address that has 'alignment' + * lowest order bits all 0s. + */ + +/* How many addresses does the .align take? */ +static relax_addressT relax_align(address, alignment) +register relax_addressT address; /* Address now. */ +register long alignment; /* Alignment (binary). */ +{ + relax_addressT mask; + relax_addressT new_address; + + mask = ~ ( (~0) << alignment ); + new_address = (address + mask) & (~ mask); + return (new_address - address); +} /* relax_align() */ + +/* fixup_segment() + + Go through all the fixS's in a segment and see which ones can be + handled now. (These consist of fixS where we have since discovered + the value of a symbol, or the address of the frag involved.) + For each one, call md_apply_fix to put the fix into the frag data. + + Result is a count of how many relocation structs will be needed to + handle the remaining fixS's that we couldn't completely handle here. + These will be output later by emit_relocations(). */ + +static long fixup_segment(fixP, this_segment_type) +register fixS *fixP; +segT this_segment_type; /* N_TYPE bits for segment. */ +{ + register long seg_reloc_count; + register symbolS *add_symbolP; + register symbolS *sub_symbolP; + register long add_number; + register int size; + register char *place; + register long where; + register char pcrel; + register fragS *fragP; + register segT add_symbol_segment = SEG_ABSOLUTE; + + /* FIXME: remove this line */ /* fixS *orig = fixP; */ + seg_reloc_count = 0; + + for ( ; fixP; fixP = fixP->fx_next) { + fragP = fixP->fx_frag; + know(fragP); + where = fixP->fx_where; + place = fragP->fr_literal + where; + size = fixP->fx_size; + add_symbolP = fixP->fx_addsy; +#ifdef TC_I960 + if (fixP->fx_callj && TC_S_IS_CALLNAME(add_symbolP)) { + /* Relocation should be done via the + associated 'bal' entry point + symbol. */ + + if (!TC_S_IS_BALNAME(tc_get_bal_of_call(add_symbolP))) { + as_bad("No 'bal' entry point for leafproc %s", + S_GET_NAME(add_symbolP)); + continue; + } + fixP->fx_addsy = add_symbolP = tc_get_bal_of_call(add_symbolP); + } /* callj relocation */ +#endif + sub_symbolP = fixP->fx_subsy; + add_number = fixP->fx_offset; + pcrel = fixP->fx_pcrel; + + if (add_symbolP) { + add_symbol_segment = S_GET_SEGMENT(add_symbolP); + } /* if there is an addend */ + + if (sub_symbolP) { + if (!add_symbolP) { + /* Its just -sym */ + if (S_GET_SEGMENT(sub_symbolP) != SEG_ABSOLUTE) { + as_bad("Negative of non-absolute symbol %s", S_GET_NAME(sub_symbolP)); + } /* not absolute */ + + add_number -= S_GET_VALUE(sub_symbolP); + + /* if sub_symbol is in the same segment that add_symbol + and add_symbol is either in DATA, TEXT, BSS or ABSOLUTE */ + } else if ((S_GET_SEGMENT(sub_symbolP) == add_symbol_segment) + && (SEG_NORMAL(add_symbol_segment) + || (add_symbol_segment == SEG_ABSOLUTE))) { + /* Difference of 2 symbols from same segment. */ + /* Can't make difference of 2 undefineds: 'value' means */ + /* something different for N_UNDF. */ +#ifdef TC_I960 + /* Makes no sense to use the difference of 2 arbitrary symbols + * as the target of a call instruction. + */ + if (fixP->fx_callj) { + as_bad("callj to difference of 2 symbols"); + } +#endif /* TC_I960 */ + add_number += S_GET_VALUE(add_symbolP) - + S_GET_VALUE(sub_symbolP); + + add_symbolP = NULL; + fixP->fx_addsy = NULL; + } else { + /* Different segments in subtraction. */ + know(!(S_IS_EXTERNAL(sub_symbolP) && (S_GET_SEGMENT(sub_symbolP) == SEG_ABSOLUTE))); + + if ((S_GET_SEGMENT(sub_symbolP) == SEG_ABSOLUTE)) { + add_number -= S_GET_VALUE(sub_symbolP); + } else { + as_bad("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %d.", + segment_name(S_GET_SEGMENT(sub_symbolP)), + S_GET_NAME(sub_symbolP), fragP->fr_address + where); + } /* if absolute */ + } + } /* if sub_symbolP */ + +#ifdef PIC + /* + * Bring _GLOBAL_OFFSET_TABLE_ forward, now we've had the + * chance to collapse any accompanying symbols into a number. + * This is the sequel of the hack in expr.c to parse operands + * of the form `_GLOBAL_OFFSET_TABLE_+(L1-L2)'. Note that + * _GLOBAL_OFFSET_TABLE_ can only be an "add symbol". + */ + if (add_symbolP == NULL && fixP->fx_gotsy != NULL) { + add_symbolP = fixP->fx_addsy = fixP->fx_gotsy; + add_symbol_segment = S_GET_SEGMENT(add_symbolP); + } +#endif + + if (add_symbolP) { + if (add_symbol_segment == this_segment_type && pcrel) { + /* + * This fixup was made when the symbol's segment was + * SEG_UNKNOWN, but it is now in the local segment. + * So we know how to do the address without relocation. + */ +#ifdef TC_I960 + /* reloc_callj() may replace a 'call' with a 'calls' or a 'bal', + * in which cases it modifies *fixP as appropriate. In the case + * of a 'calls', no further work is required, and *fixP has been + * set up to make the rest of the code below a no-op. + */ + reloc_callj(fixP); +#endif /* TC_I960 */ + + add_number += S_GET_VALUE(add_symbolP); + add_number -= md_pcrel_from(fixP); + pcrel = 0; /* Lie. Don't want further pcrel processing. */ + fixP->fx_addsy = NULL; /* No relocations please. */ + } else { + switch (add_symbol_segment) { + case SEG_ABSOLUTE: +#ifdef TC_I960 + reloc_callj(fixP); /* See comment about reloc_callj() above*/ +#endif /* TC_I960 */ + add_number += S_GET_VALUE(add_symbolP); + fixP->fx_addsy = NULL; + add_symbolP = NULL; + break; + default: + seg_reloc_count ++; +#ifdef PIC + /* + * Do not fixup refs to global data + * even if defined here. + */ + if (!flagseen['k'] || + (fixP->fx_r_type != RELOC_GLOB_DAT && +#ifdef TC_I386 +/* XXX - This must be rationalized */ + fixP->fx_r_type != RELOC_GOT && + fixP->fx_r_type != RELOC_GOTOFF && +#endif + (fixP->fx_r_type != RELOC_32 || + !S_IS_EXTERNAL(add_symbolP)))) +#endif + add_number += S_GET_VALUE(add_symbolP); + break; + + case SEG_UNKNOWN: +#ifdef TC_I960 + if ((int)fixP->fx_bit_fixP == 13) { + /* This is a COBR instruction. They have only a + * 13-bit displacement and are only to be used + * for local branches: flag as error, don't generate + * relocation. + */ + as_bad("can't use COBR format with external label"); + fixP->fx_addsy = NULL; /* No relocations please. */ + continue; + } /* COBR */ +#endif /* TC_I960 */ + +#ifdef OBJ_COFF +#ifdef TE_I386AIX + if (S_IS_COMMON(add_symbolP)) + add_number += S_GET_VALUE(add_symbolP); +#endif /* TE_I386AIX */ +#endif /* OBJ_COFF */ + ++seg_reloc_count; + + break; + + + } /* switch on symbol seg */ + } /* if not in local seg */ + } /* if there was a + symbol */ + + if (pcrel) { + add_number -= md_pcrel_from(fixP); + if (add_symbolP == 0) { + fixP->fx_addsy = & abs_symbol; + ++seg_reloc_count; + } /* if there's an add_symbol */ + } /* if pcrel */ + + if (!fixP->fx_bit_fixP) { + if ((size == 1 && + (add_number& ~0xFF) && (add_number & ~0xFF != (-1 & ~0xFF))) || + (size == 2 && + (add_number& ~0xFFFF) && (add_number & ~0xFFFF != (-1 & ~0xFFFF)))) { + as_bad("Value of %d too large for field of %d bytes at 0x%x", + add_number, size, fragP->fr_address + where); + } /* generic error checking */ + } /* not a bit fix */ + + md_apply_fix(fixP, add_number); + } /* For each fixS in this segment. */ + +#ifdef OBJ_COFF +#ifdef TC_I960 + { + fixS *topP = fixP; + + /* two relocs per callj under coff. */ + for (fixP = topP; fixP; fixP = fixP->fx_next) { + if (fixP->fx_callj && fixP->fx_addsy != 0) { + ++seg_reloc_count; + } /* if callj and not already fixed. */ + } /* for each fix */ + } +#endif /* TC_I960 */ + +#endif /* OBJ_COFF */ + return(seg_reloc_count); +} /* fixup_segment() */ + + +static int is_dnrange(f1,f2) +struct frag *f1; +struct frag *f2; +{ + while (f1) { + if (f1->fr_next == f2) + return 1; + f1=f1->fr_next; + } + return 0; +} /* is_dnrange() */ + +/* Append a string onto another string, bumping the pointer along. */ +void + append (charPP, fromP, length) +char **charPP; +char *fromP; +unsigned long length; +{ + if (length) { /* Don't trust memcpy() of 0 chars. */ + memcpy(*charPP, fromP, (int) length); + *charPP += length; + } +} + +int section_alignment[SEG_MAXIMUM_ORDINAL]; + +/* + * This routine records the largest alignment seen for each segment. + * If the beginning of the segment is aligned on the worst-case + * boundary, all of the other alignments within it will work. At + * least one object format really uses this info. + */ +void record_alignment(seg, align) +segT seg; /* Segment to which alignment pertains */ +int align; /* Alignment, as a power of 2 + * (e.g., 1 => 2-byte boundary, 2 => 4-byte boundary, etc.) + */ +{ + + if ( align > section_alignment[(int) seg] ){ + section_alignment[(int) seg] = align; + } /* if highest yet */ + + return; +} /* record_alignment() */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of write.c */ diff --git a/gnu/usr.bin/as/write.h b/gnu/usr.bin/as/write.h new file mode 100644 index 000000000000..01e727241802 --- /dev/null +++ b/gnu/usr.bin/as/write.h @@ -0,0 +1,120 @@ +/* write.h + + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * write.h,v 1.3 1993/10/02 20:58:02 pk Exp + */ + + +#ifndef TC_I960 +#ifdef hpux +#define EXEC_MACHINE_TYPE HP9000S200_ID +#endif +#endif /* TC_I960 */ + +#ifndef LOCAL_LABEL +#ifdef DOT_LABEL_PREFIX +#define LOCAL_LABEL(name) (name[0] == '.' \ + && (name[1] == 'L' || name[1] == '.')) +#else /* not defined DOT_LABEL_PREFIX */ +#define LOCAL_LABEL(name) (name[0] == 'L') +#endif /* not defined DOT_LABEL_PREFIX */ +#endif /* LOCAL_LABEL */ + +#define S_LOCAL_NAME(s) (LOCAL_LABEL(S_GET_NAME(s))) + +#include "bit_fix.h" + +/* + * FixSs may be built up in any order. + */ + +struct fix { + fragS *fx_frag; /* Which frag? */ + long fx_where; /* Where is the 1st byte to fix up? */ + symbolS *fx_addsy; /* NULL or Symbol whose value we add in. */ + symbolS *fx_subsy; /* NULL or Symbol whose value we subtract. */ +#ifdef PIC + symbolS *fx_gotsy; /* NULL or __GLOBAL_OFFSET_TABLE_ . */ +#endif + long fx_offset; /* Absolute number we add in. */ + struct fix *fx_next; /* NULL or -> next fixS. */ + short int fx_size; /* How many bytes are involved? */ + char fx_pcrel; /* TRUE: pc-relative. */ + char fx_pcrel_adjust; /* pc-relative offset adjust */ + char fx_im_disp; /* TRUE: value is a displacement */ + bit_fixS *fx_bit_fixP; /* IF NULL no bitfix's to do */ + char fx_bsr; /* sequent-hack */ + enum reloc_type fx_r_type; /* Sparc hacks */ + char fx_callj; /* TRUE if target is a 'callj' (used by i960) */ + long fx_addnumber; +}; + +typedef struct fix fixS; + +COMMON char *next_object_file_charP; + +#ifndef MANY_SEGMENTS +COMMON fixS *text_fix_root, *text_fix_tail; /* Chains fixSs. */ +COMMON fixS *data_fix_root, *data_fix_tail; /* Chains fixSs. */ +COMMON fixS *bss_fix_root, *bss_fix_tail; /* Chains fixSs. */ +#endif +COMMON fixS **seg_fix_rootP, **seg_fix_tailP; /* -> one of above. */ +extern long string_byte_count; +extern int section_alignment[]; + +#if __STDC__ == 1 + +bit_fixS *bit_fix_new(int size, int offset, long base_type, long base_adj, long min, long max, long add); +void append(char **charPP, char *fromP, unsigned long length); +void record_alignment(segT seg, int align); +void write_object_file(void); + +fixS *fix_new(fragS *frag, + int where, + int size, + symbolS *add_symbol, + symbolS *sub_symbol, + long offset, + int pcrel, + enum reloc_type r_type +#ifdef PIC + ,symbolS *got_symbol); +#else + ); +#endif + +#else /* not __STDC__ */ + +bit_fixS *bit_fix_new(); +fixS *fix_new(); +void append(); +void record_alignment(); +void write_object_file(); + +#endif /* not __STDC__ */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of write.h */ diff --git a/gnu/usr.bin/as/xmalloc.c b/gnu/usr.bin/as/xmalloc.c new file mode 100644 index 000000000000..4c8181145edc --- /dev/null +++ b/gnu/usr.bin/as/xmalloc.c @@ -0,0 +1,75 @@ +/* xmalloc.c - get memory or bust + + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 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() + + */ + +#ifndef lint +static char rcsid[] = "$Id: xmalloc.c,v 1.2 1993/11/03 00:52:32 paul Exp $"; +#endif + +#include <stdio.h> + +#if __STDC__ == 1 +#include <stdlib.h> +#else +#ifdef USG +#include <malloc.h> +#else +char * malloc(); +#endif /* USG */ +#endif /* not __STDC__ */ + +#define error as_fatal + +char * xmalloc(n) +long n; +{ + char * retval; + void error(); + + if ((retval = malloc ((unsigned)n)) == NULL) + { + error("virtual memory exceeded"); + } + return (retval); +} + +/* end of xmalloc.c */ diff --git a/gnu/usr.bin/as/xrealloc.c b/gnu/usr.bin/as/xrealloc.c new file mode 100644 index 000000000000..ca0482a1cb32 --- /dev/null +++ b/gnu/usr.bin/as/xrealloc.c @@ -0,0 +1,74 @@ +/* xrealloc.c - new memory or bust + + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 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 () + */ + +#ifndef lint +static char rcsid[] = "$Id: xrealloc.c,v 1.2 1993/11/03 00:52:34 paul Exp $"; +#endif + + +#if __STDC__ == 1 +#include <stdlib.h> +#else +#ifdef USG +#include <malloc.h> +#else +char *realloc (); +#endif /* USG */ +#endif /* not __STDC__ */ + +#define error as_fatal + +char * + xrealloc (ptr, n) +register char *ptr; +long n; +{ + void error(); + + if ((ptr = realloc (ptr, (unsigned)n)) == 0) + error ("virtual memory exceeded"); + return (ptr); +} + +/* end of xrealloc.c */ |
