diff options
author | paul <paul@FreeBSD.org> | 1993-11-03 00:56:24 +0000 |
---|---|---|
committer | paul <paul@FreeBSD.org> | 1993-11-03 00:56:24 +0000 |
commit | cebee5f5697360ad333f15d82bb2adc29ce8fab5 (patch) | |
tree | c6947a527e76f67f3d2eb22488df6f6ca9734b47 /gnu/usr.bin/as | |
parent | 6d8373f3a9c123c2c2a312938e462e8a95d834b9 (diff) | |
download | FreeBSD-src-cebee5f5697360ad333f15d82bb2adc29ce8fab5.zip FreeBSD-src-cebee5f5697360ad333f15d82bb2adc29ce8fab5.tar.gz |
Brought over NetBSD's gas ready for pk's shared libs.
Diffstat (limited to 'gnu/usr.bin/as')
197 files changed, 71914 insertions, 8829 deletions
diff --git a/gnu/usr.bin/as/CONTRIBUTORS b/gnu/usr.bin/as/CONTRIBUTORS new file mode 100644 index 0000000..cfcc7bc --- /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 index 9a17037..a43ea21 100644 --- a/gnu/usr.bin/as/COPYING +++ b/gnu/usr.bin/as/COPYING @@ -1,38 +1,40 @@ - GNU GENERAL PUBLIC LICENSE - Version 1, February 1989 + Version 2, June 1991 - Copyright (C) 1989 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + 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 license agreements of most software companies try to keep users -at the mercy of those companies. By contrast, our General Public + 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. The -General Public License applies to the Free Software Foundation's -software and to any other program whose authors commit to using it. -You can use it for your programs, too. +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. Specifically, the General Public License is designed to make -sure that you have the freedom to give away or sell copies of free -software, that you receive source code or can get it if you want it, -that you can change the software or use pieces of it in new free -programs; and that you know you can do these things. +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 a such a program, whether + 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 tell them their rights. +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, @@ -45,120 +47,207 @@ 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 Agreement applies to any program or other work which -contains a notice placed by the copyright holder saying it may be -distributed under the terms of this General Public License. The -"Program", below, refers to any such program or work, and a "work based -on the Program" means either the Program or any work containing the -Program or a portion of it, either verbatim or with modifications. Each -licensee is addressed as "you". - - 1. You may copy and distribute verbatim copies of the Program's source -code as you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice and -disclaimer of warranty; keep intact all the notices that refer to this -General Public License and to the absence of any warranty; and give any -other recipients of the Program a copy of this General Public License -along with the Program. You may charge a fee for the physical act of -transferring a copy. - - 2. You may modify your copy or copies of the Program or any portion of -it, and copy and distribute such modifications under the terms of Paragraph -1 above, provided that you also do the following: - - a) cause the modified files to carry prominent notices stating that - you changed the files and the date of any change; and - - b) cause the whole of any work that you distribute or publish, that - in whole or in part contains the Program or any part thereof, either - with or without modifications, to be licensed at no charge to all - third parties under the terms of this General Public License (except - that you may choose to grant warranty protection to some or all - third parties, at your option). - - c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive use - in the simplest and most usual way, to print or display an - announcement including an appropriate copyright notice and a notice - that there is no warranty (or else, saying that you provide a - warranty) and that users may redistribute the program under these - conditions, and telling the user how to view a copy of this General - Public License. - - d) You may charge a fee for the physical act of transferring a - copy, and you may at your option offer warranty protection in - exchange for a fee. - -Mere aggregation of another independent work with the Program (or its -derivative) on a volume of a storage or distribution medium does not bring -the other work under the scope of these terms. + 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.) - 3. You may copy and distribute the Program (or a portion or derivative of -it, under Paragraph 2) in object code or executable form under the terms of -Paragraphs 1 and 2 above provided that you also do one of the following: - - a) accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of - Paragraphs 1 and 2 above; or, - - b) accompany it with a written offer, valid for at least three - years, to give any third party free (except for a nominal charge - for the cost of distribution) a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of - Paragraphs 1 and 2 above; or, - - c) accompany it with the information you received as to where the - corresponding source code may be obtained. (This alternative is +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 alone.) - -Source code for a work means the preferred form of the work for making -modifications to it. For an executable file, complete source code means -all the source code for all modules it contains; but, as a special -exception, it need not include source code for modules which are standard -libraries that accompany the operating system on which the executable -file runs, or for standard header files or definitions files that -accompany that operating system. - - 4. You may not copy, modify, sublicense, distribute or transfer the -Program except as expressly provided under this General Public License. -Any attempt otherwise to copy, modify, sublicense, distribute or transfer -the Program is void, and will automatically terminate your rights to use -the Program under this License. However, parties who have received -copies, or rights to use copies, from you under this General Public -License will not have their licenses terminated so long as such parties -remain in full compliance. - - 5. By copying, distributing or modifying the Program (or any work based -on the Program) you indicate your acceptance of this license to do so, -and all its terms and conditions. + 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. +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. - 7. The Free Software Foundation may publish revised and/or new versions + 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 the license which applies to it and "any +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 -the license, you may choose any version ever published by the Free Software +this License, you may choose any version ever published by the Free Software Foundation. - 8. If you wish to incorporate parts of the Program into other free + 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 @@ -168,7 +257,7 @@ of promoting the sharing and reuse of software generally. NO WARRANTY - 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS 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 @@ -178,7 +267,7 @@ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + 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 @@ -193,22 +282,21 @@ POSSIBILITY OF SUCH DAMAGES. Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest -possible use to humanity, the best way to achieve this is to make it -free software which everyone can redistribute and change under these -terms. +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. + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) 19yy <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. + 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 @@ -224,26 +312,28 @@ Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19xx name of author + Gnomovision 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. +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here a sample; alter the names: +necessary. Here is a sample; alter the names: - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (a program to direct compilers to make passes - at assemblers) written by James Hacker. + 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 -That's all there is to it! +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 index 3e0e64f..db77234 100644 --- a/gnu/usr.bin/as/ChangeLog +++ b/gnu/usr.bin/as/ChangeLog @@ -1,917 +1,429 @@ -Fri Jan 4 12:48:22 EST 1991 Jay Fenlason (hack@ai.mit.edu) +Sun Mar 1 17:02:06 1992 K. Richard Pixley (rich@cygnus.com) - * messages.c Moved as_perror from input-scrub.c Modified the - error messages to look better. + * README: updated to 1.92.3, included mail announcement. - * output-file.c Don't call as_fatal, just call exit() +Sat Feb 29 00:53:16 1992 K. Richard Pixley (rich@cygnus.com) - expr.c Slightly improve checking for foo-foo case in - clean_up_expression(). Detect foo: bar: ... foo-bar... + * tc-sparc.c (md_apply_fix): relocation overflow checks. -Tue Dec 4 16:29:20 EST 1990 Jay Fenlason (hack@ai.mit.edu) + * atof-generic.c (atof_generic): recognize 99e999 as infinity for + older, broken, compilers. - * m68k.c Fixed an obscure bug involving AOFF mode with a - large constant displacement (Was forgetting to output the - extension word.) + * version.c: bump to 1.92.3, drop "Cygnus". - make-gas.com Added a three line patch from Eric Youngdale that - makes it possible to submit make-gas.com to a batch queue. + * input-scrub.c (as_where): use myname (which comes from argv[0]) + as part of all error messages. -Wed Nov 21 15:07:51 EST 1990 Jay Fenlason (hack@ai.mit.edu) + * 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 - * vms.c (VMS_TBT_Routine_END) Add a four line patch from - Eric Youngdale. + * Makefile.in, obj-aout.h, obj-coff.h: reflect file renaming. -Tue Nov 13 14:02:15 EST 1990 Jay Fenlason (hack@ai.mti.edu) + * output-file.c (output_file_create): add "b" to the fopen to + humor mess-dos. - * vms-dbg.c (VMS_DBG_record()) Another one character patch from - Eric Youngdale. + * configure.in: tahoe needs atof-tahoe. -Mon Oct 29 15:49:21 EST 1990 Jay Fenlason (hack@ai.mit.edu) + * 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 Replace some as_warn calls with as_bad. + * 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". -Fri Oct 26 15:21:15 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * config/m88k.[hc]: freshen copyrights, version 2 gpl, update to + current gas. - * i386.c, i860.c, ns32k.c Add const changes. + * config/m88k-opcode.h moved to opcode/m88k.h -Mon Oct 22 14:04:26 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * read.c: NO_DOT_PSEUDOS from hacks unfinished work. - * sparc.c Add const changes. + * opcode/m68k.h: Sun's JFcc aliases appear to be variable length. + Make them so. - * make-gas.com define const= for VMS, since many older versions of - GCC don't work correctly with const under VMS. + * opcode/a29k.h: remove rcsid. -Thu Oct 18 12:44:11 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * config/te-sun3.h: remove semicolon typo. - * i860.c i860-opcode.h Added patches from rgb@mcc.com + * config/obj-vms.c: another patch from eric youngdale. - * read.c, symbols.c, vms.c, + new_file vms-dbg-module.c - Added Eric Youngdale's <YOUNGDALE@v6550c.nrl.navy.mil> VMS debugging - patches, so debugging GCC output now works. + * write.c: white space only. - * hash.c (hash_grow) Remember to blank out the wall entry in the new - hash table. This is important on systems where malloc() returns - non-zero storage. . . + * config/tc-i960.c: change from intel for header flags. -Tue Oct 16 10:11:35 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * config/te-sequent.h, config/obj-aout.h: first cut at building + sequent headers. - * output-file.c (output_file_create) if output filename is given as - '-', write to stdout. + * config/tc-ns32k.c: patches from Jyrki Kuoppala <jkp@cs.hut.fi>. - * m68k.c Finally get the PCREL code to work right. Add relaxation of - PCREL stuff This small fix from Ken Woodland - (kenny%datacube.uucp@uunet.uu.net). + * struct-symbol.h: removed redundant decl of N_TYPE_seg. - * m68k.c Added some const declarations to constants. (md_relax_table, - md_pseudo_table, etc. . .) + * config/tc-sparc.c (sparc_ip), opcode/sparc.h: changes from chris + torek to correct a problem with "neg". some white space. -Thu Oct 11 11:15:10 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * 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. - * Makefile, read.c, write.c Include the i860 port. - (New files i860.c i860-opcode.h i860.h) + * config/tc-sparc.c: .empty pseudo-op from + gordoni@cs.adelaide.edu.au. - * m68k.c Fix some addressing modes, (AOFF, AINDEX, etc) to work in - PC relative mode. + * opcode/sparc.h: some new aliases from chris torek. - * (all over) Raeburn's const hacking. This reduces the data-space size by - declaring many tables, etc, as 'const'. + * opcode/i386.h: some new aliases and opcodes. also patches from + Steve Bleazard <steve@robobar.co.uk>. -Thu Sep 27 13:43:49 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * config/te-hpux.h: new file. - * m68k.c (get_num) Fix so that 1:w is treated properly. + * configure.in: when targetting hpux, use te-hpux.h. - * Makefile Replace references to a.out.h with a.out.gnu.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. -Tue Sep 25 15:50:36 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * config/tc-i860.c: gcc -Wall cleanup. - * sparc.c (md_number_to_imm) Fix so that RELOC_32 locations contain - zero, so that it will work with some sparc loaders which don't assume - that the locations in question do. A xix line patch from Michael Bloom - (usc!srhqla!quad1!psivax!ttidca!mb@zaphod.mps.ohio-state.edu) +Fri Feb 28 00:30:36 1992 K. Richard Pixley (rich@rtl.cygnus.com) -Mon Sep 24 11:43:15 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * configure.in: if target is sun3, use te-sun3.h. - * as.c #include <sys/types.h> if _POSIX_SOURCE defined. This because - <signal.h> uses pid_t that's defined in it. + * config/tc-m68k.h, config/te-sun3.h: moved #define of + default_magic_number_for_object_file from former to latter. - * m68k.c reverse the sense of -l option, and allow :w and :l to - override the default size of AOFF indexes. + * config/te-sun3.h: removed sun_asm_syntax and te_sun3, they + aren't used. - Also, allow -l to shorten branches to unknown labels from LONG to WORD. + * 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= " -Thu Sep 13 17:05:09 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * read.c, write.c, config/tc-i386.c: white space and comments + only. - * vax.c (md_parse_option) Don't print a warning msg if given -J + * config/obj-vms.c: convert PUT_LONG and PUT_SHORT to squirt byte + swapped numbers. -Wed Sep 5 14:26:14 EDT 1990 Jay Fenlason + * as.c, flonum-const.c, hex-value.c, input-file.c, version.c, + config/obj-aout.h, config/obj-vms.c: VMS -> HO_VMS. - * expr.c (operand) Don't get garbaged high-order bits when given a - lot of leading zeroes. + * config/ho-vms.h: added HO_VMS. -Tue Sep 4 11:40:21 EDT 1990 Jay Fenlason +Thu Feb 27 18:25:11 1992 K. Richard Pixley (rich@rtl.cygnus.com) - * read.c (pseudo_set) Compain if we're setting the symbol to the - difference of two symbols which are in different frags. (We can't - find out how far apart they are.) + * config/ChangeLog: removed. entries merged into this file. -Wed Aug 15 12:18:58 EDT 1990 Jay Fenlason + * config/ho-vms.h: new file. Move the VMS stuff out of ho-vax.h + into ho-vms.h. - * m68k.c (m68k_ip_op) Dyke out the code that deals with parsing - :[wl] at the end of expressions since it is handled in get_num() - and this was putting the result in the wrong place anyway. - Corrected a couple of other references to ->isiz instead of con?->e_siz + * configure.in: use ho-i386v4 for i386-sysvr4. -Mon Aug 13 15:53:46 EDT 1990 Jay Fenlason + * config/ho-i386v4: new file. - * read.c Handle .align specially on the sparc, or any other machine - where OTHER_ALIGN is defined. Added option and comments about it - to Makefile. +Tue Feb 25 19:54:04 1992 (Eric Youngdale at youngdale@v6550c.nrl.navy.mil) -Fri Aug 10 12:24:33 EDT 1990 Jay Fenlason + * config/obj-vms.c (VMS_write_object_file): Add work-around + for g++ compiler bug involving external vtables. - * m68k.c (get_num) Handle SEG_PASS1 expressions. +Mon Feb 24 22:19:10 1992 (Eric Youngdale at youngdale@v6550c.nrl.navy.mil) -Mon Aug 6 16:32:29 EDT 1990 Jay Fenlason + * README-vms: Describe how to get a VMS obj file to a vms machine + via NFS. - * write.c (fixup_segment) Added two patches for the NS32k - and SEQUENT A six line patch from Ian Dall - (asgard!aegir!hugin!augean!sibyl!ian@munnari.oz.au) + * configure.in: For i386-sysv*, use gas_host=i386. -Wed Aug 1 13:30:48 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * Makefile.in: Remove continuation line markers when the next line + is blank. - * m68k.c Include REGISTER_PREFIX ifdefs. + * read.c (line_comment_chars): Make external. - * write.c Include LOCAL_LABEL() and DOT_LABEL_PREFIX feature. + * input-file.c: Remove redundant include of <assert.h>. - * vax.c (md_parse_option) Accept -H option. + * config/ho-vax.h [VMS]: Include <ctype.h> and <perror.h>. - * vms.c New version of case hasher, etc. These from Eric Youngdale - <YOUNGDALE@v6550c.nrl.navy.mil> + * config/obj-vms.h: Remove said includes. Add RELOC_32 to + reloc_type to prevent compilation error. -Fri Jul 20 13:39:02 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * 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'. - * README Added README.APOLLO and README.COFF stuff +Mon Feb 24 03:48:04 1992 K. Richard Pixley (rich@cygnus.com) -Wed Jul 18 16:29:22 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * README: updated to reflect current testing status. - * Makefile Added option for SEQUENT_COMPATABILITY + * README.rich, NOTES, NOTES.config: updated slightly, marked as + "under construction". - * ns32k.c Add configurable syntax feature from - ian@sibyl.eleceng.ua.oz@augean.ua.oz.au - and SEQUENT_COMPATABILITY + * CONTRIBUTORS: new file. - * ns32k-opcode.h Add configurable syntax feature. + * README-vms: options to configure are now -options=, not + +options=. -Mon Jul 16 11:44:14 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * version.c: bumped version to 1.92.2. - * write.c (relax_segment) On ns32k, add fragP->fr_pcrel_adjust to - aim. - (fixup_segment) On ns32k, don't subtract size from - add_number on pcrel external symbols. +Mon Feb 24 03:27:00 1992 Eric Youngdale (youngdale at v6550c.nrl.navy.mil) - * ns32k.c (md_relax_table) Use correct max displacements. - This is a six-line patch from ian@sibyl.eleceng.ua.oz.au + * config.sub: Added vms as a target system. (So people do not + have to try to figure out that "vax-dec-vms" would work). - * ns32k.c (md_atof, convert_iif) Emit floating point numbers in - the correct byte order. A seven line patch from - ian@sibyl.eleceng.ua.oz.au + * 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). - * ns32k.c (all over) Some lint fixes. + * config-gas.com: New file. Script for VMS systems to set up the + configuration to build gas for VMS, and create config.status. -Mon Jul 9 13:17:00 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * make-gas.com: Redone to work with the bfd-gas scheme. - * app.c (do_scrub_next_char) If a comment is #{whitespace} - don't treat the next line as comment also. + * as.c: Add const modifier to version_string. - * m68k.c (...) Accept apc@(num:[wl]), etc. + * atof-vax.c: Remove redundant include of flonum.h. (This is also + included via as.h). - * i386.c (md_assemble) Get bitfields correct when doing cross - assembly to 386. A two line patch from Michael Bloom. - (usc!srhqla!quad1!ttidca!mb@zaphod.mps.ohio-state.edu). + * expr.c: Add "const" modifier to hex_value. - * README.APOLLO a new file with vasta@apollo's name, address - and phone # in it. + * 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. - * make-gas.com Deleted references to gdb source files. + * 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). -Fri Jul 6 14:34:27 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + * write.c: Add "const" modifier to md_[long,short]_jump_size. + Fix arguments to VMS_write_object_file. - * i386.c Ignore the .optim directive + * obj-vms.h: New file (sort of). Mostly canibalized from other + files, using: - * input-file.c Change from _IOLBF to _IOFBF in setbuffer emulation - for SYSV. + - objrecdef.h: Removed structure definition that we do not use, + and removed dollar signs from identifiers, since Unix System 5 + does not like them. -Mon Jun 18 15:36:49 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + - obj-aout.h: Took S_*, some H_* macros, and a number of + symbol definitions. - * sparc.c #ifdef DONTDEF s_sparc_align, since it isn't called from - anywhere. + - 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. -Fri Jun 15 15:53:30 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + - stab.h: Just included it, since on non VMS and non a.out systems + we have no guarantee of having it. (Define N_* symbols). - * vax.c (md_parse_option) make the code agree with the documentation - on the behaviour of the -d option. + *obj-vms.c: Renamed from vms.c. Did the following: -Thu Jun 7 14:23:54 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + - Reworked to use the S_* macros. - * atof-ieee.c (gen_to_words) Assemble 0r-0 correctly. + - Add "const" modifier to version_string. - * Makefile Remove last references to gdb*.c files. + - Added global[ref,def,value] support - * version.c New version 1.36 + - (VMS_Store_PIC_Symbol_Reference):fix a bug with static constants. -Tue May 22 13:22:26 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + - Remove a few redunant includes - all are now included through as.h. - * Makefile Mention a work-around for a possible problem with HPUX7.0 + - (obj_crawl_symbol_chain): Clean up (a lot), and remove non-VMS + code. Add definition for obj_read_begin_hook. -Mon May 21 14:06:04 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + - Borrow the stab[s,d,n] routines from obj-aout.c. - * sparc.c (sparc_ip): Change error message from "not in hash table" - to "unknown opcode". + - Borrow the seg_N_TYPE and N_TYPE_seg arrays from aout.c -Wed May 16 15:33:14 EDT 1990 hack@wookumz + - 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). - * i386.c (i386_operand) Print error msg if given an operand like - 4(mumble) which we can't parse. + - 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. - * m68k.c (md_assemble) Add '3' to the list of operand-places that - can be found in 'symbol-dependent info'. Also change - 'confusing width' diagnostic to something more meaningful. -Fri May 11 12:09:21 EDT 1990 hack@wookumz - app.c (do_scrub_next_char) Don't flush the line after a line - consisting of a single '/' A one-line patch from Mike Kupfer - (kupfer@orc.olivetti.com) + The following patches make cross assembly possible. - * i386.c (md_assemble) Call frag_wane() before calling frag_new() - A one line patch from Steve Bleazard (steve@robobar.co.uk + * as.c, read.c, symbols.c, write.c: Change "ifdef VMS" to + "ifdef OBJ_VMS". -Tue May 8 12:56:25 EDT 1990 hack@wookumz + * vms.c: - * atof-generic.c (atof-generic) Modified the Infinity detection code - to accept 0rinfinity and 0r-infinity as well as 0rinf and 0r-inf + - Wrap the #include of some VMS system dependent headers + with "ifdef VMS". -Thu Apr 26 15:17:31 EDT 1990 hack@wookumz + - (get_VMS_time_on_unix): Add new routine. Generates current + time in VMS format to be written into object file. - * atof-ieee.c Change value of NaNs to 0x7fff ffff (float) and - 0x7fff ffff ffff ffff (double) If you want some other value for - NaN, use .long and spell it out yourself. + - (Write_VMS_MHD_Records): Use get_VMS_time_on_unix if we are not + running on a VMS system. - atof-generic.c (atof_generic) Cleaned up code that detects NaN - and Inf. + - (Flush_VMS_Object_Record_Buffer): Add code to write correct + record format when running on a non-VMS system. - vax.c (md_assemble) print a useful error message if expression() - returns SEG_PASS1 or SEG_DIFFERENCE and we can't deal with those. + - (Create_VMS_Object_File): Use different mode if running under + unix. -Thu Apr 19 10:30:47 EDT 1990 hack@wookumz + - (VMS_TBT_Source_File): If we are not running on a VMS system, + write a source file record for the debugger that looks reasonable. - * input-scrub.c (AFTER_STRING) Make AFTER_STRING contain a null - so that the strstr() call when looking for "#NO_APP" after a "#APP" - will work. A two character patch from Bruce Robertson - (bruce@heather.pooh.com) +Mon Feb 24 02:06:00 1992 K. Richard Pixley (rich@cygnus.com) - * Makefile, i386.c Use atof-ieee.c instead of atof-i386.c + * Makefile.in: remove $(srcdir)/../include from INCLUDES. It + isn't needed. -Mon Apr 16 16:20:55 EDT 1990 hack@wookumz + * README: updated with current state. - * m68k.c (md_relax_table) Many of the offsets were off by two. - Fixed some generic spacing problems thoughout the file. + * 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. -Thu Apr 12 12:22:35 EDT 1990 hack@wookumz + * expr.c, expr.h, frags.c, symbols.c, write.c: white space only. - * sparc.c (md_ri_to_chars) Handle little-endian cross assembly. +Mon Feb 24 01:45:40 1992 K. Richard Pixley (rich@cygnus.com) - * write.c (relax_segment) Compare addresses correctly to avoid - accidentally relaxing a branch that we don't have to. - These small changes from John Gilmore (gnu@toad.com) + * config/te-sequent.h, config/tc-ns32k.h, config/tc-ns32k.c: + SEQUENT_COMPATIBILITY -> TE_SEQUENT. -Fri Apr 6 12:52:15 EDT 1990 hack@wookumz + * config/obj-aout.c: if OLD_GAS and i386, then screw up the magic + number. - * Makefile, expr.c symbols.c Correctly document the SUN_ASM_SYNTAX - option, and make it work. + * config/obj-bout.c: do not include aout/stab_gnu.h if NO_LISTING. -Tue Mar 20 12:46:59 EST 1990 + * config/obj-bout.h: added enum reloc_type. - * as.c (main) Only trap SIGHUP, SIGINT, SIGPIPE, and SIGTERM, - and only if they aren't being ignored. A three line patch - from Paul Eggert (eggert@twinsun.com) + * config/tc-i386.c: on OLD_GAS, .align is power of two, rather + than bytes. - * write.c (relax_segment) Correct typo 'growth - ' should have been - growth = + * config/tc-i386.h: on OLD_GAS, the filler byte should be zero + rather than NOOP. - * atof-vax.c (next_bits, flonum_gen2vax) Clean up by sharing some - variables. While we're at it, fix next_bits so that it - doesn't use littlenums that don't exist. . . + * config/tc-i860.c: relocs are 12bytes on this target. Also white + space. -Tue Mar 13 16:23:21 EST 1990 hack@wookumz + * config/tc-m68kmote.c: removed. Not ready yet. - * Rename atof-m68k.c atof-ieee.c + * config/a.out.gnu.h, config/tc-a29k.c, config/tc-m68k.c, + config/tc-ns32k.c: white space only. - * Delete atof-ns32k.c + * 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 - * m68k.c sparc.c ns32k.c atof-ieee.c Call atof-ieee instead of - atof-m68k or atof-ns32k + * config/tc-m68k.h, config/tc-i860.h, config/tc-vax.h: + REVERSE_SORT_RELOCS if OLD_GAS. - * Makefile Compile with atof-ieee.c instead of atof-ns32k.c or - atof-m68k.c + * config/mt-m68k: removed. not needed. -Mon Mar 12 14:06:55 EST 1990 hack@wookumz +Fri Feb 21 06:22:15 1992 K. Richard Pixley (rich@rtl.cygnus.com) - * as.c If the signal handler gets called twice, exit immediatly. + * config/obj-aout.c: do not include stab.gnu.h if NO_LISTING. - * ns32k.c Call gen_to_words with a pointer of the proper type, and - call md_number_to_chars to put the results in the proper byte-order. - Whoever wrote this code was *sloppy*! + * config/tc-i860.c, config/a.out.gnu.h: move i860 relocs to a proper place. - * Makefile ns32k.o depends on ns32k.c + * config/a.out.h: removed. - * vax.c (md_parse_option) If VMS, accept -+ and -h options. +Fri Feb 21 06:21:07 1992 K. Richard Pixley (rich@rtl.cygnus.com) - * vms.c (VMS_Case_Hack_Symbol) Replace #if NO_CASE_HACKING - with references to the -h option. These small VMS patches - from Angel Li (angel@flipper.miami.edu). + * Makefile.in: put header files before C source for TAGS; remove + references to non-existent syscalls.h. -Thu Mar 8 19:18:59 EST 1990 hack@wookumz - * vms.c Some trivial patches from Eric Youngdale - (YOUNGDALE@v6550c.nrl.navy.mil) + * read.c, write.c subsegs.c: back out the .bss changes. -Wed Mar 7 17:12:09 EST 1990 hack@wookumz - * make-gas.com (Define error as as_fatal when compiling vax.c and vms.c - A two line patch from Eric Youngdale - (YOUNGDALE@v6550c.nrl.navy.mil) +Fri Feb 21 02:17:22 1992 Minh Tran-Le (TRANLE@INTELLICORP.COM) -Tue Mar 6 16:01:09 EST 1990 hack@wookumz + * 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. - * Makefile Include ns32k options in makefile. A small patch from - David Taylor (taylor@think.com). +Fri Feb 21 01:53:50 1992 Minh Tran-Le (TRANLE@INTELLICORP.COM) - * as.c read.c write.c Makefile #ifdef DONTDEF out all the gdb - symbol stuff, since it isn't used anymore and it doesn't work. + * config/obj-coff.c: (for aix386) Moved the symbols .text, .data + and .bss to just after .file . -Mon Mar 5 14:51:04 EST 1990 hack@wookumz + 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)) - * i386.c (md_assemble) Replace memchr() with index(). + 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. - * as.c Trap signals 1 through NSIG, print an error msg, and don't - produce an object file. + Also, the AIX ld program require that the relocation table + is sorted by r_vaddr like the standard ATT assembler does. - * m68k.c Added a hack so that fsincosx fpx,fpy:fpz works. + [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.] - * messages.c New function: as_bad This is like as_warn, except - -W doesn't disable it, and calling it inhibits production of an - object file and causes a non-zero exit code. +Fri Feb 21 01:08:48 1992 Minh Tran-Le (TRANLE@INTELLICORP.COM) -Tue Feb 13 14:25:53 EST 1990 hack@wookumz - * Makefile Include G0 and LOADLIBES for Sequent Symmetry. - Based on a small patch from Johan Widen (jw@sics.se) + * symbols.c (local_label_name): symbols now start with ^A. -Thu Feb 1 14:08:58 EST 1990 hack@wookumz - * m68k.c Replace 'abort' with 'abort()' which will work. + * 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. -Wed Jan 24 17:15:08 EST 1990 hack@ai.mit.edu + * expr.c (operand): changed to generate local label "\001L0" + starting with a ^A so that it is recognized as a local label. - * read.c (ignore_rest_of_line) Have it print the first junk char - in both decimal and %c form. + * as.c (perform_an_assembly_pass): zero bss_fix_root, too. - (read_a_source_file) On bad pseudo-op, print out the unknown - pseudo-op's name. +Fri Feb 21 01:08:48 1992 K. Richard Pixley (rich@cygnus.com) -Tue Jan 23 13:12:48 EST 1990 hack@ai.mit.edu + * Makefile.in, configure.in, doc: use the doc. Build it, install + it, clean it, etc. - * read.c (pseudo_set) If the symbol is external, have it remain - external. +Tue Feb 18 02:21:25 1992 K. Richard Pixley (rich at cygnus.com) - * i386-opcode.h Allow jc as a synonym for jb and jnc as a syn for jnb. + * read.c: white space and comments only. + * configure.in: use the new atof-ns32.c for ns32k. -Wed Jan 3 09:35:31 EST 1990 hack@ai.mit.edu + * write.c: comment change only. - * ns32k.c [cpureg_032] Change register id of psr from 0x0b to 0x0d - * ns32k-opcode.h Change shift-counts for lsh and lshd - to one byte instead of 2 and 4. - A Trivial patch from John F. Peters (think!ames!practic.com!jfp@eddie) +Tue Feb 18 02:11:10 1992 K. Richard Pixley (rich at cygnus.com) -Tue Dec 5 16:37:44 EST 1989 hack@ai.mit.edu + * config/tc-m88k.[hc]: pulled in from hack's unfinished work. These + aren't yet integrated. - * ns32k.c (md_create_{long,short}_jump) Six line patch from - John F Peters (think!ames!vine!practice.com!jfp) to use the - correct addressing mode and byte-order for broken-word stuff. + * config/tc-i860.[hc]: blew off the dust. Something must still be + done about conflicting relocation types. - * write.c (write_object_file) One line patch to call fix_new_ns32k - with the correct # of args. + * config/tc-ns32k.c: Replaced previous tc_aout_fix_to_chars stub + with the real thing. -Fri Dec 1 16:44:21 EST 1989 hack@ai.mit.edu + * config/tc-i960.c, tc-sparc.c: white space and comments only. - * atof-generic.c, flonum-mult.c A real fix for the trailing-zeroes - problem from Georg Feil (ghfeil@white.toronto.edu) (two line change) + * config/tc-a29k.h: delete duplicate macro definition. -Mon Nov 27 15:30:46 EST 1989 hack@ai.mit.edu + * new file config/atof-ns32k.c copied from hack's last unreleased + gas. - * i386-opcode.h Fixed opcode-table entry for ljmp. A one char - patch from eliot@mgm.mit.edu +Mon Feb 17 07:51:06 1992 K. Richard Pixley (rich at cygnus.com) -Mon Nov 20 12:41:28 EST 1989 hack@ai.mit.edu + * 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. - * expr.c Replace the generic_buffer hack with a more portable one */ - - * atof-generic.c (atof_generic) Ignore trailing zeroes after a decimal - point. For some reason trailing zeroes (but not trailing nonzeroes) were - causing loss of precision. I don't know why. . . - - * vms.c Change copyright notice. Install changes from Kenneth Adelman - (adelman@tgv.com) for c++? (A dozen lines or so) - -Mon Nov 13 11:48:44 EST 1989 hack@ai.mit.edu - - * Makefile Add BINDIR and use it to control where the executable is - installed. - - * i386.c Use __builtin_alloca if possible (trivial patch from - Marco S. Hyman pacbell!dumbcat!marc) - -Mon Nov 6 18:24:47 EST 1989 hack@ai.mit.edu - - * version.c New version: 1.35 will be distributed with the - 1.36 gcc release. - -Mon Oct 30 10:38:11 EST 1989 hack@ai.mit.edu - - * atof-m68k.c (atof_m68k) Don't put the bits[] array on the stack, - since it may be pointed to after atof-m68k exits. - -Tue Oct 24 11:15:57 EDT 1989 hack@ai.mit.edu - - * atof-m68k.c Added #define for bcopy on USG systems. - #ifdef TEST the print_gen() function. - - * a.out.h if USE_HP_INC_HDR then use ../binutils/hp-include/a.out.h - -Fri Oct 13 14:36:48 EDT 1989 hack@ai.mit.edu - - * vax.c (all) Ran vax through indent -gnu to make it readable. - - vax.c (vip_op) Correctly assemble code like jmp $*0x11223344 - by setting vip_nbytes to 4 when using an immediate address. - I hope this works! - - m68k.c (s_proc (new)) Added s_proc no-op pseudo-op. - - Makefile Added instructions for compiling on Sequent Symmetry - and HP 9000/300. - - a.out.h Modified to compile on Sequent and HP above. (HP port - based on a msg from asjl@comp.vuw.ac.nz (real name unknown)). - -Tue Oct 10 14:39:44 EDT 1989 hack@ai.mit.edu - * vax.c (vip_op) Fixed a typo in an error msg and cleaned - up some spacing stuff. - -Wed Sep 27 19:07:12 EDT 1989 hack@ai.mit.edu - - * app.c (do_scrub_next_char) Fixed parsing of - # <line> "file" garbage - text so that it'll work again? (8 line patch from Mike Hibler - (mike@cs.utah.edu)) - -Mon Sep 18 16:26:01 EDT 1989 hack@ai.mit.edu - - * app.c (do_scrub_next_char): Modify parsing of /* ... */ to work - on the text /* ****/ - - * sparc.c (sparc_ip): Don't abort on insns that use the Alternate - Spaces. Try to assemble them correctly. - -Thu Sep 14 11:42:44 EDT 1989 hack@ai.mit.edu - - * sparc.c (md_number_to_imm) Dozen line patch from jkp@sauna.hut.fi - (Jyrki Kuoppala) so that gas output will work with shared libraries. - - * ns32k.c Include <string.h> instead of <strings.h> if USG defined. - - (md_end) free(freeptr_static) instead of free(freeptr) . - - * atof-ns32k.c Include as.h so that sysV stuff (bzero) will be - defined if needed. These ns32k changes from - nixbur!mollers.pad@seismo.css.gov (Josef Moellers) - -Fri Sep 1 11:39:52 EDT 1989 hack@ai.mit.edu - - * atof-m68k.c (gen_to_words) Get the sign right on negative - floating-point numbers. - -Wed Aug 30 13:59:57 EDT 1989 hack@ai.mit.edu - - * Makefile Remove the rest of the $< entries that kill sun make - -Fri Aug 25 15:00:30 EDT 1989 Nobody You Know (hack@ai.mit.edu) - - * atof-m68k.c (gen_to_words) deal with denormalized floating-point - numbers. - -Tue Aug 22 02:03:05 1989 Roland McGrath (roland at hobbes.ai.mit.edu) - - * Makefile (gas-dist.tar): Put ChangeLog in the tar file. - - * version.c: Added comment telling Jay Fenl--I mean people--not to put - changes in version.c, but to use ChangeLog instead. - - * version.c (version_string): Put "GNU" in all-caps. - - * version.c: Moved all comments about changes to ChangeLog (this file). - Many anonymous entries have been attributed to Jay Fenlason (hack). - -Thu Aug 17 15:53:57 1989 Jay Fenlason (hack at apple-gunkies.ai.mit.edu) - - * Makefile: Removed $< references that seem - to choke some versions of make. - - * frags.c (frag_grow): Fixed to deal with requests for very - large frags (larger than frags.chunk_size). - - * app.c (do_scrub_next_char): Have it ignore any characters - after the filename in a # line "filename". - - * sparc.c (s_common): On an error, don't print out - input_line_pointer past the end of the line where the error is. - - * atof-generic.c (atof_generic): Accept any case for - inf and nan. - - * m68k.c (m68_ip): Don't use PC-relative mode for alterable - addressing modes. - -Tue Aug 15 04:58:36 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) - - * sparc.c (md_begin): Rewrote this function to perform consistency - checks with the new opcode table. - -Fri Aug 11 16:01:16 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) - - * sparc-opcode.h (struct sparc_opcode): Replaced `mask' field with - `lose'; removed `last' field. Updated all opcodes accordingly. - Fixed several opcodes that generated the wrong instructions. - sparc.c (md_begin, sparc_ip): Changed to use new struct sparc_opcode. - -Thu Aug 3 14:44:24 1989 Jay Fenlason (hack at apple-gunkies.ai.mit.edu) - - * Makefile (a32k): Use read- and write-ns32k.o - * ns32k.c (encode_operand): Make sure pcrel_adjust starts out zeroed. - * read.c (cons): Call fix_new_ns32k() if NS32K is defined. - * write.c (write_object_file): Ditto. - These so that .word sym-sym (etc) will produce values with - the proper byte-order. - -Wed Aug 2 12:55:?? 1989 Jay Fenlason (hack at apple-gunkies.ai.mit.edu) - - * sparc.c (comment_chars[]): Removed '|' because it was causing - problems. Probably not the best fix, since I suspect other - assemblers (68020) may get | in .stabs also, and the 68020 needs - the '|' comment character. - -Mon Jul 31 09:22:28 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) - - * sparc.c (sparc_ip): Allow the characters [0123] in opcodes. - -Tue Jul 25 16:32:12 1989 Jay Fenlason (hack) - - * atof-generic.c (atof_generic): Tried to keep - size_of_digits_in_littlenum from going negative. - - * sparc-opcode.h: Added duplicate [i+1] entries to go with - the [1+i] entries already there. A kludgy fix, but it works. - -Mon Jul 24 17:20:03 1989 Jay Fenlason (hack) - - * write.c (relax_segment): Modified rs_org code so it won't - occasionally dump core. - - * write.c (pseudo_set): Modified SEG_DIFFERENCE to (perhaps) - allow one to set a symbol to the difference of two other symbols. - - * ns32k.c (convert_iif): Moved size_so_far+=size and size=0 inside - the check for a valid type. - - * sparc-opcode.h: Modified the entries for std "q,[1+i]", "D,[1+i]", - and "Q,[1+i]". - -(In version 1.34) Jay Fenlason (hack) - - * Makefile: Reorganized, added stuff to make asparc. - - * sparc.c, sparc-opcode.h, sparc.h: Sparc port. - - * write.c: Set the size of text and bss segments to a multiple of eight - bytes. - - * m68k.c: Moved .single pseudo-op to machine independent part. - - * atof-generic.c: Fixed type in #ifdef __GNUC__. - - * sparc-opcode.h: Handle "mov REG, %y". - - * make-gas.com: Know that error.c no longer exists. - - * sparc.c: Handle [expr+reg]. - Don't call getExpression when looking for an immediate and getting - something that starts with % and isn't %hi or %lo. - - * Teach the 68k about long conditional branches. - -(In version 1.33) Jay Fenlason (hack) - - * Use __builtin_alloca if available. - - * README: Added more instructions for reporting bugs. - - * ns32k-opcode.h: Changed the acbb, acbw, and acbd insns. - - * vax.c: Replaced instances of LENGTH[STRING] with STRING[LENGTH]. - - * ns32k.c (encode_operand): Increased max size of bit field for exts - and inss instructions from 31 to 32 bits. - - * flonum-mult.c (flonum_multip): Fixed typo. - - * m68kc.: Allow #32 to be the same as #0 for bit-field ops. - - * make-gas.com, version.c, hex-value.c, flonum-const.c: VMS fixes. - - * ns32k.c, ns32k-opcode.h: More fixes from taylor@think.com. - Mostly typos in comments, etc. - - * ns32k-opcode.h: Fixed size of immediate operands to andw and andd - instructions. - -(In version 1.32) Jay Fenlason (hack) - - * read.c (s_set): Fixed misnamed variable. - - * as.c: Don't hang if given an invalid option. - - * m68k.c: Fixed bug in creating absolute long addresses for branches. - - * ns3k*: Some small ns32k patches. - - * m68k.c: Recognize 0rnan, 0rinf, 0r-inf. - - * app.c: Don't dump core on unterminated strings. - - * symbols.c: Give reasonable error messages. - - * ns32k*: Allow -m32032 and -m32532 options. - - * atof-*.c: Added support for NaN, Inf, and -Inf in atof_generic and - the various descriptions. - - * m68k.c (add_fix): Replace occurrences of "width==" with - "(width)==". This correct a precedence problem. - - * write.c, struc-symbol.h, m68k-opcode.h, m-hpux.h, Makefile: Changes - for HP-UX from Chris Hanson (cph@kleph.ai.mit.edu). - - * m68k-opcode.h: Reorder movem insns so gdb will see the ones using the - register list syntax first. - - * symbols.c (colon): Give more useful error messages when something was - defined as a .comm and is now trying to be defined locally. - Also, redefining a symbol is a fatal, not a warning. - - * m68k.c: Fixed a bug in using bignums as literal bit patterns for - floating-point numbers. - -(In version 1.31) Jay Fenlason (hack) - - * i386*: More patches. - - * Moved machine-dependent option parsing into the machine-dependent - source files. - -(In version 1.30) Jay Fenlason (hack) - - * i386*: New new version. - - * atof-m68k.c: Changed to be smaller, with somewhat better modularity. - Also fixed an obscure bug wherein next_bits would return random bits. - - * m68k.c: Be more careful about creating PC-relative addressing modes - on the 68000 and 68010. - - * frags.c (frag_new): Zero out the new frag. - - * Don't choke on "foo= bar" or on formfeeds. - - * read.c: Allow Sun-syntax local labels #ifdef SUN_ASM_SYNTAX. - * m-sun3.h: Defined SUN_ASM_SYNTAX. - -(In version 1.29) Jay Fenlason (hack) - - * i386.c: Newer version that fixes a bug wherein a jump instruction - would be split between two frags. - - * i386*: New version. - - * m68k.c: #ifdef M_SUN and -m68010, produce Sun-2 executables. - -(In version 1.28) Jay Fenlason (hack) - - * m68k.c: Added .single pseudo-op. - - * Made ". = X" and ".set .,X" equivalent to ".org X". - The pseudo-symbol "." has the value of the location the assembler is - currently assembling to. - -(In version 1.27) Jay Fenlason (hack) - - * Merged ns32k and i386 support. - -(In version 1.26) Jay Fenlason (hack) - - * Added partial ns32k support. - - * Added RMS's evil .word misfeature. Invented the -k (kludge) option - to warn that this misfeature was used. - - * Modified some files to get rid of warnings from GCC. - - * Added fix so that / can also be a comment character by itself. - -(In version 1.25) Jay Fenlason (hack) - - * Installed patches for VMS. - - * as.h (SIZEOF_STRUCT_FRAG): Added space before backslash-newline. - - * messages.c: Fixed typo. - - * app.c: Handle : correctly. - - * error.c: Removed; no longer used. - - * m68k-opcode.h: Added fnop. - Fixed to correctly handle fmovem with a register list and - non-predecriment addressing mode. - - * m68k-opcode.h: Fixed to know about long form of FBcc insns. - - * write.c: Warn if a fixup ended up being wider than its field width. - -(In version 1.24) Jay Fenlason (hack) - - * Accept and ignore -mc68010 and -m68010 switches. - - * Correctly assemble long subroutine calls on the 68000 without using a - 68020-specific instruction. - - * When calling with no filenames, read stdin. - -(In version 1.23) Jay Fenlason (hack) - - * app.c: Rewritten. - - * xmalloc.c, xrealloc.c: Replaced to work with GCC. - -(In version 1.22) Jay Fenlason (hack) - - * write.c: Fixed a VMS bug. - - * m68k.c: Fixed a bug having to do with turning absolute into - PC-relative. - - * atof-m68k.c (atof_m68k, gen_to_words): Try to avoid a problem with - running off the end of the LITTLENUMS. - - * vax.c: Fixed so parenthesized expressions work. - - * atof-generic.c: Added a cast that fixes problems with some C - compilers. - -(In version 1.21) - - * Changes for VMS support and correct bitfield order for - cross-assembly. - -(In version 1.20) - - * m68k*: Fixed "fmovel #N, fpcr". Added fpcr and fpsr to the list of - registers. - -(In version 1.19) - - * m68k.c? (md_convert_frag): Don't put the fixups for absolute long to - PC-relative in the data segment. - - * atof-generic.c: #include <alloca.h> #ifdef sparc. - -(In version 1.18) - - * Re-fixed _vfprintf stuff (?). - - * Made "movem REG, ADDR" work. - - * Improved preprocessing, without temporary files. - -(In version 1.17) - - * Don't produce an undefined empty symbol for ".globl foo," (a line - ending with a comma). - - * Fixed a bug wherein ".long X" became ".long 0" on the Sparc. - - * Fixed a bug which caused many "#APP" "#NO_APP" pairs to dump core. - - * Fixed calls to _doprnt to call _vfprintf #ifndef NO_VARARGS. - -(In version 1.16) - - * Merged HP-UX changes from Chris Hanson (cph@zurich.ai.mit.edu). - - * flonum-multip.c: Renamed to flonum-mult.c. - - * m-hpux.h: Created. - - * m68k.c (bcopy): Fixed. - -(In version 1.15) - - * struct-symbol.h: Renamed to struc-symbol.h. - -(In version 1.14) - - * vax.c: Added a quick fix for the offset of fixed-width branches not - fitting in the field given. - - * gdb-lines.c, read.c: Added support for .gdline and .gdbline - pseudo-ops. - -(In version 1.13) - - * read.c, atof-generic.c: Fixed bugs in reading in floating-point - numbers. - - * m68k-opcode.h: Made "fmovep a0@, fp0" work. - -(In version 1.12) - - * write.c: Fixed an obscure bug in relaction that would occasionally - cause the assembler to stop relaxing when it really had at least one - more pass to do. - -(In version 1.11) - - * m68k*: Allow register lists in fmovem. - - * Added more floating-point exponents. - - * Print an error message on exponent overflow. - -(In version 1.10) - - * Fixed floating point bugs that made it generate incorrect numbers for - values over 10^16 or so. - -(In version 1.09) - - * Fixed bug wherein you couldn't forward reference local label 0. - -(In version 1.08) - - * m68k.c, m68k-opcode.h: Added support for fmovem with register lists. - - * Fixed an obscure bug having to do with generating PC-relative - addressing mode for things in the middle of the instruction instead of - at the end. - -Wed Mar 1 15:29:24 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) - - * *.*: Modified copyright notices to reflect new General Public - License. - - * Makefile: Added copyright notice. - -Fri Feb 17 09:42:01 1989 Jay Fenlason (hack at spiff) - - * Patched frags.c so that new frags start out bzero()ed. - -Thu Jan 26 14:23:44 1989 Jay Fenlason (hack at apple-gunkies.ai.mit.edu) - - * Added patches from pace to files as.h i386.c i386-opcode.h - imull foo,%eax no longer gets assembled into the 32-64 bit - multiply, which clobbers %edx behind gcc's back - - jcxz/jecxz were backwards - - There was a bug when using %ebp as a base register with no - displacement - - Instructions like andb $0xffffff, %al used to put out too many - immediate bytes - - The splitting jump instructions across frags could happen when - obstack_room()==6 too. - -Local Variables: -mode: indented-text -left-margin: 8 -version-control: never -End: diff --git a/gnu/usr.bin/as/Makefile b/gnu/usr.bin/as/Makefile index e75351b6..0a2ae0a 100644 --- a/gnu/usr.bin/as/Makefile +++ b/gnu/usr.bin/as/Makefile @@ -1,15 +1,72 @@ -# @(#)Makefile 6.1 (Berkeley) 3/3/91 +# from: @(#)Makefile 6.1 (Berkeley) 3/3/91 +# $Id: Makefile,v 1.10 1993/10/16 22:04:48 pk 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 append.c as.c atof-generic.c bignum-copy.c \ - expr.c flonum-const.c flonum-copy.c flonum-mult.c \ +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 \ - messages.c obstack.c output-file.c read.c subsegs.c \ - symbols.c version.c write.c xmalloc.c xrealloc.c -CFLAGS+= -I$(.CURDIR) -I$(.CURDIR)/config \ - -DSIGTY=void -Derror=as_fatal + 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 +#LDADD+= -lgnumalloc +DPADD+= /usr/lib/libgnumalloc.a + +CONF_HEADERS= targ-cpu.h obj-format.h host.h targ-env.h + .PATH: $(.CURDIR)/config -.include "config/Makefile.$(MACHINE)" +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 0000000..1497b1f --- /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 index b3f3f92..9f18fac 100644 --- a/gnu/usr.bin/as/NOTES +++ b/gnu/usr.bin/as/NOTES @@ -1,35 +1,16 @@ -gdb debugging of assembly sources: - write a function linestab() that generates a .stabd symbol - independently of the input - write a function filestab() to generate a .stabs symbol - we need to take especial care with #line directives - since we want to handle locore, and locore is passed thru cpp - this could be tough - outline of a solution: - cpp sends us lines of the form - # logical-line "logical-file" trash - these lines are interpreted ahead of the gas preprocess pass - in the starting state, the logical filename is the same - as the real filename (in case there're no #lines) - the initial logical line number is 1 - every time we're ready to process a new instruction line, - if the source file has changed, - emit a .stabs for the logical file - emit a .stabd for the logical line - bump the logical line number - can gas eat multiple actual lines in one insn? +to do: -i386 nits: - jmp *$foo produces a short relative branch - string quotes in comments - Bill says gas eats text across newlines to find matches - works fine for me - I think it's most likely due to cpp - make / no longer be a comment char - it's now like the VAX: # is the only comment char - incorrectly assembles lcall, int3, into, bsr/f instructions - constant expressions fail if more than a few terms - gives (low+2)*3+4*5 as an example - works fine for me - cpp seems to think $ is a valid literal - use -$ in /usr/bin/cpp +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 0000000..a511519 --- /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 0000000..73b7605 --- /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 0000000..796c603 --- /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 0000000..46c61cd --- /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 0000000..adde6fe --- /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 0000000..5a2ecc4 --- /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 0000000..a3f79bb --- /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 index a0ec8a2..4c89a77 100644 --- a/gnu/usr.bin/as/app.c +++ b/gnu/usr.bin/as/app.c @@ -1,182 +1,273 @@ +/* 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 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 file is part of GAS, the GNU Assembler. + + GAS is free software; you can 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>;.file <filename> pair. + # <number> <filename> <garbage> into a .line <number>\n.app-file <filename> pair. This needs better error-handling. - */ -#include <stdio.h> -#ifdef USG -#define bzero(s,n) memset(s,0,n) + */ +#ifndef lint +static char rcsid[] = "$Id: app.c,v 1.3 1993/10/02 20:57:12 pk Exp $"; #endif -#if !defined(__STDC__) && !defined(const) + +#include <stdio.h> +#include "as.h" /* For BAD_CASE() only */ + +#if (__STDC__ != 1) && !defined(const) #define const /* Nothing */ #endif -static char lex [256]; -static const char symbol_chars[] = - "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; +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[]; - -#define LEX_IS_SYMBOL_COMPONENT (1) -#define LEX_IS_WHITESPACE (2) -#define LEX_IS_LINE_SEPERATOR (4) -#define LEX_IS_COMMENT_START (8) /* JF added these two */ -#define LEX_IS_LINE_COMMENT_START (16) -#define IS_SYMBOL_COMPONENT(c) (lex [c] & LEX_IS_SYMBOL_COMPONENT) -#define IS_WHITESPACE(c) (lex [c] & LEX_IS_WHITESPACE) -#define IS_LINE_SEPERATOR(c) (lex [c] & LEX_IS_LINE_SEPERATOR) -#define IS_COMMENT(c) (lex [c] & LEX_IS_COMMENT_START) -#define IS_LINE_COMMENT(c) (lex [c] & LEX_IS_LINE_COMMENT_START) - -void -do_scrub_begin() -{ +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; - - bzero (lex, sizeof(lex)); /* Trust NOBODY! */ - lex [' '] |= LEX_IS_WHITESPACE; - lex ['\t'] |= LEX_IS_WHITESPACE; - for (p =symbol_chars;*p;++p) - lex [*p] |= LEX_IS_SYMBOL_COMPONENT; - lex ['\n'] |= LEX_IS_LINE_SEPERATOR; -#ifdef DONTDEF - lex [':'] |= LEX_IS_LINE_SEPERATOR; -#endif - lex [';'] |= LEX_IS_LINE_SEPERATOR; - for (p=comment_chars;*p;p++) - lex[*p] |= LEX_IS_COMMENT_START; - for (p=line_comment_chars;*p;p++) - lex[*p] |= LEX_IS_LINE_COMMENT_START; -} + + 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() -{ +int scrub_from_file() { return getc(scrub_file); } -void -scrub_to_file(ch) +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() -{ +int scrub_from_string() { return scrub_string == scrub_last_string ? EOF : *scrub_string++; -} +} /* scrub_from_string() */ -void -scrub_to_string(ch) +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; } -int -do_scrub_next_char(get,unget) +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)(); -/* FILE *fp; */ { - /* State 0: beginning of normal line - 1: After first whitespace on normal line (flush more white) - 2: After first non-white on normal line (keep 1white) - 3: after second white on normal line (flush white) - 4: after putting out a .line, put out digits - 5: parsing a string, then go to old-state - 6: putting out \ escape in a "d string. - 7: After putting out a .file, put out string. - 8: After putting out a .file string, flush until newline. - -1: output string in out_string and go to the state in old_state - -2: flush text until a '*' '/' is seen, then go to state old_state - */ - - static state; - static old_state; - static char *out_string; - static char out_buf[20]; - static add_newlines; - int ch; - - if(state==-1) { + /*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) { + if (*out_string == 0) { state=old_state; old_state=3; } return ch; - } - if(state==-2) { - for(;;) { - do ch=(*get)(); - while(ch!=EOF && ch!='\n' && ch!='*'); - if(ch=='\n' || ch==EOF) - return ch; - ch=(*get)(); - if(ch==EOF || ch=='/') - break; + + 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 ' '; - } - if(state==4) { + + case 4: ch=(*get)(); - if(ch==EOF || (ch>='0' && ch<='9')) - return ch; + if (ch == EOF || (ch >= '0' && ch <= '9')) + return ch; else { - while(ch!=EOF && IS_WHITESPACE(ch)) - ch=(*get)(); - if(ch=='"') { + while (ch != EOF && IS_WHITESPACE(ch)) + ch=(*get)(); + if (ch == '"') { (*unget)(ch); - out_string="; .file "; + out_string="\n.app-file "; old_state=7; state= -1; return *out_string++; } else { - while(ch!=EOF && ch!='\n') - ch=(*get)(); + while (ch != EOF && ch != '\n') + ch=(*get)(); return ch; } } - } - if(state==5) { + + case 5: ch=(*get)(); - if(ch=='"') { + if (ch == '"') { state=old_state; return '"'; - } else if(ch=='\\') { + } else if (ch == '\\') { state=6; return ch; - } else if(ch==EOF) { + } else if (ch == EOF) { as_warn("End of file in string: inserted '\"'"); state=old_state; (*unget)('\n'); @@ -184,19 +275,19 @@ void (*unget)(); } else { return ch; } - } - if(state==6) { + + case 6: state=5; ch=(*get)(); - switch(ch) { + 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': @@ -204,6 +295,9 @@ void (*unget)(); case 'n': case 'r': case 't': +#ifdef BACKSLASH_V + case 'v': +#endif /* BACKSLASH_V */ case '0': case '1': case '2': @@ -213,158 +307,202 @@ void (*unget)(); 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; - } - - if(state==7) { + + case 7: ch=(*get)(); state=5; old_state=8; return ch; - } - - if(state==8) { + + case 8: do ch= (*get)(); - while(ch!='\n'); + while (ch != '\n'); state=0; return ch; } - - flushchar: + + /* OK, we are somewhere in states 0 through 4 */ + + /* flushchar: */ ch=(*get)(); - switch(ch) { - case ' ': - case '\t': + 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_SEPERATOR(ch)) { - (*unget)(ch); - goto flushchar; + 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; } - (*unget)(ch); - if(state==0 || state==2) { - state++; - return ' '; - } else goto flushchar; - - case '/': - ch=(*get)(); - if(ch=='*') { - for(;;) { + 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 { - ch=(*get)(); - if(ch=='\n') - add_newlines++; - } while(ch!=EOF && ch!='*'); - ch=(*get)(); - if(ch==EOF || ch=='/') - break; + 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(ch==EOF) - as_warn("End of file in '/' '*' string: */ inserted"); - - (*unget)(' '); - goto flushchar; + if (ch2 == EOF) + as_warn("End of file in multiline comment"); + + ch = ' '; + goto recycle; } else { - if(IS_COMMENT('/') || (state==0 && IS_LINE_COMMENT('/'))) { - (*unget)(ch); - ch='/'; - goto deal_misc; - } - if(ch!=EOF) - (*unget)(ch); - return '/'; + if (ch2 != EOF) + (*unget)(ch2); + return ch; } break; - - case '"': + + case LEX_IS_STRINGQUOTE: old_state=state; state=5; - return '"'; - break; - - case '\'': + return ch; + +#ifndef IEEE_STYLE + case LEX_IS_ONECHAR_QUOTE: ch=(*get)(); - if(ch==EOF) { - as_warn("End-of-file after a ': \000 inserted"); + if (ch == EOF) { + as_warn("End-of-file after a one-character quote; \000 inserted"); ch=0; } - sprintf(out_buf,"(%d)",ch&0xff); + sprintf(out_buf,"%d", (int)(unsigned char)ch); + + /* None of these 'x constants for us. We want 'x'. + */ + if ( (ch=(*get)()) != '\'' ) { +#ifdef REQUIRE_CHAR_CLOSE_QUOTE + as_warn("Missing close quote: (assumed)"); +#else + (*unget)(ch); +#endif + } + old_state=state; state= -1; out_string=out_buf; return *out_string++; - - case ':': - if(state!=3) - state=0; +#endif + case LEX_IS_COLON: + if (state != 3) + state=0; return ch; - - case '\n': - if(add_newlines) { + + case LEX_IS_NEWLINE: + /* Roll out a bunch of newlines from inside comments, etc. */ + if (add_newlines) { --add_newlines; (*unget)(ch); } - case ';': + /* fall thru into... */ + + case LEX_IS_LINE_SEPARATOR: state=0; return ch; - - default: - deal_misc: - if(state==0 && IS_LINE_COMMENT(ch)) { - do ch=(*get)(); - while(ch!=EOF && IS_WHITESPACE(ch)); - if(ch==EOF) { - as_warn("EOF in comment: Newline inserted"); - return '\n'; - } - if(ch<'0' || ch>'9') { - while(ch!=EOF && ch!='\n') - ch=(*get)(); - if(ch==EOF) - as_warn("EOF in Comment: Newline inserted"); - state=0; - return '\n'; - } - (*unget)(ch); - old_state=4; - state= -1; - out_string=".line "; - return *out_string++; - - } else if(IS_COMMENT(ch)) { - do ch=(*get)(); - while(ch!=EOF && ch!='\n'); - if(ch==EOF) - as_warn("EOF in comment: Newline inserted"); + + 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'; - - } else if(state==0) { - state=2; + } + /* 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; + } else if (state == 1) { + state=2; /* Ditto */ return ch; } else { - return ch; - + return ch; /* Opcode or operands already */ } - case EOF: - if(state==0) - return ch; - as_warn("End-of-File not at end of a line"); } return -1; } @@ -377,10 +515,10 @@ char line_comment_chars[] = "#"; main() { int ch; - + app_begin(); - while((ch=do_scrub_next_char(stdin))!=EOF) - putc(ch,stdout); + while ((ch=do_scrub_next_char(stdin)) != EOF) + putc(ch,stdout); } as_warn(str) @@ -390,3 +528,12 @@ char *str; 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 index 2910279..57e2dc1 100644 --- a/gnu/usr.bin/as/as.1 +++ b/gnu/usr.bin/as/as.1 @@ -3,7 +3,7 @@ .TH as 1 "21 January 1992" "cygnus support" "GNU Development Tools" .SH NAME -GNU as\-\-the portable GNU assembler. +GNU as \- the portable GNU assembler. .SH SYNOPSIS .na @@ -15,7 +15,7 @@ GNU as\-\-the portable GNU assembler. .RB "[\|" \-I .I path\c \&\|] -.RB "[\|" \-K "\|]" +.RB "[\|" \-k "\|]" .RB "[\|" \-L "\|]" .RB "[\|" \-o .I objfile\c @@ -144,8 +144,8 @@ to the search list for .B .include directives. .TP -.B \-K -Issue warnings when difference tables altered for long displacements. +.B \-k +Handle position independent code, generated by gcc -fpic. .TP .B \-L Keep (in symbol table) local symbols, starting with `\|\c diff --git a/gnu/usr.bin/as/as.1aout b/gnu/usr.bin/as/as.1aout index 2910279..57e2dc1 100644 --- a/gnu/usr.bin/as/as.1aout +++ b/gnu/usr.bin/as/as.1aout @@ -3,7 +3,7 @@ .TH as 1 "21 January 1992" "cygnus support" "GNU Development Tools" .SH NAME -GNU as\-\-the portable GNU assembler. +GNU as \- the portable GNU assembler. .SH SYNOPSIS .na @@ -15,7 +15,7 @@ GNU as\-\-the portable GNU assembler. .RB "[\|" \-I .I path\c \&\|] -.RB "[\|" \-K "\|]" +.RB "[\|" \-k "\|]" .RB "[\|" \-L "\|]" .RB "[\|" \-o .I objfile\c @@ -144,8 +144,8 @@ to the search list for .B .include directives. .TP -.B \-K -Issue warnings when difference tables altered for long displacements. +.B \-k +Handle position independent code, generated by gcc -fpic. .TP .B \-L Keep (in symbol table) local symbols, starting with `\|\c diff --git a/gnu/usr.bin/as/as.c b/gnu/usr.bin/as/as.c index db85525..a9cbb70 100644 --- a/gnu/usr.bin/as/as.c +++ b/gnu/usr.bin/as/as.c @@ -1,32 +1,21 @@ -/*- - * This code is derived from software copyrighted by the Free Software - * Foundation. - * - * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. - */ - -#ifndef lint -static char sccsid[] = "@(#)as.c 6.3 (Berkeley) 5/8/91"; -#endif /* not lint */ - /* as.c - GAS main program. - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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. @@ -42,6 +31,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ * don't support them now. * */ +#ifndef lint +static char rcsid[] = "$Id: as.c,v 1.3 1993/10/02 20:57:15 pk Exp $"; +#endif + +#include <stdio.h> +#include <string.h> #ifdef _POSIX_SOURCE #include <sys/types.h> /* For pid_t in signal.h */ @@ -49,52 +44,66 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <signal.h> #define COMMON + #include "as.h" -#include "struc-symbol.h" -#include "write.h" - /* Warning! This may have some slightly strange side effects - if you try to compile two or more assemblers in the same - directory! - */ +#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 -SIGTY got_sig(); +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 int gdb_begin(); +long gdb_begin(); #endif +int listing; /* true if a listing is wanted */ + char *myname; /* argv[0] */ -extern char version_string[]; +extern const char version_string[]; -main(argc,argv) -int argc; -char **argv; +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 -) */ + int work_argc; /* variable copy of argc */ + char **work_argv; /* variable copy of argv */ + char *arg; /* an arg to program */ + char a; /* an arg flag (after -) */ static const int sig[] = { SIGHUP, SIGINT, SIGPIPE, SIGTERM, 0}; - - extern int bad_error; /* Did we hit a bad error ? */ - - char *stralloc(); /* Make a (safe) copy of a string. */ - void symbol_begin(); - void read_begin(); - void write_object_file(); - - for(a=0;sig[a]!=0;a++) - if(signal(sig[a], SIG_IGN) != SIG_IGN) - signal(sig[a], got_sig); - + + for (a=0;sig[a] != 0;a++) + if (signal(sig[a], SIG_IGN) != SIG_IGN) + signal(sig[a], got_sig); + myname=argv[0]; - bzero (flagseen, sizeof(flagseen)); /* aint seen nothing yet */ - out_file_name = "a.out"; /* default .o file */ + 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 */ @@ -113,107 +122,161 @@ char **argv; * 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 != '-') /* Filename. We need it later. */ + continue; /* Keep scanning args looking for flags. */ if (arg[1] == '-' && arg[2] == 0) { /* "--" as an argument means read STDIN */ /* on this scan, we don't want to think about filenames */ * work_argv = ""; /* Code that means 'use stdin'. */ continue; } - /* This better be a switch. */ - arg ++; /* -> letter. */ - - while (a = * arg) {/* scan all the 1-char flags */ - arg ++; /* arg -> after letter. */ + /* 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_warn("%s: Flag option -%c has already been seen!",myname,a); - flagseen[a] = TRUE; + /* 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); + 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); + as_warn("%s: I expected a filename after -G", myname); arg = ""; /* Finished with this arg. */ break; #endif - -#ifndef WORKING_DOT_WORD + + 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); + 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); + as_warn("%s: I expected a filename after -o. \"%s\" assumed.", myname, out_file_name); arg = ""; /* Finished with this arg. */ break; - + case 'R': /* -R means put data into text segment */ break; - + case 'v': -#ifdef VMS +#ifdef OBJ_VMS { - extern char *compiler_version_string; - compiler_version_string = arg; + extern char *compiler_version_string; + compiler_version_string = arg; } -#else /* not VMS */ +#else /* not OBJ_VMS */ fprintf(stderr,version_string); - if(*arg && strcmp(arg,"ersion")) - as_warn("Unknown -v option ignored"); -#endif - while(*arg) arg++; /* Skip the rest */ + 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; - - case 'g': - /* - * -g asks gas to produce gdb/dbx line number - * and file name stabs so that an assembly - * file can be handled by a source debugger. - */ - break; - + default: --arg; - if(md_parse_option(&arg,&work_argc,&work_argv)==0) - as_warn("%s: I don't understand '%c' flag!",myname,a); - if(arg && *arg) - arg++; + 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; } } @@ -229,21 +292,37 @@ char **argv; } #ifdef DONTDEF if (gdb_begin(gdb_symbol_file_name) == 0) - flagseen ['G'] = 0; /* Don't do any gdbsym stuff. */ + flagseen['G'] = 0; /* Don't do any gdbsym stuff. */ #endif /* Here with flags set up in flagseen[]. */ + perform_an_assembly_pass(argc,argv); /* Assemble it. */ - if (seen_at_least_1_file() && !bad_error) - write_object_file();/* relax() addresses then emit object file */ +#ifdef TC_I960 + brtab_emit(); +#endif + if (seen_at_least_1_file() + && !((had_warnings() && flagseen['Z']) + || had_errors() > 0)) { + write_object_file(); /* relax() addresses then emit object file */ + } /* we also check in write_object_file() just before emit. */ + input_scrub_end(); md_end(); /* MACHINE.c */ -#ifndef VMS - exit(bad_error); /* WIN */ -#else /* VMS */ - exit(!bad_error); /* WIN */ -#endif /* VMS */ -} - + +#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() * @@ -256,34 +335,50 @@ char **argv; * Note the un*x semantics: there is only 1 logical input file, but it * may be a catenation of many 'physical' input files. */ -perform_an_assembly_pass (argc, argv) -int argc; -char ** argv; +static void perform_an_assembly_pass(argc, argv) +int argc; +char **argv; { - char * buffer; /* Where each bufferful of lines will start. */ - void read_a_source_file(); int saw_a_file = 0; - + 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; - need_pass_2 = FALSE; + bss_fix_root = NULL; + + subseg_new (SEG_TEXT, 0); +#endif /* not MANY_SEGMENTS */ - argv++; /* skip argv[0] */ - argc--; /* skip argv[0] */ + argv++; /* skip argv[0] */ + argc--; /* skip argv[0] */ while (argc--) { - if (*argv) { /* Is it a file-name argument? */ - /* argv -> "" if stdin desired, else -> filename */ - if (buffer = input_scrub_new_file (*argv) ) { - saw_a_file++; - read_a_source_file(buffer); - } + 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 */ + argv++; /* completed that argv */ } - if(!saw_a_file) - if(buffer = input_scrub_new_file("") ) - read_a_source_file(buffer); -} + if (!saw_a_file) + read_a_source_file(""); +} /* perform_an_assembly_pass() */ /* * stralloc() @@ -292,33 +387,43 @@ char ** argv; * Return the address of the new string. Die if there is any error. */ -char * -stralloc (str) +static char * + stralloc (str) char * str; { register char * retval; - register long int len; - + register long len; + len = strlen (str) + 1; retval = xmalloc (len); - (void)strcpy (retval, str); - return (retval); + (void) strcpy(retval, str); + return(retval); } -lose() -{ - as_fatal( "%s: 2nd pass not implemented - get your code from random(3)",myname ); -} - -SIGTY -got_sig(sig) +#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); + + as_bad("Interrupted by signal %d", sig); + if (here_before++) + exit(1); + return((SIGTY) 0); } -/* end: as.c */ +/* + * 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 index 8de4052..7b1e27d 100644 --- a/gnu/usr.bin/as/as.h +++ b/gnu/usr.bin/as/as.h @@ -1,76 +1,86 @@ /* as.h - global header file - Copyright (C) 1987 Free Software Foundation, Inc. + 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 file is part of GAS, the GNU Assembler. +/* + * $Id: as.h,v 1.3 1993/10/02 20:57:16 pk Exp $ + */ -GAS is free software; you can 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. +#define GAS 1 +/* #include <ansidecl.h> */ +#include "host.h" +#include "flonum.h" -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +#if __STDC__ != 1 +#define volatile /**/ +#ifndef const +#define const /**/ +#endif /* const */ +#endif /* __STDC__ */ -You should have received a copy of the GNU General 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 __GNUC__ +#define alloca __builtin_alloca +#define register +#endif /* __GNUC__ */ -#ifndef asH -#define asH /* Don't declare things twice. */ +#ifndef __LINE__ +#define __LINE__ "unknown" +#endif /* __LINE__ */ -#if !defined(__STDC__) && !defined(const) -#define const /* ignore */ -#endif - -#ifdef USG -#define index strchr -#define bzero(s,n) memset((s),0,(n)) -#define bcopy(from,to,n) memcpy((to),(from),(n)) -#define setbuffer(a,b,c) -#endif +#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 DUMP to include data-structure dumpers. * #define COMMON as "extern" for all modules except one, where you #define * COMMON as "". * If TEST is #defined, then we are testing a module: #define COMMON as "". */ - - /* These #defines are for parameters of entire assembler. */ /* #define SUSPECT JF remove for speed testing */ -/* #define DUMP */ -#define NDEBUG /* JF disable asserts */ /* These #includes are for type definitions etc. */ -/* #include "style.h" */ #include <stdio.h> #include <assert.h> -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free xfree +#include <string.h> -/* These defines are potentially useful */ -#define FALSE (0) -#define TRUE (!FALSE) -#define ASSERT assert -#define BAD_CASE(value) \ -{ \ - as_fatal ("Case value %d unexpected at line %d of file \"%s\"\n", \ - value, __LINE__, __FILE__); \ -} +#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 */ @@ -83,21 +93,17 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define COMMON extern /* our commons live elswhere */ #endif #endif - /* COMMON now defined */ - -#ifdef SUSPECT -#define register /* no registers: helps debugging */ -#define know(p) ASSERT(p) /* know() is less ugly than #ifdef SUSPECT/ */ - /* assert()/#endif. */ +/* 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 /* #ifdef SUSPECT */ - - -char *xmalloc(); /* keep C compilers happy */ -char *xrealloc(); /* " */ -void free(); /* " */ -#define xfree free +#endif /* input_scrub.c */ @@ -106,18 +112,6 @@ void free(); /* " */ * Also understands printing line-number part of error messages. */ - /* Line number things. */ -int seen_at_least_1_file(); -void bump_line_counters(); -void new_logical_line(); -void as_where(); -void as_perror(); -void as_howmuch(); - /* Sanitising things. */ -void input_scrub_begin(); -void input_scrub_end(); -char *input_scrub_new_file(); -char *input_scrub_next_buffer(); /* subsegs.c Sub-segments. Also, segment(=expression type)s.*/ @@ -125,7 +119,7 @@ char *input_scrub_next_buffer(); * This table describes the use of segments as EXPRESSION types. * * X_seg X_add_symbol X_subtract_symbol X_add_number - * SEG_NONE no (legal) expression + * SEG_ABSENT no (legal) expression * SEG_PASS1 no (defined) " * SEG_BIG * > 32 bits const. * SEG_ABSOLUTE 0 @@ -134,6 +128,7 @@ char *input_scrub_next_buffer(); * 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. @@ -149,69 +144,81 @@ char *input_scrub_next_buffer(); * X_add_symbol != X_sub_symbol (then we just cancel them, => SEG_ABSOLUTE). */ -typedef enum -{ - SEG_ABSOLUTE, - SEG_TEXT, - SEG_DATA, - SEG_BSS, + +#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_NONE, /* Mythical Segment: NO expression seen. */ + 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. */ -} segT; -#define SEG_MAXIMUM_ORDINAL (SEG_DIFFERENCE) + /* 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; -typedef unsigned char subsegT; +#define SEG_MAXIMUM_ORDINAL (SEG_REGISTER) + +typedef int subsegT; COMMON subsegT now_subseg; - /* What subseg we are accreting now? */ +/* What subseg we are accreting now? */ COMMON segT now_seg; - /* Segment our instructions emit to. */ - /* Only OK values are SEG_TEXT or SEG_DATA. */ +/* Segment our instructions emit to. */ +/* Only OK values are SEG_TEXT or SEG_DATA. */ extern char *const seg_name[]; -extern const int seg_N_TYPE[]; -extern const segT N_TYPE_seg[]; -void subsegs_begin(); -void subseg_change(); -void subseg_new(); - -/* relax() */ +extern int section_alignment[]; -typedef enum -{ - rs_fill, /* Variable chars to be repeated fr_offset */ - /* times. Fr_symbol unused. */ - /* Used with fr_offset == 0 for a constant */ - /* length frag. */ - rs_align, /* Align: Fr_offset: power of 2. */ - /* 1 variable char: fill character. */ - rs_org, /* Org: Fr_offset, fr_symbol: address. */ - /* 1 variable char: fill character. */ +/* 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; +} relax_stateT; /* typedef unsigned char relax_substateT; */ /* JF this is more likely to leave the end of a struct frag on an align boundry. Be very careful with this. */ -typedef unsigned long int relax_substateT; +typedef unsigned long relax_substateT; -typedef unsigned long int relax_addressT;/* Enough bits for address. */ - /* Still an integer type. */ +typedef unsigned long relax_addressT;/* Enough bits for address. */ +/* Still an integer type. */ /* frags.c */ @@ -227,66 +234,183 @@ typedef unsigned long int relax_addressT;/* Enough bits for address. */ * of the 1st char of a frag is generally not known until after relax(). * Many things at assembly time describe an address by {object-file-address * of a particular frag}+offset. - + BUG: it may be smarter to have a single pointer off to various different -notes for different frag kinds. See how code pans out. - - + notes for different frag kinds. See how code pans */ struct frag /* a code fragment */ { - long unsigned int fr_address; /* Object file address. */ + unsigned long fr_address; /* Object file address. */ struct frag *fr_next; /* Chain forward; ascending address order. */ - /* Rooted in frch_root. */ - - long int fr_fix; /* (Fixed) number of chars we know we have. */ - /* May be 0. */ - long int fr_var; /* (Variable) number of chars after above. */ - /* May be 0. */ + /* 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 int fr_offset; /* 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 */ + /* These are needed only on the NS32K machines */ char fr_pcrel_adjust; char fr_bsr; - char fr_literal [1]; /* Chars begin here. */ - /* One day we will compile fr_literal[0]. */ +#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. */ +((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 *frag_now; /* -> current frag we are building. */ +/* This frag is incomplete. */ +/* It is, however, included in frchain_now. */ +/* Frag_now->fr_fix is bogus. Use: */ +/* Virtual frag_now->fr_fix == obstack_next_free(&frags)-frag_now->fr_literal.*/ COMMON fragS zero_address_frag; /* For foreign-segment symbol fixups. */ COMMON fragS bss_address_frag; /* For local common (N_BSS segment) fixups. */ -void frag_new(); -char * frag_more(); -char * frag_var(); -void frag_wane(); -void frag_align(); - - /* main program "as.c" (command arguments etc) */ COMMON char -flagseen[128]; /* ['x'] TRUE if "-x" seen. */ + flagseen[128]; /* ['x'] TRUE if "-x" seen. */ COMMON char * -out_file_name; /* name of emitted object file */ + 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) -#endif /* #ifdef asH */ +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: as.h */ +/* end of as.h */ diff --git a/gnu/usr.bin/as/atof-generic.c b/gnu/usr.bin/as/atof-generic.c index 4975410..b4e0971 100644 --- a/gnu/usr.bin/as/atof-generic.c +++ b/gnu/usr.bin/as/atof-generic.c @@ -1,24 +1,31 @@ /* atof_generic.c - turn a string of digits into a Flonum - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. + 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.3 1993/10/02 20:57:17 pk Exp $"; +#endif -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +#include <ctype.h> +#include <string.h> -You should have received a copy of the GNU General 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 <ctype.h> -#include "flonum.h" #ifdef __GNUC__ #define alloca __builtin_alloca #else @@ -27,500 +34,493 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #endif #endif -#ifdef USG -#define bzero(s,n) memset(s,0,n) -#define index strchr -#endif - -#define FALSE (0) -#define TRUE (1) - -char *index(); +/* #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 int * -* * -\***********************************************************************/ + * * + * 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"} + + */ - 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; - + atof_generic ( + address_of_string_pointer, /* return pointer to just + AFTER number we read. */ + string_of_decimal_marks, /* At most one per number. */ + string_of_decimal_exponent_marks, + address_of_generic_floating_point_number) +char **address_of_string_pointer; +const char *string_of_decimal_marks; +const char *string_of_decimal_exponent_marks; +FLONUM_TYPE *address_of_generic_floating_point_number; { - - int return_value; /* 0 means OK. */ - char * first_digit; - /* char * last_digit; JF unused */ - int number_of_digits_before_decimal; - int number_of_digits_after_decimal; - long int decimal_exponent; - int number_of_digits_available; - char digits_sign_char; - - { - /* - * Scan the input string, abstracting (1)digits (2)decimal mark (3) exponent. - * It would be simpler to modify the string, but we don't; just to be nice - * to caller. - * We need to know how many digits we have, so we can allocate space for - * the digits' value. - */ - - char * p; - char c; - int seen_significant_digit; - - first_digit = * address_of_string_pointer; - c= *first_digit; - if (c=='-' || c=='+') - { - digits_sign_char = c; - first_digit ++; - } - else - digits_sign_char = '+'; - - if( (first_digit[0]=='n' || first_digit[0]=='N') - && (first_digit[1]=='a' || first_digit[1]=='A') - && (first_digit[2]=='n' || first_digit[2]=='N')) { - address_of_generic_floating_point_number->sign=0; - address_of_generic_floating_point_number->exponent=0; - address_of_generic_floating_point_number->leader=address_of_generic_floating_point_number->low; - (*address_of_string_pointer)=first_digit+3; - return 0; - } - if( (first_digit[0]=='i' || first_digit[0]=='I') - && (first_digit[1]=='n' || first_digit[1]=='N') - && (first_digit[2]=='f' || first_digit[2]=='F')) { - address_of_generic_floating_point_number->sign= digits_sign_char=='+' ? 'P' : 'N'; - address_of_generic_floating_point_number->exponent=0; - address_of_generic_floating_point_number->leader=address_of_generic_floating_point_number->low; - if( (first_digit[3]=='i' || first_digit[3]=='I') - && (first_digit[4]=='n' || first_digit[4]=='N') - && (first_digit[5]=='i' || first_digit[5]=='I') - && (first_digit[6]=='t' || first_digit[6]=='T') - && (first_digit[7]=='y' || first_digit[7]=='Y')) - (*address_of_string_pointer)=first_digit+8; - else - (*address_of_string_pointer)=first_digit+3; - return 0; - } - - number_of_digits_before_decimal = 0; - number_of_digits_after_decimal = 0; - decimal_exponent = 0; - seen_significant_digit = FALSE; - for (p = first_digit; - (c = * p) - && (!c || ! index (string_of_decimal_marks, c) ) - && (!c || ! index (string_of_decimal_exponent_marks, c) ); - p ++) - { - if (isdigit(c)) - { - if (seen_significant_digit || c > '0') - { - number_of_digits_before_decimal ++; - seen_significant_digit = TRUE; - } - else - { - first_digit++; - } - } - else - { - break; /* p -> char after pre-decimal digits. */ - } - } /* For each digit before decimal mark. */ - if (c && index (string_of_decimal_marks, c)) - { - for (p ++; - (c = * p) - && (!c || ! index (string_of_decimal_exponent_marks, c) ); - p ++) - { - if (isdigit(c)) - { - number_of_digits_after_decimal ++; /* This may be retracted below. */ - if (/* seen_significant_digit || */ c > '0') - { - seen_significant_digit = TRUE; - } - } - else - { - if ( ! seen_significant_digit) - { - number_of_digits_after_decimal = 0; - } - break; - } - } /* For each digit after decimal mark. */ - } - while(number_of_digits_after_decimal && first_digit[number_of_digits_before_decimal+number_of_digits_after_decimal]=='0') - --number_of_digits_after_decimal; -/* last_digit = p; JF unused */ - - if (c && index (string_of_decimal_exponent_marks, c) ) - { - char digits_exponent_sign_char; + 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; - c = * ++ p; - if (c && index ("+-",c)) - { - digits_exponent_sign_char = c; - c = * ++ p; - } - else - { - digits_exponent_sign_char = '+'; - } - for (; - (c); - c = * ++ p) - { - if (isdigit(c)) - { - decimal_exponent = decimal_exponent * 10 + c - '0'; - /* - * BUG! If we overflow here, we lose! - */ - } - else - { - break; - } - } - if (digits_exponent_sign_char == '-') - { - decimal_exponent = - decimal_exponent; - } - } - * address_of_string_pointer = p; - } - - number_of_digits_available = - number_of_digits_before_decimal - + number_of_digits_after_decimal; - return_value = 0; - if (number_of_digits_available == 0) - { - address_of_generic_floating_point_number -> exponent = 0; /* Not strictly necessary */ - address_of_generic_floating_point_number -> leader - = -1 + address_of_generic_floating_point_number -> low; - address_of_generic_floating_point_number -> sign = digits_sign_char; - /* We have just concocted (+/-)0.0E0 */ - } - else - { - LITTLENUM_TYPE * digits_binary_low; - int precision; - int maximum_useful_digits; - int number_of_digits_to_use; - int more_than_enough_bits_for_digits; - int more_than_enough_littlenums_for_digits; - int size_of_digits_in_littlenums; - int size_of_digits_in_chars; - FLONUM_TYPE power_of_10_flonum; - FLONUM_TYPE digits_flonum; - - - precision = (address_of_generic_floating_point_number -> high - - address_of_generic_floating_point_number -> low - + 1 - ); /* Number of destination littlenums. */ - /* Includes guard bits (two littlenums worth) */ - maximum_useful_digits = ( ((double) (precision - 2)) - * ((double) (LITTLENUM_NUMBER_OF_BITS)) - / (LOG_TO_BASE_2_OF_10) - ) - + 2; /* 2 :: guard digits. */ - if (number_of_digits_available > maximum_useful_digits) - { - number_of_digits_to_use = maximum_useful_digits; + /* + * 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); } - else - { - number_of_digits_to_use = number_of_digits_available; + + /* 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); } - decimal_exponent += number_of_digits_before_decimal - number_of_digits_to_use; - - more_than_enough_bits_for_digits - = ((((double)number_of_digits_to_use) * LOG_TO_BASE_2_OF_10) + 1); - more_than_enough_littlenums_for_digits - = ( more_than_enough_bits_for_digits - / LITTLENUM_NUMBER_OF_BITS - ) - + 2; - - /* - * Compute (digits) part. In "12.34E56" this is the "1234" part. - * Arithmetic is exact here. If no digits are supplied then - * this part is a 0 valued binary integer. - * Allocate room to build up the binary number as littlenums. - * We want this memory to disappear when we leave this function. - * Assume no alignment problems => (room for n objects) == - * n * (room for 1 object). - */ - - size_of_digits_in_littlenums = more_than_enough_littlenums_for_digits; - size_of_digits_in_chars = size_of_digits_in_littlenums - * sizeof( LITTLENUM_TYPE ); - digits_binary_low = (LITTLENUM_TYPE *) - alloca (size_of_digits_in_chars); - bzero ((char *)digits_binary_low, size_of_digits_in_chars); - /* Digits_binary_low[] is allocated and zeroed. */ - - { - /* - * Parse the decimal digits as if * digits_low was in the units position. - * Emit a binary number into digits_binary_low[]. - * - * Use a large-precision version of: - * (((1st-digit) * 10 + 2nd-digit) * 10 + 3rd-digit ...) * 10 + last-digit + 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; - char * p; - char c; - int count; /* Number of useful digits left to scan. */ - for (p = first_digit, count = number_of_digits_to_use; - count; - p ++, -- count) - { - c = * p; - if (isdigit(c)) - { + + 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; + /* - * Multiply by 10. Assume can never overflow. - * Add this digit to digits_binary_low[]. + * 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). */ - - long int carry; - LITTLENUM_TYPE * littlenum_pointer; - LITTLENUM_TYPE * littlenum_limit; - - littlenum_limit - = digits_binary_low - + more_than_enough_littlenums_for_digits - - 1; - carry = c - '0'; /* char -> binary */ - for (littlenum_pointer = digits_binary_low; - littlenum_pointer <= littlenum_limit; - littlenum_pointer ++) - { - long int work; - - work = carry + 10 * (long)(*littlenum_pointer); - * littlenum_pointer = work & LITTLENUM_MASK; - carry = work >> LITTLENUM_NUMBER_OF_BITS; - } - if (carry != 0) - { - /* - * We have a GROSS internal error. - * This should never happen. - */ - abort(); /* RMS prefers abort() to any message. */ - } - } - else - { - ++ count; /* '.' doesn't alter digits used count. */ - } /* if valid digit */ - } /* for each digit */ - } - - /* - * Digits_binary_low[] properly encodes the value of the digits. - * Forget about any high-order littlenums that are 0. - */ - while (digits_binary_low [size_of_digits_in_littlenums - 1] == 0 - && size_of_digits_in_littlenums >= 2) - size_of_digits_in_littlenums --; - - digits_flonum . low = digits_binary_low; - digits_flonum . high = digits_binary_low + size_of_digits_in_littlenums - 1; - digits_flonum . leader = digits_flonum . high; - digits_flonum . exponent = 0; - /* - * The value of digits_flonum . sign should not be important. - * We have already decided the output's sign. - * We trust that the sign won't influence the other parts of the number! - * So we give it a value for these reasons: - * (1) courtesy to humans reading/debugging - * these numbers so they don't get excited about strange values - * (2) in future there may be more meaning attached to sign, - * and what was - * harmless noise may become disruptive, ill-conditioned (or worse) - * input. - */ - digits_flonum . sign = '+'; - - { - /* - * Compute the mantssa (& exponent) of the power of 10. - * If sucessful, then multiply the power of 10 by the digits - * giving return_binary_mantissa and return_binary_exponent. - */ - - LITTLENUM_TYPE *power_binary_low; - int decimal_exponent_is_negative; - /* This refers to the "-56" in "12.34E-56". */ - /* FALSE: decimal_exponent is positive (or 0) */ - /* TRUE: decimal_exponent is negative */ - FLONUM_TYPE temporary_flonum; - LITTLENUM_TYPE *temporary_binary_low; - int size_of_power_in_littlenums; - int size_of_power_in_chars; - - size_of_power_in_littlenums = precision; -/* Precision has a built-in fudge factor so we get a few guard bits. */ - - - decimal_exponent_is_negative = decimal_exponent < 0; - if (decimal_exponent_is_negative) - { - decimal_exponent = - decimal_exponent; - } - /* From now on: the decimal exponent is > 0. Its sign is seperate. */ - - size_of_power_in_chars - = size_of_power_in_littlenums - * sizeof( LITTLENUM_TYPE ) + 2; - power_binary_low = (LITTLENUM_TYPE *) alloca ( size_of_power_in_chars ); - temporary_binary_low = (LITTLENUM_TYPE *) alloca ( size_of_power_in_chars ); - bzero ((char *)power_binary_low, size_of_power_in_chars); - * power_binary_low = 1; - power_of_10_flonum . exponent = 0; - power_of_10_flonum . low = power_binary_low; - power_of_10_flonum . leader = power_binary_low; - power_of_10_flonum . high = power_binary_low + size_of_power_in_littlenums - 1; - power_of_10_flonum . sign = '+'; - temporary_flonum . low = temporary_binary_low; - temporary_flonum . high = temporary_binary_low + size_of_power_in_littlenums - 1; - /* - * (power) == 1. - * Space for temporary_flonum allocated. - */ - - /* - * ... - * - * WHILE more bits - * DO find next bit (with place value) - * multiply into power mantissa - * OD - */ - { - int place_number_limit; + + 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 - { + 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'); + 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 */ + 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'); + printf(" after computing power_of_10_flonum: "); + flonum_print(&power_of_10_flonum ); + (void) putchar('\n'); #endif - } - - } - - /* - * power_of_10_flonum is power of ten in binary (mantissa) , (exponent). - * It may be the number 1, in which case we don't NEED to multiply. - * - * Multiply (decimal digits) by power_of_10_flonum. - */ - - flonum_multip (& power_of_10_flonum, & digits_flonum, address_of_generic_floating_point_number); - /* Assert sign of the number we made is '+'. */ - address_of_generic_floating_point_number -> sign = digits_sign_char; - - } /* If we had any significant digits. */ - return (return_value); -} /* atof_generic () */ - -/* end: atof_generic.c */ + } + + } + + /* + * 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 index 2640121..08c92f8 100644 --- a/gnu/usr.bin/as/bignum-copy.c +++ b/gnu/usr.bin/as/bignum-copy.c @@ -1,29 +1,28 @@ /* bignum_copy.c - copy a bignum - Copyright (C) 1987 Free Software Foundation, Inc. + 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 file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "bignum.h" - -#ifdef USG -#define bzero(s,n) memset(s,0,n) -#define bcopy(from,to,n) memcpy(to,from,n) +#ifndef lint +static char rcsid[] = "$Id: bignum-copy.c,v 1.3 1993/10/02 20:57:18 pk Exp $"; #endif +#include "as.h" + /* * bignum_copy () * @@ -31,45 +30,47 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ * If the output is shorter than the input, copy lower-order littlenums. * Return 0 or the number of significant littlenums dropped. * Assumes littlenum arrays are densely packed: no unused chars between - * the littlenums. Uses bcopy() to move littlenums, and wants to + * 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 */ + bignum_copy(in, in_length, out, out_length) +register LITTLENUM_TYPE *in; +register int in_length; /* in sizeof(littlenum)s */ +register LITTLENUM_TYPE *out; +register int out_length; /* in sizeof(littlenum)s */ { - register int significant_littlenums_dropped; + 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) - { - register LITTLENUM_TYPE * p; /* -> most significant (non-zero) input littlenum. */ + if (out_length > in_length) { + memset((char *) (out + out_length), + '\0', (out_length - in_length) << LITTLENUM_SHIFT); + } - bcopy ((char *)in, (char *)out, out_length << LITTLENUM_SHIFT); - for (p = in + in_length - 1; p >= in; -- p) - { - if (* p) break; - } - significant_littlenums_dropped = p - in - in_length + 1; - if (significant_littlenums_dropped < 0) - { - significant_littlenums_dropped = 0; - } - } - else - { - bcopy ((char *)in, (char *)out, in_length << LITTLENUM_SHIFT); - if (out_length > in_length) - { - bzero ((char *)(out + out_length), (out_length - in_length) << LITTLENUM_SHIFT); + significant_littlenums_dropped = 0; } - significant_littlenums_dropped = 0; - } - return (significant_littlenums_dropped); -} + + return(significant_littlenums_dropped); +} /* bignum_copy() */ -/* end: bignum_copy.c */ +/* end of bignum-copy.c */ diff --git a/gnu/usr.bin/as/bignum.h b/gnu/usr.bin/as/bignum.h index dbc95a3..d95ca9a 100644 --- a/gnu/usr.bin/as/bignum.h +++ b/gnu/usr.bin/as/bignum.h @@ -1,33 +1,37 @@ /* bignum.h-arbitrary precision integers - Copyright (C) 1987 Free Software Foundation, Inc. + 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 part of GAS, the GNU Assembler. - -GAS is free software; you can 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: bignum.h,v 1.3 1993/10/02 20:57:19 pk 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. * -* * -\***********************************************************************/ + * * + * 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) @@ -38,11 +42,23 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define BITS_PER_CHAR (8) #endif -typedef unsigned short int LITTLENUM_TYPE; - +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! */ +#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: bignum.h */ +/* 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 0000000..e72d6d6 --- /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/10/02 20:57:19 pk 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 0000000..ad98201 --- /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/10/02 20:57:20 pk 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 0000000..48e2e49 --- /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 0000000..4261d35 --- /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.4 1993/10/16 03:23:04 cgd 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 index 945246b..bbae017 100644 --- a/gnu/usr.bin/as/config/Makefile.i386 +++ b/gnu/usr.bin/as/config/Makefile.i386 @@ -1,4 +1,5 @@ -# @(#)Makefile.i386 6.1 (Berkeley) 3/3/91 +# from: @(#)Makefile.i386 6.1 (Berkeley) 3/3/91 +# $Id: Makefile.i386,v 1.3 1993/10/02 20:58:21 pk Exp $ CFLAGS+= -DNON_BROKEN_WORDS -SRCS+= i386.c atof-ieee.c +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 0000000..d4b22ab --- /dev/null +++ b/gnu/usr.bin/as/config/Makefile.pc532 @@ -0,0 +1,7 @@ +# $Id: Makefile.pc532,v 1.1 1993/10/16 03:23:37 cgd 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 0000000..c9d9af1 --- /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/10/02 20:58:22 pk 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 0000000..f62b087 --- /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.3 1993/10/02 20:58:23 pk 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 0000000..4c9863b --- /dev/null +++ b/gnu/usr.bin/as/config/aout.h @@ -0,0 +1,424 @@ +/* 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, + +#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 index 6ff45c8..18941cc 100644 --- a/gnu/usr.bin/as/config/atof-ieee.c +++ b/gnu/usr.bin/as/config/atof-ieee.c @@ -1,177 +1,188 @@ /* atof_ieee.c - turn a Flonum into an IEEE floating point number - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "flonum.h" -#ifdef USG -#define bzero(s,n) memset(s,0,n) -#define bcopy(from,to,n) memcpy((to),(from),(n)) + 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.3 1993/10/02 20:58:25 pk 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. */ +/* 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. */ +/* Length in LittleNums of guard bits. */ #define GUARD (2) -static unsigned long int mask [] = { - 0x00000000, - 0x00000001, - 0x00000003, - 0x00000007, - 0x0000000f, - 0x0000001f, - 0x0000003f, - 0x0000007f, - 0x000000ff, - 0x000001ff, - 0x000003ff, - 0x000007ff, - 0x00000fff, - 0x00001fff, - 0x00003fff, - 0x00007fff, - 0x0000ffff, - 0x0001ffff, - 0x0003ffff, - 0x0007ffff, - 0x000fffff, - 0x001fffff, - 0x003fffff, - 0x007fffff, - 0x00ffffff, - 0x01ffffff, - 0x03ffffff, - 0x07ffffff, - 0x0fffffff, - 0x1fffffff, - 0x3fffffff, - 0x7fffffff, - 0xffffffff - }; +static 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 LITTLENUM_TYPE *littlenum_pointer; static int -next_bits (number_of_bits) - int number_of_bits; + 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); + int return_value; + + if (!littlenums_left) + return(0); + if (number_of_bits >= bits_left_in_littlenum) { + return_value = mask[bits_left_in_littlenum] & *littlenum_pointer; + number_of_bits -= bits_left_in_littlenum; + return_value <<= number_of_bits; + + if (--littlenums_left) { + bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits; + --littlenum_pointer; + return_value |= (*littlenum_pointer >> bits_left_in_littlenum) & mask[number_of_bits]; + } + } else { + bits_left_in_littlenum -= number_of_bits; + return_value = mask[number_of_bits] & (*littlenum_pointer >> bits_left_in_littlenum); + } + return(return_value); } /* Num had better be less than LITTLENUM_NUMBER_OF_BITS */ -static int -unget_bits(num) +static void + unget_bits(num) +int num; { - if(!littlenums_left) { + 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); + 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; + bits_left_in_littlenum += num; } static void -make_invalid_floating_point_number (words) - LITTLENUM_TYPE * words; + make_invalid_floating_point_number(words) +LITTLENUM_TYPE *words; { - as_warn("cannot create floating-point number"); - words[0]= ((unsigned)-1)>>1; /* Zero the leftmost bit */ - words[1]= -1; - words[2]= -1; - words[3]= -1; - words[4]= -1; - words[5]= -1; + 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! * -* * -\***********************************************************************/ + * 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. */ + atof_ieee(str, what_kind, words) +char *str; /* Text to convert to binary. */ +char what_kind; /* 'd', 'f', 'g', 'h' */ +LITTLENUM_TYPE *words; /* Build the binary here. */ { - static LITTLENUM_TYPE bits [MAX_PRECISION + MAX_PRECISION + GUARD]; - /* Extra bits for zeroed low-order bits. */ - /* The 1st MAX_PRECISION are zeroed, */ - /* the last contain flonum bits. */ - char * return_value; - int precision; /* Number of 16-bit words in the format. */ - long int exponent_bits; - + 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. */ - - bzero (bits, sizeof(LITTLENUM_TYPE) * MAX_PRECISION); - - switch(what_kind) { + + /* 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': @@ -179,7 +190,7 @@ atof_ieee (str, what_kind, words) precision = F_PRECISION; exponent_bits = 8; break; - + case 'd': case 'D': case 'r': @@ -187,7 +198,7 @@ atof_ieee (str, what_kind, words) precision = D_PRECISION; exponent_bits = 11; break; - + case 'x': case 'X': case 'e': @@ -195,111 +206,115 @@ atof_ieee (str, what_kind, words) precision = X_PRECISION; exponent_bits = 15; break; - + case 'p': case 'P': precision = P_PRECISION; - exponent_bits= -1; + exponent_bits = -1; break; - + default: - make_invalid_floating_point_number (words); - return NULL; + make_invalid_floating_point_number(words); + return(NULL); } - + generic_floating_point_number.high = generic_floating_point_number.low + precision - 1 + GUARD; - - if (atof_generic (& return_value, ".", EXP_CHARS, & generic_floating_point_number)) { - /* as_warn("Error converting floating point number (Exponent overflow?)"); */ - make_invalid_floating_point_number (words); - return NULL; + + if (atof_generic(&return_value, ".", EXP_CHARS, &generic_floating_point_number)) { + /* as_bad("Error converting floating point number (Exponent overflow?)"); */ + make_invalid_floating_point_number(words); + return(NULL); } gen_to_words(words, precision, exponent_bits); - return return_value; + + /* 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 */ -gen_to_words(words,precision,exponent_bits) +int gen_to_words(words, precision, exponent_bits) LITTLENUM_TYPE *words; -long int exponent_bits; int precision; +long 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; - + 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; + if (generic_floating_point_number.sign == '+') + words[0] = 0x0000; else - words[0]=0x8000; - bzero (&words[1], sizeof(LITTLENUM_TYPE) * (precision-1)); - return return_value; + 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; + 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; + words[0] = 0x7fff; + words[1] = 0xffff; + words[2] = 0xffff; + words[3] = 0xffff; } return return_value; - } else if(generic_floating_point_number.sign=='P') { + } else if (generic_floating_point_number.sign == 'P') { /* +INF: Do the right thing */ - if(precision==F_PRECISION) { - words[0]=0x7f80; - words[1]=0; + if (precision == F_PRECISION) { + words[0] = 0x7f80; + words[1] = 0; } else { - words[0]=0x7ff0; - words[1]=0; - words[2]=0; - words[3]=0; + words[0] = 0x7ff0; + words[1] = 0; + words[2] = 0; + words[3] = 0; } - return return_value; - } else if(generic_floating_point_number.sign=='N') { + return(return_value); + } else if (generic_floating_point_number.sign == 'N') { /* Negative INF */ - if(precision==F_PRECISION) { - words[0]=0xff80; - words[1]=0x0; + if (precision == F_PRECISION) { + words[0] = 0xff80; + words[1] = 0x0; } else { - words[0]=0xfff0; - words[1]=0x0; - words[2]=0x0; - words[3]=0x0; + words[0] = 0xfff0; + words[1] = 0x0; + words[2] = 0x0; + words[3] = 0x0; } - return return_value; + 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. - */ + /* + * 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; + 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; + 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. */ @@ -307,152 +322,151 @@ int precision; /* 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)); - + 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) { + 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) { + 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) { + 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; + return(return_value); } - if(precision==X_PRECISION && exponent_bits==15) { - *lp++=0; - *lp++=0; - num_bits-=LITTLENUM_NUMBER_OF_BITS-1; + 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; + 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)); + 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; + 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; + *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; + 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); - + 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)) { + if (next_bits(1)) { --lp; - if(prec_bits>LITTLENUM_NUMBER_OF_BITS) { + 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 = 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; + tmp_bits -= LITTLENUM_NUMBER_OF_BITS; } - if(tmp_bits>LITTLENUM_NUMBER_OF_BITS || (lp[n]&mask[tmp_bits])!=mask[tmp_bits]) { - unsigned long int carry; - + 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 = *lp + carry; + *lp = carry; carry >>= LITTLENUM_NUMBER_OF_BITS; } } - } else if((*lp&mask[prec_bits])!=mask[prec_bits]) - lp++; + } 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. - */ + } 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); + word1 |= (exponent_4 << ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits)) + | next_bits ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits); } - - * lp ++ = word1; - + + *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); + if (exponent_bits == 15 && precision == X_PRECISION) { + *lp++ = 0; + *lp++ = 1 << (LITTLENUM_NUMBER_OF_BITS) | next_bits(LITTLENUM_NUMBER_OF_BITS - 1); } - + /* The rest of the words are just mantissa bits. */ - while(lp < words + precision) - *lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS); - - if (next_bits (1)) { - unsigned long int carry; - /* - * Since the NEXT bit is a 1, round UP the mantissa. - * The cunning design of these hidden-1 floats permits - * us to let the mantissa overflow into the exponent, and - * it 'does the right thing'. However, we lose if the - * highest-order bit of the lowest-order word flips. - * Is that clear? - */ - - -/* #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2) - Please allow at least 1 more bit in carry than is in a LITTLENUM. - We need that extra bit to hold a carry during a LITTLENUM carry - propagation. Another extra bit (kept 0) will assure us that we - don't get a sticky sign bit after shifting right, and that - permits us to propagate the carry without any masking of bits. -#endif */ - for (carry = 1, lp --; carry && (lp >= words); lp --) { - carry = * lp + carry; - * lp = carry; + 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)) ) { + 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)); + *words &= ~(1 << (LITTLENUM_NUMBER_OF_BITS - 1)); /* make_invalid_floating_point_number (words); */ /* return return_value; */ } @@ -463,23 +477,23 @@ int precision; /* 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) + 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?)"); + 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) + print_gen(gen) FLONUM_TYPE *gen; { FLONUM_TYPE f; @@ -487,19 +501,24 @@ FLONUM_TYPE *gen; double dv; float fv; static char sbuf[40]; - - if(gen) { - f=generic_floating_point_number; - generic_floating_point_number= *gen; + + if (gen) { + f = generic_floating_point_number; + generic_floating_point_number = *gen; } - gen_to_words(&arr[0],4,11); - bcopy(&arr[0],&dv,sizeof(double)); - sprintf(sbuf,"%x %x %x %x %.14G ",arr[0],arr[1],arr[2],arr[3],dv); - gen_to_words(&arr[0],2,8); - bcopy(&arr[0],&fv,sizeof(float)); - sprintf(sbuf+strlen(sbuf),"%x %x %.12g\n",arr[0],arr[1],fv); - if(gen) - generic_floating_point_number=f; - return sbuf; + 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 0000000..cadeec0 --- /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 0000000..6425e93 --- /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 0000000..8a69502 --- /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 0000000..bcbb343 --- /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 0000000..e3819bc --- /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 0000000..2af0341 --- /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 0000000..1cab4d5 --- /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 0000000..493cfc6 --- /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 0000000..d5ff31a --- /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 0000000..6941b7e --- /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/10/02 20:58:36 pk 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 0000000..d31b51a --- /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 0000000..fe57e8e --- /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 0000000..0d68e6f --- /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 0000000..6c74df4 --- /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 0000000..cf619e8 --- /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 0000000..1193b1b --- /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 0000000..443fe3b --- /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 0000000..eee0553 --- /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 0000000..4b6680e --- /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 0000000..3375d42 --- /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 0000000..a1e5d77 --- /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 0000000..5bfcd28 --- /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 0000000..528e6fc --- /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 0000000..d968db2 --- /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 0000000..1e6eb3c --- /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 0000000..225fc36 --- /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 0000000..f40f51d --- /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 0000000..f40f51d --- /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 0000000..c0a470e --- /dev/null +++ b/gnu/usr.bin/as/config/obj-aout.c @@ -0,0 +1,604 @@ +/* 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_ignore, 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); + + /* 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() */ + +#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 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. + */ + if (symbolP->sy_size && flagseen['k']) { + symbolS *addme; +#ifdef USE_NSIZE_PREFIX /*XXX*/ + char buf[BUFSIZ]; + + /* + * Changed my mind, make name: "=symbol" + */ + buf[0] = '='; + strncpy(buf+1, S_GET_NAME(symbolP), BUFSIZ-2); + addme = symbol_make(buf); +#else + addme = symbol_make(S_GET_NAME(symbolP)); +#endif +#if 0 + S_SET_SEGMENT(addme, SEG_SIZE); +#endif + addme->sy_symbol.n_type = N_SIZE; + S_SET_VALUE(addme, symbolP->sy_size); + /* Set external if symbolP is ? */ +#if 1 + if (S_IS_EXTERN(symbolP)) + S_SET_EXTERNAL(addme); +#endif + } + 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 0000000..4c91f9d --- /dev/null +++ b/gnu/usr.bin/as/config/obj-aout.h @@ -0,0 +1,207 @@ +/* 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.1 1993/10/02 20:58:55 pk 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 */ + +/* 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 0000000..626516b --- /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 0000000..958d8a9 --- /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 0000000..f6d9302 --- /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 0000000..e28d435 --- /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 0000000..238e6c5 --- /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 0000000..9720d5e --- /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 0000000..d69c7a0 --- /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 0000000..d1afabb --- /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 0000000..a91eff9 --- /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 0000000..f370722 --- /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 0000000..5f74a5f --- /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 0000000..3baa081 --- /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 0000000..5d12387 --- /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 0000000..fec056d --- /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 0000000..84ec97a --- /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 0000000..fee1ca2 --- /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 0000000..e69de29 --- /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 0000000..181d4aa --- /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 0000000..db4786b --- /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 0000000..6da7896 --- /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 0000000..9a6e164 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-i386.c @@ -0,0 +1,2303 @@ +/* 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.3 1993/10/27 00:14:50 pk 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. + */ + long opoffset = 0; + if (flagseen['k']) + opoffset = obstack_next_free(&frags) - frag_now->fr_literal; +#endif + + /* First the prefix bytes. */ + for (q = i.prefix; q < i.prefix + i.prefixes; q++) { + p = frag_more (1); + md_number_to_chars (p, (unsigned int) *q, 1); + } + + /* Now the opcode; be careful about word order here! */ + if (fits_in_unsigned_byte(t->base_opcode)) { + FRAG_APPEND_1_CHAR (t->base_opcode); + } else if (fits_in_unsigned_word(t->base_opcode)) { + p = frag_more (2); + /* put out high byte first: can't use md_number_to_chars! */ + *p++ = (t->base_opcode >> 8) & 0xff; + *p = t->base_opcode & 0xff; + } else { /* opcode is either 3 or 4 bytes */ + if (t->base_opcode & 0xff000000) { + p = frag_more (4); + *p++ = (t->base_opcode >> 24) & 0xff; + } else p = frag_more (3); + *p++ = (t->base_opcode >> 16) & 0xff; + *p++ = (t->base_opcode >> 8) & 0xff; + *p = (t->base_opcode ) & 0xff; + } + + /* Now the modrm byte and base index byte (if present). */ + if (t->opcode_modifier & Modrm) { + p = frag_more (1); + /* md_number_to_chars (p, i.rm, 1); */ + md_number_to_chars (p, (i.rm.regmem<<0 | i.rm.reg<<3 | i.rm.mode<<6), 1); + /* If i.rm.regmem == ESP (4) && i.rm.mode != Mode 3 (Register mode) + ==> need second modrm byte. */ + if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING && i.rm.mode != 3) { + p = frag_more (1); + /* md_number_to_chars (p, i.bi, 1); */ + md_number_to_chars (p,(i.bi.base<<0 | i.bi.index<<3 | i.bi.scale<<6), 1); + } + } +#ifdef PIC + if (flagseen['k']) + opoffset = obstack_next_free(&frags) - frag_now->fr_literal - opoffset; +#endif + + 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 = opoffset; + opoffset = 0; + } +#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 = opoffset; + opoffset = 0; + } +#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_GLOB_DAT; + *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_GLOB_DAT; + *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_GLOB_DAT) + 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_GLOB_DAT: + extra_bits = (1 << 4) & 0x10; /* r_baserel */ + r_symbolnum = fixP->fx_addsy->sy_number; + if (S_IS_EXTERNAL(fixP->fx_addsy)) + extrn_bit = 1; + 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 0000000..b9ac3fe --- /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/10/02 20:59:21 pk 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 0000000..0123138 --- /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 0000000..adc0d8f --- /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 0000000..8f9091c --- /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 0000000..caad4d6 --- /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 0000000..5f70e42 --- /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 0000000..c1bb934 --- /dev/null +++ b/gnu/usr.bin/as/config/tc-m68k.c @@ -0,0 +1,3985 @@ +/* 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; + long off; + char wid; + char pcrel; + } 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) {\ + the_ins.reloc[the_ins.nrel].n= ((width) == 'B') ? (the_ins.numo*2-1) : \ + (((width) == 'b') ? ((the_ins.numo-1)*2) : (the_ins.numo*2));\ + the_ins.reloc[the_ins.nrel].add=adds((exp));\ + the_ins.reloc[the_ins.nrel].sub=subs((exp));\ + the_ins.reloc[the_ins.nrel].off=offs((exp));\ + the_ins.reloc[the_ins.nrel].wid=width;\ + the_ins.reloc[the_ins.nrel++].pcrel=pc_rel;\ + } + +#define add_frag(add,off,type) {\ + the_ins.fragb[the_ins.nfrag].fragoff=the_ins.numo;\ + the_ins.fragb[the_ins.nfrag].fadd=add;\ + the_ins.fragb[the_ins.nfrag].foff=off;\ + the_ins.fragb[the_ins.nfrag++].fragty=type;\ + } + +#define isvar(exp) ((exp) && (adds(exp) || subs(exp))) + +#define seg(exp) ((exp)->e_exp.X_seg) +#define adds(exp) ((exp)->e_exp.X_add_symbol) +#define subs(exp) ((exp)->e_exp.X_subtract_symbol) +#define offs(exp) ((exp)->e_exp.X_add_number) + + +struct 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 + + +/* 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; + 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) { + 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]) { + + case '*': + case '~': + case '%': + case ';': + case '@': + case '!': + case '&': + case '$': + case '?': + case '/': +#ifndef NO_68851 + case '|': +#endif + switch (opP->mode) { + case IMMED: + tmpreg=0x3c; /* 7.4 */ + if (strchr("bwl",s[1])) nextword=get_num(opP->con1,80); + else nextword=nextword=get_num(opP->con1,0); + if (isvar(opP->con1)) + add_fix(s[1],opP->con1,0); + switch (s[1]) { + case 'b': + if (!isbyte(nextword)) + opP->error="operand out of range"; + addword(nextword); + baseo=0; + break; + case 'w': + if (!isword(nextword)) + opP->error="operand out of range"; + addword(nextword); + baseo=0; + break; + case 'l': + addword(nextword>>16); + addword(nextword); + baseo=0; + break; + + case 'f': + baseo=2; + outro=8; + break; + case 'F': + baseo=4; + outro=11; + break; + case 'x': + baseo=6; + outro=15; + break; + case 'p': + baseo=6; + outro= -1; + break; + default: + as_fatal("Internal error: Can't decode %c%c in line %s of file \"%s\"", + *s, s[1], __LINE__, __FILE__); + } + if (!baseo) + break; + + /* We gotta put out some float */ + if (seg(opP->con1) != SEG_BIG) { + int_to_gen(nextword); + gen_to_words(words,baseo,(long 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) { + add_frag(adds(opP->con1), + offs(opP->con1), + TAB(PCLEA,SZ_UNDEF)); + break; + } else { + addword(0x0170); + add_fix('l',opP->con1,1); + } + } else + addword(0x0170); + addword(nextword>>16); + } else { + if (opP->reg == PC) + tmpreg=0x3A; /* 7.2 */ + else + tmpreg=0x28+opP->reg-ADDR; /* 5.areg */ + + if (isvar(opP->con1)) { + if (opP->reg == PC) { + add_fix('w',opP->con1,1); + } else + add_fix('w',opP->con1,0); + } + } + addword(nextword); + break; + + case 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); + 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); + opP->con1->e_exp.X_add_number+=6; + } else + add_fix(siz1 == 3 ? 'l' : 'w',opP->con1,0); + } + if (siz1 == 3) + addword(baseo>>16); + if (siz1) + addword(baseo); + + if (isvar(opP->con2)) { + if (opP->reg == PC || opP->reg == ZPC) { + add_fix(siz2 == 3 ? 'l' : 'w',opP->con2,1); + opP->con1->e_exp.X_add_number+=6; + } else + add_fix(siz2 == 3 ? 'l' : 'w',opP->con2,0); + } + if (siz2 == 3) + addword(outro>>16); + if (siz2) + addword(outro); + + break; + + case ABSL: + nextword=get_num(opP->con1,80); + switch (opP->con1->e_siz) { + default: + as_warn("Unknown size for absolute reference"); + case 0: + if (!isvar(opP->con1) && issword(offs(opP->con1))) { + tmpreg=0x38; /* 7.0 */ + addword(nextword); + break; + } + /* Don't generate pc relative code + on 68010 and 68000 */ + if (isvar(opP->con1) + && !subs(opP->con1) + && seg(opP->con1) == SEG_TEXT + && now_seg == SEG_TEXT + && 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); + + tmpreg=0x39; /* 7.1 mode */ + addword(nextword>>16); + addword(nextword); + break; + + case 2: /* Word */ + if (isvar(opP->con1)) + add_fix('w',opP->con1,0); + + tmpreg=0x38; /* 7.0 mode */ + addword(nextword); + break; + } + break; + case MSCR: + default: + as_bad("unknown/incorrect operand"); + /* abort(); */ + } + install_gen_operand(s[1],tmpreg); + break; + + case '#': + case '^': + switch (s[1]) { /* JF: I hate floating point! */ + case 'j': + tmpreg=70; + break; + case '8': + tmpreg=20; + break; + case 'C': + tmpreg=50; + break; + case '3': + default: + tmpreg=80; + break; + } + tmpreg=get_num(opP->con1,tmpreg); + if (isvar(opP->con1)) + add_fix(s[1],opP->con1,0); + switch (s[1]) { + case 'b': /* Danger: These do no check for + certain types of overflow. + user beware! */ + if (!isbyte(tmpreg)) + opP->error="out of range"; + insop(tmpreg); + if (isvar(opP->con1)) + the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2; + break; + case 'w': + if (!isword(tmpreg)) + opP->error="out of range"; + insop(tmpreg); + if (isvar(opP->con1)) + the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2; + break; + case 'l': + insop(tmpreg); /* Because of the way insop works, we put these two out backwards */ + insop(tmpreg>>16); + if (isvar(opP->con1)) + the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2; + break; + case '3': + tmpreg&=0xFF; + case '8': + case 'C': + install_operand(s[1],tmpreg); + break; + default: + as_fatal("Internal error: Unknown mode #%c in line %s of file \"%s\"", s[1], __LINE__, __FILE__); + } + break; + + case '+': + case '-': + case 'A': + case 'a': + install_operand(s[1], opP->reg - ADDR); + break; + + case 'B': + tmpreg = get_num(opP->con1, 80); + switch (s[1]) { + case 'B': + /* Needs no offsetting */ + add_fix('B', opP->con1, 1); + break; + case 'W': + /* Offset the displacement to be relative to byte disp location */ + opP->con1->e_exp.X_add_number += 2; + add_fix('w', opP->con1, 1); + 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; + /* Offset the displacement to be relative to byte disp location */ + opP->con1->e_exp.X_add_number+=4; + add_fix('l',opP->con1,1); + addword(0); + addword(0); + break; + case 'g': + 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); + } + 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); + addword(0); + addword(0); + break; + case 'c': /* Var size Coprocesssor branches */ + if (subs(opP->con1)) { + add_fix('l',opP->con1,1); + add_frag((symbolS *)0,(long)0,TAB(FBRANCH,LONG)); + } else if (adds(opP->con1)) { + add_frag(adds(opP->con1),offs(opP->con1),TAB(FBRANCH,SZ_UNDEF)); + } else { + /* add_frag((symbolS *)0,offs(opP->con1),TAB(FBRANCH,SHORT)); */ + the_ins.opcode[the_ins.numo-1]|=0x40; + add_fix('l',opP->con1,1); + addword(0); + addword(4); + } + break; + default: + as_fatal("Internal error: operand type B%c unknown in line %s of file \"%s\"", + s[1], __LINE__, __FILE__); + } + break; + + case 'C': /* Ignore it */ + break; + + case 'd': /* JF this is a kludge */ + if (opP->mode == AOFF) { + install_operand('s',opP->reg-ADDR); + } else { + char *tmpP; + + tmpP=opP->con1->e_end-2; + opP->con1->e_beg++; + opP->con1->e_end-=4; /* point to the , */ + baseo=m68k_reg_parse(&tmpP); + if (baseo<ADDR+0 || baseo>ADDR+7) { + as_bad("Unknown address reg, using A0"); + baseo=0; + } else baseo-=ADDR; + install_operand('s',baseo); + } + tmpreg=get_num(opP->con1,80); + if (!issword(tmpreg)) { + as_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 + +/* 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++) { + switch (the_ins.reloc[m].wid) { + case 'B': + n=1; + break; + case 'b': + n=1; + break; + case '3': + n=2; + break; + case 'w': + n=2; + break; + case 'l': + n=4; + break; + default: + as_fatal("Don't know how to figure width of %c in md_assemble()",the_ins.reloc[m].wid); + } + + fix_new(frag_now, + (toP-frag_now->fr_literal)-the_ins.numo*2+the_ins.reloc[m].n, + n, + the_ins.reloc[m].add, + the_ins.reloc[m].sub, + the_ins.reloc[m].off, + the_ins.reloc[m].pcrel, + NO_RELOC); + } + return; + } + + /* There's some frag hacking */ + for (n=0,fromP= &the_ins.opcode[0];n<the_ins.nfrag;n++) { + int wid; + + if (n == 0) wid=2*the_ins.fragb[n].fragoff; + else wid=2*(the_ins.numo-the_ins.fragb[n-1].fragoff); + toP=frag_more(wid); + to_beg_P=toP; + shorts_this_frag=0; + for (m=wid/2;m;--m) { + md_number_to_chars(toP,(long)(*fromP),2); + toP+=2; + fromP++; + shorts_this_frag++; + } + for (m=0;m<the_ins.nrel;m++) { + if ((the_ins.reloc[m].n) >= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */) { + the_ins.reloc[m].n-= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */; + break; + } + wid=the_ins.reloc[m].wid; + if (wid == 0) + continue; + the_ins.reloc[m].wid=0; + wid = (wid == 'b') ? 1 : (wid == 'w') ? 2 : (wid == 'l') ? 4 : 4000; + + fix_new(frag_now, + (toP-frag_now->fr_literal)-the_ins.numo*2+the_ins.reloc[m].n, + wid, + the_ins.reloc[m].add, + the_ins.reloc[m].sub, + the_ins.reloc[m].off, + the_ins.reloc[m].pcrel, + NO_RELOC); + } + /* know(the_ins.fragb[n].fadd); */ + (void)frag_var(rs_machine_dependent,10,0,(relax_substateT)(the_ins.fragb[n].fragty), + the_ins.fragb[n].fadd,the_ins.fragb[n].foff,to_beg_P); + } + n=(the_ins.numo-the_ins.fragb[n-1].fragoff); + shorts_this_frag=0; + if (n) { + toP=frag_more(n*sizeof(short)); + while (n--) { + md_number_to_chars(toP,(long)(*fromP),2); + toP+=2; + fromP++; + shorts_this_frag++; + } + } + for (m=0;m<the_ins.nrel;m++) { + int wid; + + wid=the_ins.reloc[m].wid; + if (wid == 0) + continue; + the_ins.reloc[m].wid=0; + wid = (wid == 'b') ? 1 : (wid == 'w') ? 2 : (wid == 'l') ? 4 : 4000; + + fix_new(frag_now, + (the_ins.reloc[m].n + toP-frag_now->fr_literal)-/* the_ins.numo */ shorts_this_frag*2, + wid, + the_ins.reloc[m].add, + the_ins.reloc[m].sub, + the_ins.reloc[m].off, + the_ins.reloc[m].pcrel, + NO_RELOC); + } +} + +/* This function is called once, at assembler startup time. This should + set up all the tables, etc that the MD part of the assembler needs + */ +void + md_begin() +{ + /* + * md_begin -- set up hash tables with 68000 instructions. + * similar to what the vax assembler does. ---phr + */ + /* RMS claims the thing to do is take the m68k-opcode.h table, and make + a copy of it at runtime, adding in the information we want but isn't + there. I think it'd be better to have an awk script hack the table + at compile time. Or even just xstr the table and use it as-is. But + my lord ghod hath spoken, so we do it this way. Excuse the ugly var + names. */ + + register const struct m68k_opcode *ins; + register struct 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, + NO_RELOC); + + fragP->fr_fix+=4; + ext=0; + } else if (fragP->fr_opcode[0] == 0x60) { + fragP->fr_opcode[0]= 0x4E; + fragP->fr_opcode[1]= 0xF9; /* JMP with ABSL LONG offset */ + subseg_change(SEG_TEXT, 0); + fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset,0, + NO_RELOC); + fragP->fr_fix+=4; + ext=0; + } else { + as_bad("Long branch offset not supported."); + } + } else { + fragP->fr_opcode[1]=0xff; + ext=4; + } + break; + case TAB(BCC68000,LONG): + /* only Bcc 68000 instructions can come here */ + /* change bcc into b!cc/jmp absl long */ + fragP->fr_opcode[0] ^= 0x01; /* invert bcc */ + fragP->fr_opcode[1] = 0x6; /* branch offset = 6 */ + + /* JF: these used to be fr_opcode[2,3], but they may be in a + different frag, in which case refering to them is a no-no. + Only fr_opcode[0,1] are guaranteed to work. */ + *buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */ + *buffer_address++ = 0xf9; + fragP->fr_fix += 2; /* account for jmp instruction */ + subseg_change(SEG_TEXT,0); + fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, + fragP->fr_offset,0, + NO_RELOC); + fragP->fr_fix += 4; + ext=0; + break; + case TAB(DBCC,LONG): + /* only DBcc 68000 instructions can come here */ + /* change dbcc into dbcc/jmp absl long */ + /* JF: these used to be fr_opcode[2-7], but that's wrong */ + *buffer_address++ = 0x00; /* branch offset = 4 */ + *buffer_address++ = 0x04; + *buffer_address++ = 0x60; /* put in bra pc+6 */ + *buffer_address++ = 0x06; + *buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */ + *buffer_address++ = 0xf9; + + fragP->fr_fix += 6; /* account for bra/jmp instructions */ + subseg_change(SEG_TEXT,0); + fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, + fragP->fr_offset,0, + NO_RELOC); + fragP->fr_fix += 4; + ext=0; + break; + case TAB(FBRANCH,SHORT): + know((fragP->fr_opcode[1]&0x40) == 0); + ext=2; + break; + case TAB(FBRANCH,LONG): + fragP->fr_opcode[1]|=0x40; /* Turn on LONG bit */ + ext=4; + break; + case TAB(PCREL,SHORT): + ext=2; + break; + case TAB(PCREL,LONG): + /* 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, 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, NO_RELOC); + fragP->fr_opcode[1] &= ~0x3F; + fragP->fr_opcode[1] |= 0x3A; + ext=2; + break; + case TAB(PCLEA,LONG): + subseg_change(SEG_TEXT,0); + fix_new(fragP, (int) (fragP->fr_fix) + 2, 4, fragP->fr_symbol, (symbolS *) 0, fragP->fr_offset + 2, 1, NO_RELOC); + *buffer_address++ = 0x01; + *buffer_address++ = 0x70; + fragP->fr_fix+=2; + /* buffer_address+=2; */ + ext=4; + break; + +} /* 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; /* JBSR with ABSL LONG offset */ + subseg_change(SEG_TEXT, 0); + fix_new(fragP, fragP->fr_fix, 4, + fragP->fr_symbol, 0, fragP->fr_offset, 0, NO_RELOC); + fragP->fr_fix+=4; + frag_wane(fragP); + } else if (fragP->fr_opcode[0] == 0x60) { + fragP->fr_opcode[0]= 0x4E; + fragP->fr_opcode[1]= 0xF9; /* JMP with ABSL LONG offset */ + subseg_change(SEG_TEXT, 0); + fix_new(fragP, fragP->fr_fix, 4, + fragP->fr_symbol, 0, fragP->fr_offset, 0, NO_RELOC); + fragP->fr_fix+=4; + frag_wane(fragP); + } else { + as_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, 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, NO_RELOC); + 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, NO_RELOC); + fragP->fr_fix += 2; + } else { + fragP->fr_opcode[1] = 0x06; /* branch offset = 6 */ + /* JF: these were fr_opcode[2,3] */ + buffer_address[2] = 0x4e; /* put in jmp long (0x4ef9) */ + buffer_address[3] = 0xf9; + fragP->fr_fix += 2; /* account for jmp instruction */ + subseg_change(SEG_TEXT,0); + fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, + fragP->fr_offset, 0, NO_RELOC); + fragP->fr_fix += 4; + } + frag_wane(fragP); + break; + } /* case TAB(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, NO_RELOC); + fragP->fr_fix += 2; + } else { + /* JF: these were fr_opcode[5-7] */ + buffer_address[3] = 0x06; /* Plus 6 */ + buffer_address[4] = 0x4e; /* put in jmp long (0x4ef9) */ + buffer_address[5] = 0xf9; + fragP->fr_fix += 6; /* account for bra/jmp instruction */ + subseg_change(SEG_TEXT,0); + fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, + fragP->fr_offset, 0, NO_RELOC); + fragP->fr_fix += 4; + } + + frag_wane(fragP); + break; + } /* case TAB(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; + + 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() */ + +#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, + 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 */ + + 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, plus + its size. (??? Is this right? FIXME-SOON!) */ +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 0000000..ce69252 --- /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 0000000..8d98baf --- /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 0000000..fd7dd86 --- /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 0000000..d5960d1 --- /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 0000000..e69de29 --- /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 0000000..e69de29 --- /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 0000000..02d86c4 --- /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 0000000..c3c09db --- /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 0000000..e69de29 --- /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 0000000..e69de29 --- /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 0000000..93f6bdde --- /dev/null +++ b/gnu/usr.bin/as/config/tc-sparc.c @@ -0,0 +1,1762 @@ +/* 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/10/27 00:14:52 pk 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': + 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; + } + } + 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 0000000..27355a7 --- /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/10/02 20:59:41 pk 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 0000000..68dc5b9 --- /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 0000000..e63cb63 --- /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 0000000..9133c84 --- /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 0000000..d3972e1 --- /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 0000000..5f358a2 --- /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 0000000..f72d5ee --- /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/10/02 20:59:49 pk 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 0000000..5458df6 --- /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 0000000..dcadbc3 --- /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 0000000..4858c7d --- /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 0000000..da8de1d --- /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 0000000..fbf9d9a --- /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 0000000..e559f28 --- /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 0000000..99702fb --- /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 0000000..1c10191 --- /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 0000000..18331cd --- /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 0000000..52f4b29 --- /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 0000000..30717ff --- /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/10/02 20:57:24 pk 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 0000000..f2c319f --- /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 0000000..fdae0b2 --- /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 0000000..c3b04e1 --- /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 0000000..9564387 --- /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 0000000..3d4e7fd --- /dev/null +++ b/gnu/usr.bin/as/doc/all.m4 @@ -0,0 +1,20 @@ +_divert__(-1) +<$Id: all.m4,v 1.1 1993/10/02 21:00:13 pk 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 0000000..c9e0f57 --- /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/10/02 21:00:15 pk 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 0000000..f1e7f63 --- /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 0000000..f9820ea --- /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 0000000..bf444a6 --- /dev/null +++ b/gnu/usr.bin/as/doc/gen.m4 @@ -0,0 +1,14 @@ +_divert__(-1) +<$Id: gen.m4,v 1.1 1993/10/02 21:00:19 pk 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 0000000..ed52c85 --- /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 0000000..e8718aa --- /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 0000000..1fca147 --- /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 0000000..4013e72 --- /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 0000000..dfa17d3 --- /dev/null +++ b/gnu/usr.bin/as/doc/none.m4 @@ -0,0 +1,57 @@ +_divert__(-1) +<$Id: none.m4,v 1.1 1993/10/02 21:00:24 pk 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 0000000..9a9696f --- /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/10/02 21:00:25 pk 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 0000000..121855a --- /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 0000000..009e334 --- /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 0000000..d5913be --- /dev/null +++ b/gnu/usr.bin/as/doc/vintage.m4 @@ -0,0 +1,11 @@ +_divert__(-1) +<$Id: vintage.m4,v 1.1 1993/10/02 21:00:29 pk 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 index f3a377d..413917d 100644 --- a/gnu/usr.bin/as/expr.c +++ b/gnu/usr.bin/as/expr.c @@ -1,21 +1,21 @@ /* expr.c -operands, expressions- - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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 @@ -24,20 +24,26 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ * Here, "operand"s are of expressions, not instructions. */ +#ifndef lint +static char rcsid[] = "$Id: expr.c,v 1.3 1993/10/02 20:57:26 pk Exp $"; +#endif + #include <ctype.h> +#include <string.h> + #include "as.h" -#include "flonum.h" -#include "read.h" -#include "struc-symbol.h" -#include "expr.h" + #include "obstack.h" -#include "symbols.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 SUN_ASM_SYNTAX +#ifdef LOCAL_LABELS_DOLLAR extern int local_label_defined[]; #endif @@ -46,22 +52,22 @@ extern int local_label_defined[]; * Also build any bignum literal here. */ -/* LITTLENUM_TYPE generic_buffer [6]; /* JF this is a hack */ +/* 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]; + */ +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 */ -}; + &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; @@ -73,413 +79,401 @@ int generic_floating_point_magic; * * out: A expressionS. X_seg determines how to understand the rest of the * expressionS. - * The operand may have been empty: in this case X_seg == SEG_NONE. - * Input_line_pointer -> (next non-blank) char after operand. + * 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; + operand (expressionP) +register expressionS * expressionP; { - register char c; - register char *name; /* points to name of symbol */ - register struct symbol * symbolP; /* Points to symbol */ - - extern char hex_value[]; /* In hex_value.c */ - char *local_label_name(); - - SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */ - c = * input_line_pointer ++; /* Input_line_pointer -> past char in c. */ - if (isdigit(c)) + register 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; /* 8, 10 or 16 */ - /* 0 means we saw start of a floating- */ - /* point constant. */ - register short int maxdig;/* Highest permitted digit value. */ - register int too_many_digits; /* If we see >= this number of */ - /* digits, assume it is a bignum. */ - register char * digit_2; /* -> 2nd digit of number. */ - int small; /* TRUE if fits in 32 bits. */ - - if (c=='0') - { /* non-decimal radix */ - if ((c = * input_line_pointer ++)=='x' || c=='X') - { - c = * input_line_pointer ++; /* read past "0x" or "0X" */ - maxdig = radix = 16; - too_many_digits = 9; - } - else - { - /* If it says '0f' and the line ends or it DOESN'T look like - a floating point #, its a local label ref. DTRT */ - if(c=='f' && (! *input_line_pointer || - (!index("+-.0123456789",*input_line_pointer) && - !index(EXP_CHARS,*input_line_pointer)))) - { - maxdig = radix = 10; - too_many_digits = 11; - c='0'; - input_line_pointer-=2; - } - else if (c && index (FLT_CHARS,c)) - { - radix = 0; /* Start of floating-point constant. */ - /* input_line_pointer -> 1st char of number. */ - expressionP -> X_add_number = - (isupper(c) ? tolower(c) : c); + 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; } - else - { /* By elimination, assume octal radix. */ - radix = 8; - maxdig = 10; /* Un*x sux. Compatibility. */ - too_many_digits = 11; - } - } - /* c == char after "0" or "0x" or "0X" or "0e" etc.*/ - } - else - { - maxdig = radix = 10; - too_many_digits = 11; - } - if (radix) - { /* Fixed-point integer constant. */ - /* May be bignum, or may fit in 32 bits. */ -/* - * Most numbers fit into 32 bits, and we want this case to be fast. - * So we pretend it will fit into 32 bits. If, after making up a 32 - * bit number, we realise that we have scanned more digits than - * comfortably fit into 32 bits, we re-scan the digits coding - * them into a bignum. For decimal and octal numbers we are conservative: some - * numbers may be assumed bignums when in fact they do fit into 32 bits. - * Numbers of any radix can have excess leading zeros: we strive - * to recognise this and cast them back into 32 bits. - * We must check that the bignum really is more than 32 - * bits, and change it back to a 32-bit number if it fits. - * The number we are looking for is expected to be positive, but - * if it fits into 32 bits as an unsigned number, we let it be a 32-bit - * number. The cavalier approach is for speed in ordinary cases. - */ - digit_2 = input_line_pointer; - for (number=0; (digit=hex_value[c])<maxdig; c = * input_line_pointer ++) + } /* 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; + 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) + /* C contains character after number. */ + /* Input_line_pointer->char after C. */ + small = input_line_pointer - digit_2 < too_many_digits; + if (!small) { - /* - * We saw a lot of digits. Manufacture a bignum the hard way. - */ - LITTLENUM_TYPE * leader; /* -> high order littlenum of the bignum. */ - LITTLENUM_TYPE * pointer; /* -> littlenum we are frobbing now. */ - long int carry; - - leader = generic_bignum; - generic_bignum [0] = 0; - generic_bignum [1] = 0; - /* We could just use digit_2, but lets be mnemonic. */ - input_line_pointer = -- digit_2; /* -> 1st digit. */ - c = *input_line_pointer ++; - for (; (carry = hex_value [c]) < maxdig; c = * input_line_pointer ++) + /* + * 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 ++) + for (pointer = generic_bignum; + pointer <= leader; + pointer++) { - long int work; - - work = carry + radix * * pointer; - * pointer = work & LITTLENUM_MASK; - carry = work >> LITTLENUM_NUMBER_OF_BITS; + long work; + + work = carry + radix * *pointer; + *pointer = work & LITTLENUM_MASK; + carry = work >> LITTLENUM_NUMBER_OF_BITS; } - if (carry) + if (carry) { - if (leader < generic_bignum + SIZE_OF_LARGE_NUMBER - 1) + if (leader < generic_bignum + SIZE_OF_LARGE_NUMBER - 1) { /* Room to grow a longer bignum. */ - * ++ leader = carry; + *++leader = carry; } } } - /* Again, C is char after number, */ - /* input_line_pointer -> after C. */ - know( BITS_PER_INT == 32 ); - know( LITTLENUM_NUMBER_OF_BITS == 16 ); - /* Hence the constant "2" in the next line. */ - if (leader < generic_bignum + 2) + /* 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 = TRUE; + number = + ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS) + | (generic_bignum[0] & LITTLENUM_MASK); + small = 1; } - else + else { - number = leader - generic_bignum + 1; /* Number of littlenums in the bignum. */ + number = leader - generic_bignum + 1; /* Number of littlenums in the bignum. */ } } - if (small) + 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) + /* + * Here with number, in correct radix. c is the next char. + * Note that unlike Un*x, we allow "011f" "0x9f" to + * both mean the same as the (conventional) "9f". This is simply easier + * than checking for strict canonical form. Syntax sux! + */ + if (number<10) { -#ifdef SUN_ASM_SYNTAX - if (c=='b' || (c=='$' && local_label_defined[number])) -#else - if (c=='b') + 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_table_lookup(name)) /* seen before */ - && (symbolP -> sy_type & N_TYPE) != N_UNDF /* symbol is defined: OK */ - ) + /* + * 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( (symbolP -> sy_type & N_TYPE) == N_DATA - || (symbolP -> sy_type & N_TYPE) == N_TEXT ); - expressionP -> X_add_symbol = symbolP; - expressionP -> X_add_number = 0; - expressionP -> X_seg = N_TYPE_seg [symbolP -> sy_type]; + /* 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 + else { /* Either not seen or not defined. */ - as_warn( "Backw. ref to unknown label \"%d:\", 0 assumed.", - number - ); - expressionP -> X_add_number = 0; - expressionP -> X_seg = SEG_ABSOLUTE; + as_bad("Backw. ref to unknown label \"%d:\", 0 assumed.", + number); + expressionP->X_add_number = 0; + expressionP->X_seg = SEG_ABSOLUTE; } } - else + else { -#ifdef SUN_ASM_SYNTAX - if (c=='f' || (c=='$' && !local_label_defined[number])) -#else - if (c=='f') + 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); - if ( symbolP = symbol_table_lookup( name )) - { - /* We have no need to check symbol properties. */ - know( (symbolP -> sy_type & N_TYPE) == N_UNDF - || (symbolP -> sy_type & N_TYPE) == N_DATA - || (symbolP -> sy_type & N_TYPE) == N_TEXT); - } - else - { - symbolP = symbol_new (name, N_UNDF, 0,0,0, & zero_address_frag); - symbol_table_insert (symbolP); - } - expressionP -> X_add_symbol = symbolP; - expressionP -> X_seg = SEG_UNKNOWN; - expressionP -> X_subtract_symbol = NULL; - expressionP -> X_add_number = 0; + /* + * 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 + 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') */ + expressionP->X_add_number = number; + expressionP->X_seg = SEG_ABSOLUTE; + input_line_pointer--; /* Restore following character. */ + } /* if (c == 'f') */ + } /* if (c == 'b') */ } - else + else { /* Really a number. */ - expressionP -> X_add_number = number; - expressionP -> X_seg = SEG_ABSOLUTE; - input_line_pointer --; /* Restore following character. */ - } /* if (number<10) */ + expressionP->X_add_number = number; + expressionP->X_seg = SEG_ABSOLUTE; + input_line_pointer--; /* Restore following character. */ + } /* if (number<10) */ } - else + else { - expressionP -> X_add_number = number; - expressionP -> X_seg = SEG_BIG; - input_line_pointer --; /* -> char following number. */ + 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) + 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) + if (error_code == ERROR_EXPONENT_OVERFLOW) { - as_warn( "Bad floating-point constant: exponent overflow, probably assembling junk" ); + as_bad("Bad floating-point constant: exponent overflow, probably assembling junk"); } - else - { - as_warn( "Bad floating-point constant: unknown error code=%d.", error_code); + 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". */ + expressionP->X_seg = SEG_BIG; + /* input_line_pointer->just after constant, */ + /* which may point to whitespace. */ + know(expressionP->X_add_number < 0); /* < 0 means "floating point". */ } /* if (not floating-point constant) */ } - else if(c=='.' && !is_part_of_name(*input_line_pointer)) { - extern struct obstack frags; - - /* - JF: '.' is pseudo symbol with value of current location in current - segment. . . - */ - symbolP = symbol_new("L0\001", - (unsigned char)(seg_N_TYPE[(int)now_seg]), - 0, - 0, - (valueT)(obstack_next_free(&frags)-frag_now->fr_literal), - frag_now); - expressionP->X_add_number=0; - expressionP->X_add_symbol=symbolP; - expressionP->X_seg = now_seg; - - } else if ( is_name_beginner(c) ) /* here if did not begin with a digit */ - { - /* - * Identifier begins here. - * This is kludged for speed, so code is repeated. - */ - name = -- input_line_pointer; - c = get_symbol_end(); - symbolP = symbol_table_lookup(name); - if (symbolP) - { - /* - * If we have an absolute symbol, then we know it's value now. - */ - register segT seg; - - seg = N_TYPE_seg [(int) symbolP -> sy_type & N_TYPE]; - if ((expressionP -> X_seg = seg) == SEG_ABSOLUTE ) + 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))) { - expressionP -> X_add_number = symbolP -> sy_value; + as_bad("Unary operator %c ignored because bad operand follows", c); + break; } - else - { - expressionP -> X_add_number = 0; - expressionP -> X_add_symbol = symbolP; + /* 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 - { - expressionP -> X_add_symbol - = symbolP - = symbol_new (name, N_UNDF, 0,0,0, & zero_address_frag); - - expressionP -> X_add_number = 0; - expressionP -> X_seg = SEG_UNKNOWN; - symbol_table_insert (symbolP); - } - * input_line_pointer = c; - expressionP -> X_subtract_symbol = NULL; - } - else if (c=='(')/* didn't begin with digit & not a name */ - { - (void)expression( expressionP ); - /* Expression() will pass trailing whitespace */ - if ( * input_line_pointer ++ != ')' ) - { - as_warn( "Missing ')' assumed"); - input_line_pointer --; - } - /* here with input_line_pointer -> char after "(...)" */ - } - else if ( c=='~' || c=='-' ) - { /* unary operator: hope for SEG_ABSOLUTE */ - switch(operand (expressionP)) { - case SEG_ABSOLUTE: - /* input_line_pointer -> char after operand */ - if ( c=='-' ) - { - expressionP -> X_add_number = - expressionP -> X_add_number; -/* - * Notice: '-' may overflow: no warning is given. This is compatible - * with other people's assemblers. Sigh. - */ - } - else - { - expressionP -> X_add_number = ~ expressionP -> X_add_number; - } - break; - - case SEG_TEXT: - case SEG_DATA: - case SEG_BSS: - case SEG_PASS1: - case SEG_UNKNOWN: - if(c=='-') { /* JF I hope this hack works */ - expressionP->X_subtract_symbol=expressionP->X_add_symbol; - expressionP->X_add_symbol=0; - expressionP->X_seg=SEG_DIFFERENCE; - break; - } - default: /* unary on non-absolute is unsuported */ - as_warn("Unary operator %c ignored because bad operand follows", c); - break; - /* Expression undisturbed from operand(). */ - } } - else if (c=='\'') + 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; + /* + * 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 + else { - /* can't imagine any other kind of operand */ - expressionP -> X_seg = SEG_NONE; - input_line_pointer --; + /* 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 */ + /* + * 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() */ @@ -487,7 +481,7 @@ operand (expressionP) * In: address of a expressionS. * The X_seg field of the expressionS may only take certain values. * Now, we permit SEG_PASS1 to make code smaller & faster. - * Elsewise we waste time special-case testing. Sigh. Ditto SEG_NONE. + * 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; @@ -495,55 +489,60 @@ operand (expressionP) */ static void -clean_up_expression (expressionP) - register expressionS * expressionP; + clean_up_expression (expressionP) +register expressionS *expressionP; { - switch (expressionP -> X_seg) - { - case SEG_NONE: + 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; - + expressionP->X_add_symbol = NULL; + expressionP->X_subtract_symbol = NULL; + expressionP->X_add_number = 0; + break; + case SEG_BIG: case SEG_ABSOLUTE: - expressionP -> X_subtract_symbol = NULL; - expressionP -> X_add_symbol = NULL; - break; - - case SEG_TEXT: - case SEG_DATA: - case SEG_BSS: + expressionP->X_subtract_symbol = NULL; + expressionP->X_add_symbol = NULL; + break; + case SEG_UNKNOWN: - expressionP -> X_subtract_symbol = NULL; - break; - + expressionP->X_subtract_symbol = NULL; + break; + case SEG_DIFFERENCE: - /* - * It does not hurt to 'cancel' NULL==NULL - * when comparing symbols for 'eq'ness. - * It is faster to re-cancel them to NULL - * than to check for this special case. - */ - if (expressionP -> X_subtract_symbol == expressionP -> X_add_symbol - || ( expressionP->X_subtract_symbol - && expressionP->X_add_symbol - && expressionP->X_subtract_symbol->sy_frag==expressionP->X_add_symbol->sy_frag - && expressionP->X_subtract_symbol->sy_value==expressionP->X_add_symbol->sy_value)) - { - expressionP -> X_subtract_symbol = NULL; - expressionP -> X_add_symbol = NULL; - expressionP -> X_seg = SEG_ABSOLUTE; + /* + * 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; - + break; + + case SEG_REGISTER: + expressionP->X_add_symbol = NULL; + expressionP->X_subtract_symbol = NULL; + break; + default: - BAD_CASE( expressionP -> X_seg); - break; + if (SEG_NORMAL(expressionP->X_seg)) { + expressionP->X_subtract_symbol = NULL; + } + else { + BAD_CASE (expressionP->X_seg); + } + break; } -} +} /* clean_up_expression() */ /* * expr_part () @@ -557,94 +556,106 @@ clean_up_expression (expressionP) */ static segT -expr_part (symbol_1_PP, symbol_2_P) - struct symbol ** symbol_1_PP; - struct symbol * symbol_2_P; + expr_part (symbol_1_PP, symbol_2_P) +symbolS ** symbol_1_PP; +symbolS * symbol_2_P; { - segT return_value; - - know( (* symbol_1_PP) == NULL - || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_TEXT - || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_DATA - || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_BSS - || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF - ); - know( symbol_2_P == NULL - || (symbol_2_P -> sy_type & N_TYPE) == N_TEXT - || (symbol_2_P -> sy_type & N_TYPE) == N_DATA - || (symbol_2_P -> sy_type & N_TYPE) == N_BSS - || (symbol_2_P -> sy_type & N_TYPE) == N_UNDF - ); - if (* symbol_1_PP) + 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 (((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF) + if (!S_IS_DEFINED(* symbol_1_PP)) { - if (symbol_2_P) + if (symbol_2_P) { - return_value = SEG_PASS1; - * symbol_1_PP = NULL; + return_value = SEG_PASS1; + * symbol_1_PP = NULL; } - else + else { - know( ((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF) - return_value = SEG_UNKNOWN; + know(!S_IS_DEFINED(* symbol_1_PP)); + return_value = SEG_UNKNOWN; } } - else + else { - if (symbol_2_P) + if (symbol_2_P) { - if ((symbol_2_P -> sy_type & N_TYPE) == N_UNDF) + if (!S_IS_DEFINED(symbol_2_P)) { - * symbol_1_PP = NULL; - return_value = SEG_PASS1; + * symbol_1_PP = NULL; + return_value = SEG_PASS1; } - else + else { - /* {seg1} - {seg2} */ - as_warn( "Expression too complex, 2 symbols forgotten: \"%s\" \"%s\"", - (* symbol_1_PP) -> sy_name, symbol_2_P -> sy_name ); - * symbol_1_PP = NULL; - return_value = SEG_ABSOLUTE; + /* {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 + else { - return_value = N_TYPE_seg [(* symbol_1_PP) -> sy_type & N_TYPE]; + return_value = S_GET_SEGMENT(* symbol_1_PP); } } } - else + else { /* (* symbol_1_PP) == NULL */ - if (symbol_2_P) + if (symbol_2_P) { - * symbol_1_PP = symbol_2_P; - return_value = N_TYPE_seg [(symbol_2_P) -> sy_type & N_TYPE]; + * symbol_1_PP = symbol_2_P; + return_value = S_GET_SEGMENT(symbol_2_P); } - else + else { - * symbol_1_PP = NULL; - return_value = SEG_ABSOLUTE; + * symbol_1_PP = NULL; + return_value = SEG_ABSOLUTE; } } - know( return_value == SEG_ABSOLUTE - || return_value == SEG_TEXT - || return_value == SEG_DATA - || return_value == SEG_BSS - || return_value == SEG_UNKNOWN - || return_value == SEG_PASS1 - ); - know( (* symbol_1_PP) == NULL - || ((* symbol_1_PP) -> sy_type & N_TYPE) == seg_N_TYPE [(int) return_value] ); - return (return_value); +#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. + * 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. @@ -654,58 +665,58 @@ expr_part (symbol_1_PP, symbol_2_P) * 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. + * 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) - */ -} + 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, __, __, __, - -__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, -__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, -__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, -__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, -__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, -__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, -__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, -__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __ -}; +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, __, __, __, + + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __ + }; /* @@ -713,243 +724,238 @@ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __ * 0 operand, (expression) * 1 + - * 2 & ^ ! | - * 3 * / % < > + * 3 * / % << >> */ -typedef char operator_rankT; static const operator_rankT -op_rank [] = { 0, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1 }; + op_rank[] = { 0, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1 }; -segT /* Return resultP -> X_seg. */ -expr (rank, resultP) - register operator_rankT rank; /* Larger # is higher rank. */ - register expressionS * resultP; /* Deliver result here. */ +/* 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_NONE == expr (op_rank[(int) op_left], &right)) - { - as_warn("Missing operand value assumed absolute 0."); - resultP -> X_add_number = 0; - resultP -> X_subtract_symbol = NULL; - resultP -> X_add_symbol = NULL; - resultP -> X_seg = SEG_ABSOLUTE; - } - know( * input_line_pointer != ' ' ); - c_right = * input_line_pointer; - op_right = op_encoding [c_right]; - if (* input_line_pointer == c_right && (c_right == '<' || c_right == '>') ) - { - input_line_pointer ++; - } /* -> after operator. */ - know( (int) op_right == 0 - || op_rank [(int) op_right] <= op_rank[(int) op_left] ); - /* input_line_pointer -> after right-hand quantity. */ - /* left-hand quantity in resultP */ - /* right-hand quantity in right. */ - /* operator in op_left. */ - if ( resultP -> X_seg == SEG_PASS1 || right . X_seg == SEG_PASS1 ) - { - resultP -> X_seg = SEG_PASS1; - } - else - { - if ( resultP -> X_seg == SEG_BIG ) - { - as_warn( "Left operand of %c is a %s. Integer 0 assumed.", - c_left, resultP -> X_add_number > 0 ? "bignum" : "float"); - resultP -> X_seg = SEG_ABSOLUTE; - resultP -> X_add_symbol = 0; - resultP -> X_subtract_symbol = 0; - resultP -> X_add_number = 0; - } - if ( right . X_seg == SEG_BIG ) - { - as_warn( "Right operand of %c is a %s. Integer 0 assumed.", - c_left, right . X_add_number > 0 ? "bignum" : "float"); - right . X_seg = SEG_ABSOLUTE; - right . X_add_symbol = 0; - right . X_subtract_symbol = 0; - right . X_add_number = 0; - } - if ( op_left == O_subtract ) - { - /* - * Convert - into + by exchanging symbols and negating number. - * I know -infinity can't be negated in 2's complement: - * but then it can't be subtracted either. This trick - * does not cause any further inaccuracy. - */ - - register struct symbol * symbolP; - - right . X_add_number = - right . X_add_number; - symbolP = right . X_add_symbol; - right . X_add_symbol = right . X_subtract_symbol; - right . X_subtract_symbol = symbolP; - if (symbolP) - { - right . X_seg = SEG_DIFFERENCE; + 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; } - op_left = O_add; - } - - if ( op_left == O_add ) - { - segT seg1; - segT seg2; - - know( resultP -> X_seg == SEG_DATA - || resultP -> X_seg == SEG_TEXT - || resultP -> X_seg == SEG_BSS - || resultP -> X_seg == SEG_UNKNOWN - || resultP -> X_seg == SEG_DIFFERENCE - || resultP -> X_seg == SEG_ABSOLUTE - || resultP -> X_seg == SEG_PASS1 - ); - know( right . X_seg == SEG_DATA - || right . X_seg == SEG_TEXT - || right . X_seg == SEG_BSS - || right . X_seg == SEG_UNKNOWN - || right . X_seg == SEG_DIFFERENCE - || right . X_seg == SEG_ABSOLUTE - || right . X_seg == SEG_PASS1 - ); - - clean_up_expression (& right); - clean_up_expression (resultP); - - seg1 = expr_part (& resultP -> X_add_symbol, right . X_add_symbol); - seg2 = expr_part (& resultP -> X_subtract_symbol, right . X_subtract_symbol); - if (seg1 == SEG_PASS1 || seg2 == SEG_PASS1) { - need_pass_2 = TRUE; - resultP -> X_seg = SEG_PASS1; - } else if (seg2 == SEG_ABSOLUTE) - resultP -> X_seg = seg1; - else if ( seg1 != SEG_UNKNOWN - && seg1 != SEG_ABSOLUTE - && seg2 != SEG_UNKNOWN - && seg1 != seg2) { - know( seg2 != SEG_ABSOLUTE ); - know( resultP -> X_subtract_symbol ); - know( seg1 == SEG_TEXT || seg1 == SEG_DATA || seg1== SEG_BSS ); - know( seg2 == SEG_TEXT || seg2 == SEG_DATA || seg2== SEG_BSS ); - know( resultP -> X_add_symbol ); - know( resultP -> X_subtract_symbol ); - as_warn("Expression too complex: forgetting %s - %s", - resultP -> X_add_symbol -> sy_name, - resultP -> X_subtract_symbol -> sy_name); - resultP -> X_seg = SEG_ABSOLUTE; - /* Clean_up_expression() will do the rest. */ - } else - resultP -> X_seg = SEG_DIFFERENCE; - - resultP -> X_add_number += right . X_add_number; - clean_up_expression (resultP); - } - else - { /* Not +. */ - if ( resultP -> X_seg == SEG_UNKNOWN || right . X_seg == SEG_UNKNOWN ) - { - resultP -> X_seg = SEG_PASS1; - need_pass_2 = TRUE; - } - else - { - resultP -> X_subtract_symbol = NULL; - resultP -> X_add_symbol = NULL; - /* Will be SEG_ABSOLUTE. */ - if ( resultP -> X_seg != SEG_ABSOLUTE || right . X_seg != SEG_ABSOLUTE ) - { - as_warn( "Relocation error. Absolute 0 assumed."); - resultP -> X_seg = SEG_ABSOLUTE; - resultP -> X_add_number = 0; - } - else - { - switch ( op_left ) - { - case O_bit_inclusive_or: - resultP -> X_add_number |= right . X_add_number; - break; - - case O_modulus: - if (right . X_add_number) - { - resultP -> X_add_number %= right . X_add_number; - } - else - { - as_warn( "Division by 0. 0 assumed." ); - resultP -> X_add_number = 0; - } - break; - - case O_bit_and: - resultP -> X_add_number &= right . X_add_number; - break; - - case O_multiply: - resultP -> X_add_number *= right . X_add_number; - break; - - case O_divide: - if (right . X_add_number) - { - resultP -> X_add_number /= right . X_add_number; - } - else - { - as_warn( "Division by 0. 0 assumed." ); - resultP -> X_add_number = 0; - } - break; - - case O_left_shift: - resultP -> X_add_number <<= right . X_add_number; - break; - - case O_right_shift: - resultP -> X_add_number >>= right . X_add_number; - break; - - case O_bit_exclusive_or: - resultP -> X_add_number ^= right . X_add_number; - break; - - case O_bit_or_not: - resultP -> X_add_number |= ~ right . X_add_number; - break; - - default: - BAD_CASE( op_left ); - break; - } /* switch(operator) */ - } - } /* If we have to force need_pass_2. */ - } /* If operator was +. */ - } /* If we didn't set need_pass_2. */ - op_left = op_right; - } /* While next operator is >= this rank. */ - return (resultP -> X_seg); -} + 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() @@ -967,14 +973,28 @@ expr (rank, resultP) * lines end in end-of-line. */ char -get_symbol_end() + get_symbol_end() { - register char c; + register char c; + + while (is_part_of_name(c = *input_line_pointer++)) ;; + *--input_line_pointer = 0; + return (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: expr.c */ +/* end of expr.c */ diff --git a/gnu/usr.bin/as/expr.h b/gnu/usr.bin/as/expr.h index 964d3b9..2706d4d 100644 --- a/gnu/usr.bin/as/expr.h +++ b/gnu/usr.bin/as/expr.h @@ -1,21 +1,25 @@ /* expr.h -> header file for expr.c - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + 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.3 1993/10/02 20:57:27 pk Exp $ + */ -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * Abbreviations (mnemonics). @@ -42,28 +46,40 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ * In other words the "type" of an expression is its segment. */ -typedef struct -{ +typedef struct { symbolS *X_add_symbol; /* foo */ symbolS *X_subtract_symbol; /* bar */ - long int X_add_number; /* 42. Must be signed. */ + 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 *). */ +/* 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. */ +/* 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. */ +/* 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(); -segT expr(); -char get_symbol_end(); +#endif /* not __STDC__ */ -/* end: expr.h */ +/* 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 0000000..28d8008 --- /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/10/02 20:57:28 pk 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 0000000..8fcdb52 --- /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/10/02 20:57:29 pk 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 index 1b7b5ea..41e90bd 100644 --- a/gnu/usr.bin/as/flonum-mult.c +++ b/gnu/usr.bin/as/flonum-mult.c @@ -1,200 +1,203 @@ -/* flonum_multip.c - multiply two flonums - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of Gas, the GNU Assembler. - -The GNU assembler is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY. No author or distributor -accepts responsibility to anyone for the consequences of using it -or for whether it serves any particular purpose or works at all, -unless he says so in writing. Refer to the GNU Assembler General -Public License for full details. - -Everyone is granted permission to copy, modify and redistribute -the GNU Assembler, but only under the conditions described in the -GNU Assembler General Public License. A copy of this license is -supposed to have been given to you along with the GNU Assembler -so you can know your rights and responsibilities. It should be -in a file named COPYING. Among other things, the copyright -notice and this notice must be preserved on all copies. */ +/* 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.3 1993/10/02 20:57:30 pk 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 ...) -*/ + + /^\ + (carry) a .b ... | ... a .b a .b + A B | 0 1 0 0 + | + ... | ... a .b + | 1 0 + | + | ... + | + | + | + | ___ + | \ + +----- P = > a .b + N /__ i j + + N = 0 ... A+B + + for all i,j where i+j=N + [i,j integers > 0] + + a[], b[], p[] may not intersect. + Zero length factors signify 0 significant bits: treat as 0.0. + 0.0 factors do the right thing. + Zero length product OK. + + I chose the ForTran accent "foo[bar]" instead of the C accent "*garply" + because I felt the ForTran way was more intuitive. The C way would + probably yield better code on most C compilers. Dean Elsner. + (C style also gives deeper insight [to me] ... oh well ...) + */ -void -flonum_multip (a, b, product) - FLONUM_TYPE * a, - * b, - * product; +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 int work; - unsigned long int carry; - long int exponent; - LITTLENUM_TYPE * q; - long int significant; /* TRUE when we emit a non-0 littlenum */ - /* ForTran accent follows. */ - int P; /* Scan product low-order -> high. */ - int N; /* As in sum above. */ - int A; /* Which [] of a? */ - int B; /* Which [] of b? */ - - if((a->sign!='-' && a->sign!='+') || (b->sign!='-' && b->sign!='+')) { - /* ... - Got to fail somehow. Any suggestions? */ - product->sign=0; - return; - } - product -> sign = (a->sign == b->sign) ? '+' : '-'; - size_of_a = a -> leader - a -> low; - size_of_b = b -> leader - b -> low; - exponent = a -> exponent + b -> exponent; - size_of_product = product -> high - product -> low; - size_of_sum = size_of_a + size_of_b; - extra_product_positions = size_of_product - size_of_sum; - if (extra_product_positions < 0) - { - P = extra_product_positions; /* P < 0 */ - exponent -= extra_product_positions; /* Increases exponent. */ - } - else - { - P = 0; - } - carry = 0; - significant = 0; - for (N = 0; - N <= size_of_sum; - N++) - { - work = carry; - carry = 0; - for (A = 0; - A <= N; - A ++) - { - B = N - A; - if (A <= size_of_a && B <= size_of_b && B >= 0) + 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); + 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; + 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); + printf("work=%08x carry=%04x\n", work, carry); #endif - } - } - significant |= work; - if (significant || P<0) - { - if (P >= 0) - { - product -> low [P] = work; + } + } + significant |= work; + if (significant || P<0) + { + if (P >= 0) + { + product->low[P] = work; #ifdef TRACE -printf("P=%d. work[p]:=%04x\n", P, work); + printf("P=%d. work[p]:=%04x\n", P, work); #endif + } + P ++; + } + else + { + extra_product_positions ++; + exponent ++; + } } - P ++; - } - else - { - extra_product_positions ++; - exponent ++; - } - } - /* - * [P]-> position # size_of_sum + 1. - * This is where 'carry' should go. - */ + /* + * [P]->position # size_of_sum + 1. + * This is where 'carry' should go. + */ #ifdef TRACE -printf("final carry =%04x\n", carry); + 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 --) + if (carry) { - work = * q; - * q = carry; - carry = work; + 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; + else + { + P --; + } + product->leader = product->low + P; + product->exponent = exponent; } -/* end: flonum_multip.c */ +/* end of flonum_mult.c */ diff --git a/gnu/usr.bin/as/flonum.h b/gnu/usr.bin/as/flonum.h index b2e841a..a1a8f08 100644 --- a/gnu/usr.bin/as/flonum.h +++ b/gnu/usr.bin/as/flonum.h @@ -1,111 +1,125 @@ /* flonum.h - Floating point package - Copyright (C) 1987 Free Software Foundation, Inc. -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + 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.3 1993/10/02 20:57:31 pk Exp $ + */ -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /***********************************************************************\ -* * -* Arbitrary-precision floating point arithmetic. * -* * -* * -* Notation: a floating point number is expressed as * -* MANTISSA * (2 ** EXPONENT). * -* * -* If this offends more traditional mathematicians, then * -* please tell me your nomenclature for flonums! * -* * -\***********************************************************************/ -#if !defined(__STDC__) && !defined(const) + * * + * 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. * -* * -\***********************************************************************/ + * * + * Variable precision floating point numbers. * + * * + * Exponent is the place value of the low littlenum. E.g.: * + * If 0: low points to the units littlenum. * + * If 1: low points to the LITTLENUM_RADIX littlenum. * + * If -1: low points to the 1/LITTLENUM_RADIX littlenum. * + * * + \***********************************************************************/ /* JF: A sign value of 0 means we have been asked to assemble NaN A sign value of 'P' means we've been asked to assemble +Inf A sign value of 'N' means we've been asked to assemble -Inf - */ + */ struct FLONUM_STRUCT { - LITTLENUM_TYPE * low; /* low order littlenum of a bignum */ - LITTLENUM_TYPE * high; /* high order littlenum of a bignum */ - LITTLENUM_TYPE * leader; /* -> 1st non-zero littlenum */ - /* If flonum is 0.0, leader==low-1 */ - long int exponent; /* base LITTLENUM_RADIX */ - char sign; /* '+' or '-' */ + 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). * -* * -\***********************************************************************/ + * * + * 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. */ +/* Flonum_XXX_powers_of_ten[] table has */ +/* legal indices from 0 to */ +/* + this number inclusive. */ /***********************************************************************\ -* * -* Declare worker functions. * -* * -\***********************************************************************/ + * * + * 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); -void flonum_multip(); -void flonum_copy(); -void flonum_print(); -char * flonum_get(); /* Returns "" or error string. */ -void flonum_normal(); +#else /* not __STDC__ */ -int atof_generic(); +int atof_generic(); +void flonum_copy(); +void flonum_multip(); +#endif /* not __STDC__ */ /***********************************************************************\ -* * -* Declare error codes. * -* * -\***********************************************************************/ + * * + * Declare error codes. * + * * + \***********************************************************************/ #define ERROR_EXPONENT_OVERFLOW (2) -/* end: flonum.h */ +/* end of flonum.h */ diff --git a/gnu/usr.bin/as/frags.c b/gnu/usr.bin/as/frags.c index ee10321..208aa7d 100644 --- a/gnu/usr.bin/as/frags.c +++ b/gnu/usr.bin/as/frags.c @@ -1,27 +1,30 @@ /* frags.c - manage frags - - Copyright (C) 1987 Free Software Foundation, Inc. -This file is part of GAS, the GNU Assembler. + 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. */ -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifndef lint +static char rcsid[] = "$Id: frags.c,v 1.3 1993/10/02 20:57:31 pk Exp $"; +#endif #include "as.h" #include "subsegs.h" #include "obstack.h" -#include "frags.h" -#include "struc-symbol.h" struct obstack frags; /* All, and only, frags live here. */ @@ -37,8 +40,8 @@ fragS zero_address_frag = { 0, /* fr_subtype */ 0, /* fr_pcrel_adjust */ 0, /* fr_bsr */ - 0 /* fr_literal [0] */ -}; + 0 /* fr_literal[0] */ + }; fragS bss_address_frag = { 0, /* fr_address. Gets filled in to make up @@ -53,8 +56,8 @@ fragS bss_address_frag = { 0, /* fr_subtype */ 0, /* fr_pcrel_adjust */ 0, /* fr_bsr */ - 0 /* fr_literal [0] */ -}; + 0 /* fr_literal[0] */ + }; /* * frag_grow() @@ -65,29 +68,28 @@ fragS bss_address_frag = { * and begin a new frag. Unless the new frag has nchars chars available * do not return. Do not set up any fields of *now_frag. */ -static void -frag_grow (nchars) -int nchars; +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) { + if (obstack_room (&frags) < nchars) { + unsigned int n,oldn; + long oldc; + frag_wane(frag_now); frag_new(0); - oldn=n; + 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; } - frags.chunk_size=oldc; - } - if (obstack_room (&frags) < nchars) - as_fatal ("Can't extend frag %d. chars", nchars); -} + if (obstack_room (&frags) < nchars) + as_fatal("Can't extend frag %d. chars", nchars); +} /* frag_grow() */ /* * frag_new() @@ -106,55 +108,62 @@ int nchars; * 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 +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. */ +/* in variable_length part of frag. */ { - register fragS * former_last_fragP; -/* char *throw_away_pointer; JF unused */ - register frchainS * frchP; - long tmp; /* JF */ - - frag_now->fr_fix = (char *) (obstack_next_free (&frags)) - - (frag_now->fr_literal) - old_frags_var_max_size; - /* Fix up old frag's fr_fix. */ - - obstack_finish (&frags); - /* This will align the obstack so the */ - /* next struct we allocate on it will */ - /* begin at a correct boundary. */ - frchP = frchain_now; - know (frchP); - former_last_fragP = frchP->frch_last; - know (former_last_fragP); - know (former_last_fragP == frag_now); - obstack_blank (&frags, SIZEOF_STRUCT_FRAG); - /* We expect this will begin at a correct */ - /* boundary for a struct. */ - tmp=obstack_alignment_mask(&frags); - obstack_alignment_mask(&frags)=0; /* Turn off alignment */ - /* If we ever hit a machine - where strings must be - aligned, we Lose Big */ - frag_now=(fragS *)obstack_finish(&frags); - obstack_alignment_mask(&frags)=tmp; /* Restore alignment */ - - /* Just in case we don't get zero'd bytes */ - bzero(frag_now, SIZEOF_STRUCT_FRAG); - -/* obstack_unaligned_done (&frags, &frag_now); */ -/* know (frags.obstack_c_next_free == frag_now->fr_literal); */ - /* Generally, frag_now->points to an */ - /* address rounded up to next alignment. */ - /* However, characters will add to obstack */ - /* frags IMMEDIATELY after the struct frag, */ - /* even if they are not starting at an */ - /* alignment address. */ - former_last_fragP->fr_next = frag_now; - frchP->frch_last = frag_now; - frag_now->fr_next = NULL; + 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() */ /* @@ -167,16 +176,15 @@ int old_frags_var_max_size; /* Number of chars (already allocated on * frag_now_growth past the new chars. */ -char * -frag_more (nchars) -int nchars; +char *frag_more (nchars) +int nchars; { - register char *retval; - - frag_grow (nchars); - retval = obstack_next_free (&frags); - obstack_blank_fast (&frags, nchars); - return (retval); + register char *retval; + + frag_grow (nchars); + retval = obstack_next_free (&frags); + obstack_blank_fast (&frags, nchars); + return (retval); } /* frag_more() */ /* @@ -190,32 +198,31 @@ int nchars; * to write into. */ -char * -frag_var (type, max_chars, var, subtype, symbol, offset, opcode) -relax_stateT type; -int max_chars; -int var; -relax_substateT subtype; -symbolS * symbol; -long int offset; -char * opcode; +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); + 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() */ /* @@ -227,33 +234,32 @@ char * opcode; * Two new arguments have been added. */ -char * -frag_variant (type, max_chars, var, subtype, symbol, offset, opcode, pcrel_adjust,bsr) - relax_stateT type; - int max_chars; - int var; - relax_substateT subtype; - symbolS *symbol; - long int offset; - char *opcode; - char pcrel_adjust; - char bsr; +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); + 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() */ /* @@ -261,13 +267,12 @@ frag_variant (type, max_chars, var, subtype, symbol, offset, opcode, pcrel_adjus * * Reduce the variable end of a frag to a harmless state. */ -void -frag_wane (fragP) +void frag_wane(fragP) register fragS * fragP; { - fragP->fr_type = rs_fill; - fragP->fr_offset = 0; - fragP->fr_var = 0; + fragP->fr_type = rs_fill; + fragP->fr_offset = 0; + fragP->fr_var = 0; } /* @@ -280,13 +285,12 @@ register fragS * fragP; * (so far empty) frag, in the same subsegment as the last frag. */ -void -frag_align (alignment, fill_character) -int alignment; -int fill_character; +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_var (rs_align, 1, 1, (relax_substateT)0, (symbolS *)0, + (long)alignment, (char *)0)) = fill_character; +} /* frag_align() */ -/* end: frags.c */ +/* end of frags.c */ diff --git a/gnu/usr.bin/as/frags.h b/gnu/usr.bin/as/frags.h index 6d7310b..4532dda 100644 --- a/gnu/usr.bin/as/frags.h +++ b/gnu/usr.bin/as/frags.h @@ -1,27 +1,32 @@ /* frags.h - Header file for the frag concept. - Copyright (C) 1987 Free Software Foundation, Inc. -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + 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.3 1993/10/02 20:57:32 pk Exp $ + */ -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ extern struct obstack frags; - /* Frags ONLY live in this obstack. */ - /* We use obstack_next_free() macro */ - /* so please don't put any other objects */ - /* on this stack! */ +/* 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 @@ -30,12 +35,55 @@ extern struct obstack frags; /* JF changed < 1 to <= 1 to avoid a race conditon */ #define FRAG_APPEND_1_CHAR(datum) \ { \ - if (obstack_room( &frags ) <= 1) {\ - frag_wane (frag_now); \ - frag_new (0); \ - } \ - obstack_1grow( &frags, datum ); \ -} - - -/* end: frags.h */ + 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 0000000..32c6426 --- /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 index 21f0cc0..68a5f14 100644 --- a/gnu/usr.bin/as/hash.c +++ b/gnu/usr.bin/as/hash.c @@ -1,21 +1,21 @@ /* hash.c - hash table lookup strings - - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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. @@ -122,41 +122,50 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ * */ +#ifndef lint +static char rcsid[] = "$Id: hash.c,v 1.3 1993/10/02 20:57:34 pk Exp $"; +#endif + #include <stdio.h> -#define TRUE (1) -#define FALSE (0) + +#ifndef FALSE +#define FALSE (0) +#define TRUE (!FALSE) +#endif /* no FALSE yet */ + #include <ctype.h> #define min(a, b) ((a) < (b) ? (a) : (b)) -#include "hash.h" -char *xmalloc(); +#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 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 */ +/* 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 */ +/* 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...() */ - + + /* #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) @@ -167,71 +176,71 @@ Panic! Please make #include "stat.h" agree with previous definitions! #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 - -*/ + + 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 */ +/* 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 (); @@ -242,48 +251,49 @@ static char * hash_grow(); * */ struct hash_control * -hash_new() /* create a new hash table */ - /* return NULL if failed */ - /* return handle (address of struct hash) */ + hash_new() /* create a new hash table */ +/* return NULL if failed */ +/* return handle (address of struct hash) */ { - register struct hash_control * retval; - register struct hash_entry * room; /* points to hash table */ - register struct hash_entry * wall; - register struct hash_entry * entry; - char * malloc(); - register int * ip; /* scan stats block of struct hash_control */ - register int * nd; /* limit of stats block */ - - if ( room = (struct hash_entry *) malloc( sizeof(struct hash_entry)*((1<<START_POWER) + 1) ) ) - /* +1 for the wall entry */ - { - if ( retval = (struct hash_control *) malloc(sizeof(struct hash_control)) ) - { - nd = retval->hash_stat + STATLENGTH; - for (ip=retval->hash_stat; ip<nd; ip++) + 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 */ { - *ip = 0; - } - - retval -> hash_stat[STAT_SIZE] = 1<<START_POWER; - retval -> hash_mask = (1<<START_POWER) - 1; - retval -> hash_sizelog = START_POWER; + 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++) + 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 { - entry->hash_string = NULL; + retval = NULL; /* no room for table: fake a failure */ } - } - } - else - { - retval = NULL; /* no room for table: fake a failure */ - } - return(retval); /* return NULL or set-up structs */ + return(retval); /* return NULL or set-up structs */ } /* @@ -297,11 +307,11 @@ hash_new() /* create a new hash table */ * No errors are recoverable. */ void -hash_die(handle) - struct hash_control * handle; + hash_die(handle) +struct hash_control * handle; { - free((char *)handle->hash_where); - free((char *)handle); + free((char *)handle->hash_where); + free((char *)handle); } /* @@ -318,24 +328,24 @@ hash_die(handle) * 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; + 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; - } - } + 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; + } + } } /* @@ -348,32 +358,32 @@ hash_say(handle,buffer,bufsiz) * */ 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; + /* 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 */ + 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) + if (handle->hash_stat[STAT_USED]<0) + { + error("hash_delete"); + } +#endif /* def SUSPECT */ + } + else { - error("hash_delete"); + retval = NULL; } -#endif /* def SUSPECT */ - } - else - { - retval = NULL; - } - return(retval); + return(retval); } /* @@ -385,26 +395,26 @@ hash_delete(handle,string) * in the table. */ char * -hash_replace(handle,string,value) - register struct hash_control * handle; - register char * string; - register char * value; + 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); + 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); } /* @@ -416,34 +426,34 @@ hash_replace(handle,string,value) */ char * /* return error string */ -hash_insert(handle,string,value) - register struct hash_control * handle; - register char * string; - register char * value; + 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); + 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); } /* @@ -461,30 +471,30 @@ hash_insert(handle,string,value) * false if we inserted. */ char * -hash_jam(handle,string,value) - register struct hash_control * handle; - register char * string; - register char * value; + 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); + 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); } /* @@ -499,98 +509,99 @@ hash_jam(handle,string,value) * Internal. */ static char * -hash_grow(handle) /* make a hash table grow */ - struct hash_control * handle; + 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; + 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; + int oldused; #endif - - /* - * capture info about old hash table - */ - oldwhere = handle -> hash_where; - oldwall = handle -> hash_wall; + + /* + * capture info about old hash table + */ + oldwhere = handle->hash_where; + oldwall = handle->hash_wall; #ifdef SUSPECT - oldused = handle -> hash_stat[STAT_USED]; + oldused = handle->hash_stat[STAT_USED]; #endif - /* - * attempt to get enough room for a hash table twice as big - */ - temp = handle->hash_stat[STAT_SIZE]; - if ( newwhere = (struct hash_entry *) xmalloc((long)((temp+temp+1)*sizeof(struct hash_entry)))) - /* +1 for wall slot */ - { - retval = ""; /* assume success until proven otherwise */ - /* - * have enough room: now we do all the work. - * double the size of everything in handle, - * note: hash_mask frob works for 1's & for 2's complement machines - */ - handle->hash_mask = handle->hash_mask + handle->hash_mask + 1; - handle->hash_stat[STAT_SIZE] <<= 1; - newsize = handle->hash_stat[STAT_SIZE]; - handle->hash_where = newwhere; - handle->hash_full <<= 1; - handle->hash_sizelog += 1; - handle->hash_stat[STAT_USED] = 0; - handle->hash_wall = - newwall = newwhere + newsize; - /* - * set all those pesky new slots to vacant. - */ - for (newtrack=newwhere; newtrack <= newwall; newtrack++) - { - newtrack -> hash_string = NULL; - } - /* - * we will do a scan of the old table, the hard way, using the - * new control block to re-insert the data into new hash table. - */ - handle -> hash_stat[STAT_USED] = 0; /* inserts will bump it up to correct */ - for (oldtrack=oldwhere; oldtrack < oldwall; oldtrack++) - { - if ( (string=oldtrack->hash_string) && string!=DELETED ) + /* + * 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 */ { - if ( * (retval = hash_jam(handle,string,oldtrack->hash_value) ) ) - { - break; - } - } - } + 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"; - } + 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); + 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); } /* @@ -640,22 +651,22 @@ hash_grow(handle) /* make a hash table grow */ * yet. (The function has no graceful failures.) */ char * -hash_apply(handle,function) - struct hash_control * handle; - char* (*function)(); + 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); + 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); } /* @@ -665,23 +676,23 @@ hash_apply(handle,function) * Return found value or NULL. */ char * -hash_find(handle,string) /* return char* or NULL */ - struct hash_control * handle; - char * string; + 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); + 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); } /* @@ -694,72 +705,72 @@ hash_find(handle,string) /* return char* or NULL */ * 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 */ + hash_ask(handle,string,access) +struct hash_control * handle; +char * string; +int access; /* access type */ { - register char *string1; /* JF avoid strcmp calls */ - register char * s; - register int c; - register struct hash_entry * slot; - register int collision; /* count collisions */ - - slot = handle->hash_where + hash_code(handle,string); /* start looking here */ - handle->hash_stat[STAT_ACCESS+access] += 1; - collision = 0; - hash_found = FALSE; - while ( (s = slot->hash_string) && s!=DELETED ) - { - for(string1=string;;) { - if(!(c= *s++)) { - if(!*string1) - hash_found = TRUE; - break; - } - if(*string1++!=c) + 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; - } - if(hash_found) - break; - collision++; - slot++; - } - /* - * slot: return: - * in use: we found string slot - * at empty: - * at wall: we fell off: wrap round ???? - * in table: dig here slot - * at DELETED: dig here slot - */ - if (slot==handle->hash_wall) - { - slot = handle->hash_where; /* now look again */ - while( (s = slot->hash_string) && s!=DELETED ) - { - for(string1=string;*s;string1++,s++) { - if(*string1!=*s) - break; - } - if(*s==*string1) { - hash_found = TRUE; - break; + collision++; + slot++; + } + /* + * slot: return: + * in use: we found 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 + */ } - 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 */ + /* 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 */ } /* @@ -769,22 +780,22 @@ hash_ask(handle,string,access) * Internal. */ static int -hash_code(handle,string) - struct hash_control * handle; - register char * string; + hash_code(handle,string) +struct hash_control * handle; +register char * string; { - register long int h; /* hash code built here */ - register long int c; /* each character lands here */ - register int n; /* Amount to shift h by */ - - n = (handle->hash_sizelog - 3); - h = 0; - while (c = *string++) - { - h += c; - h = (h<<3) + (h>>n) + c; - } - return (h & handle->hash_mask); + 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); } /* @@ -793,7 +804,7 @@ hash_code(handle,string) #ifdef TEST #define TABLES (6) /* number of hash tables to maintain */ - /* (at once) in any testing */ +/* (at once) in any testing */ #define STATBUFSIZE (12) /* we can have 12 statistics */ int statbuf[STATBUFSIZE]; /* display statistics here */ @@ -808,174 +819,174 @@ int size; int used; char command; int number; /* number 0:TABLES-1 of current hashed */ - /* symbol table */ +/* 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++) + 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("address of hash table #%d control block is %xx\n" - ,pp-hashtable,*pp); + 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; + } } - 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; + 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 * 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; + destroy(string,value) +char * string; +char * value; { - free(string); - free(value); - return(NULL); + free(string); + free(value); + return(NULL); } char * -applicatee(string,value) - char * string; - char * value; + applicatee(string,value) +char * string; +char * value; { - printf("%.20s-%.20s\n",string,value); - return(NULL); + printf("%.20s-%.20s\n",string,value); + return(NULL); } whattable() /* determine number: what hash table to use */ - /* also determine h: points to hash_control */ +/* 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) + + for (;;) { - printf("warning: current hash-table-#%d. has no hash-control\n",number); + 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); + } } - return; - } - else - { - printf("invalid hash table number: %d\n",number); - } - } } #endif /* #ifdef TEST */ -/* end: hash.c */ +/* end of hash.c */ diff --git a/gnu/usr.bin/as/hash.h b/gnu/usr.bin/as/hash.h index fb68fd3..6918561 100644 --- a/gnu/usr.bin/as/hash.h +++ b/gnu/usr.bin/as/hash.h @@ -1,59 +1,65 @@ /* hash.h - for hash.c - Copyright (C) 1987 Free Software Foundation, Inc. + 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.3 1993/10/02 20:57:35 pk Exp $ + */ -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef hashH #define hashH struct hash_entry { - char * hash_string; /* points to where the symbol string is */ - /* NULL means slot is not used */ - /* DELETED means slot was deleted */ - char * hash_value; /* user's datum, associated with symbol */ + 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 */ + 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) */ -/* 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 */ +#endif /* #ifdef hashH */ -/* end: hash.c */ +/* end of hash.h */ diff --git a/gnu/usr.bin/as/hex-value.c b/gnu/usr.bin/as/hex-value.c index f97c2ab3..d27d4b3 100644 --- a/gnu/usr.bin/as/hex-value.c +++ b/gnu/usr.bin/as/hex-value.c @@ -1,55 +1,61 @@ /* hex_value.c - char=>radix-value - - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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.3 1993/10/02 20:57:36 pk Exp $"; +#endif + #define __ (42) /* blatently illegal digit value */ - /* exceeds any normal radix */ -#if !defined(__STDC__) && !defined(const) +/* 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, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __ - }; + hex_value[256] = { /* for fast ASCII -> binary */ + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, __, __, __, __, __, __, + __, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __ + }; -#ifdef VMS +#ifdef HO_VMS dummy2() { } #endif -/* end:hex_value.c */ + +/* end of hex_value.c */ diff --git a/gnu/usr.bin/as/input-file.c b/gnu/usr.bin/as/input-file.c index 8de1dcf..3b124cc 100644 --- a/gnu/usr.bin/as/input-file.c +++ b/gnu/usr.bin/as/input-file.c @@ -1,32 +1,21 @@ -/*- - * This code is derived from software copyrighted by the Free Software - * Foundation. - * - * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. - */ - -#ifndef lint -static char sccsid[] = "@(#)input-file.c 6.2 (Berkeley) 5/8/91"; -#endif /* not lint */ - /* input_file.c - Deal with Input Files - - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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. @@ -35,31 +24,25 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ * Note we don't need to #include the "as.h" file. No common coupling! */ -#define NDEBUG /* JF remove asserts */ +#ifndef lint +static char rcsid[] = "$Id: input-file.c,v 1.3 1993/10/02 20:57:37 pk Exp $"; +#endif #ifdef USG -#define index strchr -/* JF: What's the difference between _IOLBF and _IOFBF ? */ #define setbuffer(stream, buf, size) setvbuf((stream), (buf), _IOFBF, (size)) #endif #include <stdio.h> -#include <assert.h> -/* #include <sys/types.h> -#include <sys/stat.h> -#include <sys/file.h> -#include <sys/wait.h> */ +#include <string.h> -/* #include "style.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; -void as_perror(); - /* * This code opens a file, then delivers BUFFER_SIZE character * chunks of the file on demand. @@ -70,177 +53,210 @@ void as_perror(); #define BUFFER_SIZE (32 * 1024) -static char in_buf[BUFFER_SIZE]; - /* * We use static data: the data area is not sharable. */ -FILE *f_in; /* JF do things the RIGHT way */ +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 () -{ - /* file_handle = -1; */ - f_in = (FILE *)0; +void input_file_begin() { + f_in = (FILE *)0; } -void -input_file_end () -{ +void input_file_end () { } + +/* Return BUFFER_SIZE. */ +int input_file_buffer_size() { + return (BUFFER_SIZE); } -int /* Return BUFFER_SIZE. */ -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; } -int -input_file_is_open () +void + input_file_pop (arg) +char *arg; { - /* return (file_handle >= 0); */ - return f_in!=(FILE *)0; + 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. */ + input_file_open (filename, preprocess, debugging) +char * filename; /* "" means use stdin. Must not be 0. */ +int preprocess; /* TRUE if needs app. */ +int debugging; /* TRUE if we are debugging assembler. */ { - assert( filename != 0 ); /* Filename may not be NULL. */ - if (filename [0]) - { /* We have a file name. Suck it and see. */ - file_handle = open (filename, O_RDONLY, 0); - file_name = filename; - } - else - { /* use stdin for the input file. */ - file_handle = fileno (stdin); - file_name = "{standard input}"; /* For error messages. */ - } - if (file_handle < 0) - as_perror ("Can't open %s for reading", file_name); - if ( preprocess ) - { -/* - * This code was written in haste for a frobbed BSD 4.2. - * I have a flight to catch: will someone please do proper - * error checks? - Dean. - */ - int pid; - char temporary_file_name [12]; - int fd; - union wait status; - char *mktemp(); - - (void)strcpy (temporary_file_name, "#appXXXXXX"); - (void)mktemp (temporary_file_name); - pid = vfork (); - if (pid == -1) - { - as_perror ("Vfork failed", file_name); - _exit (144); - } - if (pid == 0) - { - (void)dup2 (file_handle, fileno(stdin)); - fd = open (temporary_file_name, O_WRONLY + O_TRUNC + O_CREAT, 0666); - if (fd == -1) - { - (void)write(2,"Can't open temporary\n",21); - _exit (99); + 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. */ } - (void)dup2 (fd, fileno(stdout)); -/* JF for testing #define PREPROCESSOR "/lib/app" */ + 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_warn( "Can't preprocess file \"%s\", status = %xx", file_name, status.w_status ); - } - else - { - file_handle = open (temporary_file_name, O_RDONLY, 0); - if ( ! debugging && unlink(temporary_file_name)) - as_perror ("Can't delete temp file %s", temporary_file_name); - } - if (file_handle == -1) - as_perror ("Can't retrieve temp file %s", temporary_file_name); - } + 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; + 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. */ + 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) { + if (f_in == (FILE *)0) { as_perror ("Can't open %s for reading", file_name); return; } -#ifndef VMS - setbuffer(f_in,in_buf,BUFFER_SIZE); -#endif /* VMS */ - c=getc(f_in); - if(c=='#') { /* Begins with comment, may not want to preprocess */ - c=getc(f_in); - if(c=='N') { + +#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(!index(buf,'\n')) - ungetc('#',f_in); /* It was longer */ + 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); + ungetc('\n',f_in); + } else if (c == '\n') + ungetc('\n',f_in); else - ungetc('#',f_in); + ungetc('#',f_in); } else - ungetc(c,f_in); - + ungetc(c,f_in); + #ifdef DONTDEF if ( preprocess ) { - char temporary_file_name [17]; - char *mktemp(); + 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. */ + 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 */ @@ -251,56 +267,61 @@ input_file_open (filename,pre) } #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. */ + input_file_give_next_buffer (where) +char * where; /* Where to place 1st character of new buffer. */ { - char * return_value; /* -> Last char of what we read, + 1. */ - register int size; - - if (f_in == (FILE *)0) - return 0; - /* - * fflush (stdin); could be done here if you want to synchronise - * stdin and stdout, for the case where our input file is stdin. - * Since the assembler shouldn't do any output to stdout, we - * don't bother to synch output and input. - */ - /* size = read (file_handle, where, BUFFER_SIZE); */ - if(preprocess) { - char *p; - int n; - int ch; - extern FILE *scrub_file; - int scrub_from_file(); - void scrub_to_file(); - int do_scrub_next_char(); - - scrub_file=f_in; - for(p=where,n=BUFFER_SIZE;n;--n) { - ch=do_scrub_next_char(scrub_from_file,scrub_to_file); - if(ch==EOF) - break; - *p++=ch; - } - size=BUFFER_SIZE-n; - } else - size= fread(where,sizeof(char),BUFFER_SIZE,f_in); - if (size < 0) - { - as_perror ("Can't read from %s", file_name); - size = 0; - } - if (size) - return_value = where + size; - else - { - if (fclose (f_in)) - as_perror ("Can't close %s", file_name); - f_in = (FILE *)0; - return_value = 0; - } - return (return_value); + 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: input_file.c */ +/* end of input-file.c */ diff --git a/gnu/usr.bin/as/input-file.h b/gnu/usr.bin/as/input-file.h index 42f490a..5c88c7c 100644 --- a/gnu/usr.bin/as/input-file.h +++ b/gnu/usr.bin/as/input-file.h @@ -1,24 +1,28 @@ /* input_file.h header for input-file.c - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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.3 1993/10/02 20:57:38 pk Exp $ + */ + /* * No matter what the operating system, this module must provide the @@ -43,15 +47,42 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ * 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. */ -void input_file_begin(); -void input_file_end(); -int input_file_buffer_size(); -int input_file_is_open(); -void input_file_open(); -char * input_file_give_next_buffer(); +#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: input_file.h */ +/* end of input_file.h */ diff --git a/gnu/usr.bin/as/input-scrub.c b/gnu/usr.bin/as/input-scrub.c index 71af8a0..73df1a2 100644 --- a/gnu/usr.bin/as/input-scrub.c +++ b/gnu/usr.bin/as/input-scrub.c @@ -1,52 +1,46 @@ -/*- - * This code is derived from software copyrighted by the Free Software - * Foundation. - * - * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. - */ +/* 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 sccsid[] = "@(#)input-scrub.c 6.4 (Berkeley) 5/8/91"; -#endif /* not lint */ - -/* input_scrub.c - layer between app and the rest of the world - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +static char rcsid[] = "$Id: input-scrub.c,v 1.3 1993/10/02 20:57:39 pk Exp $"; +#endif +#include <errno.h> /* Need this to make errno declaration right */ #include "as.h" -#include "read.h" #include "input-file.h" /* * O/S independent module to supply buffers of sanitised source code - * to rest of assembler. We get raw input data of some length. - * Also looks after line numbers, for e.g. error messages. - * This module used to do the sanitising, but now a pre-processor program - * (app) does that job so this module is degenerate. - * Now input is pre-sanitised, so we only worry about finding the - * last partial line. A buffer of full lines is returned to caller. + * 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. The last character before AFTER_STRING is a newline. + * 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 expect the following sanitation has already been done. + * 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. @@ -58,166 +52,269 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ */ #define BEFORE_STRING ("\n") -#define AFTER_STRING ("\0") /* bcopy of 0 chars might choke. */ +#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? */ - -static void as_1_char (); - -/* -We never have more than one source file open at once. -We may, however, read more than 1 source file in an assembly. -NULL means we have no file open right now. -*/ - - -/* -We must track the physical file and line number for error messages. -We also track a "logical" file and line number corresponding to (C?) -compiler source line numbers. -Whenever we open a file we must fill in physical_input_file. So if it is NULL -we have not opened any files yet. -*/ - -static -char * physical_input_file, - * logical_input_file; - - +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() */ -typedef unsigned int line_numberT; /* 1-origin line number in a source file. */ - /* A line ends in '\n' or eof. */ +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; +} -static -line_numberT physical_input_line, - logical_input_line; void -input_scrub_begin () + input_scrub_begin () { - know( strlen(BEFORE_STRING) == BEFORE_SIZE ); - know( strlen( AFTER_STRING) == AFTER_SIZE ); - - input_file_begin (); - - buffer_length = input_file_buffer_size (); - - buffer_start = xmalloc ((long)(BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE)); - bcopy (BEFORE_STRING, buffer_start, (int)BEFORE_SIZE); - - /* Line number things. */ - logical_input_line = 0; - logical_input_file = (char *)NULL; - physical_input_file = NULL; /* No file read yet. */ - do_scrub_begin(); + 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 () + input_scrub_end () { - input_file_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_scrub_new_file (filename) +char * filename; { - input_file_open (filename, !flagseen['f']); - physical_input_file = filename[0] ? filename : "{standard input}"; - physical_input_line = 0; + 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); +} - 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) + input_scrub_next_buffer (bufp) char **bufp; { - register char * limit; /* -> just after last char of buffer. */ - + register char * limit; /*->just after last char of buffer. */ + + *bufp = buffer_start + BEFORE_SIZE; + #ifdef DONTDEF - if(preprocess) { - if(save_buffer) { - *bufp = save_buffer; - save_buffer = 0; - } - limit = input_file_give_next_buffer(buffer_start+BEFORE_SIZE); - if (!limit) { - partial_where = 0; - if(partial_size) - as_warn("Partial line at end of file ignored"); - return partial_where; - } - - if(partial_size) - bcopy(save_source, partial_where,(int)AFTER_SIZE); - do_scrub(partial_where,partial_size,buffer_start+BEFORE_SIZE,limit-(buffer_start+BEFORE_SIZE),&out_string,&out_length); - limit=out_string + out_length; - for(p=limit;*--p!='\n';) - ; - p++; - if(p<=buffer_start+BEFORE_SIZE) - as_fatal("Source line too long. Please change file '%s' and re-make the assembler.",__FILE__); - - partial_where = p; - partial_size = limit-p; - bcopy(partial_where, save_source,(int)AFTER_SIZE); - bcopy(AFTER_STRING, partial_where, (int)AFTER_SIZE); - - save_buffer = *bufp; - *bufp = out_string; - - return partial_where; - } - - /* We're not preprocessing. Do the right thing */ -#endif - if (partial_size) - { - bcopy (partial_where, buffer_start + BEFORE_SIZE, (int)partial_size); - bcopy (save_source, buffer_start + BEFORE_SIZE, (int)AFTER_SIZE); - } - limit = input_file_give_next_buffer (buffer_start + BEFORE_SIZE + partial_size); - if (limit) - { - register char * p; /* Find last newline. */ - - for (p = limit; * -- p != '\n'; ) - { + 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; } - ++ p; - if (p <= buffer_start + BEFORE_SIZE) - { - as_fatal ("Source line too long. Please change file %s then rebuild assembler.", __FILE__); + + /* 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); } - partial_where = p; - partial_size = limit - p; - bcopy (partial_where, save_source, (int)AFTER_SIZE); - bcopy (AFTER_STRING, partial_where, (int)AFTER_SIZE); - } - else - { - partial_where = 0; - if (partial_size > 0) - { - as_warn( "Partial line at end of file ignored" ); + 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); -} + return(partial_where); +} /* input_scrub_next_buffer() */ /* * The remaining part of this file deals with line numbers, error @@ -226,16 +323,16 @@ char **bufp; int -seen_at_least_1_file () /* TRUE if we opened any file. */ + seen_at_least_1_file () /* TRUE if we opened any file. */ { - return (physical_input_file != NULL); + return (physical_input_file != NULL); } void -bump_line_counters () + bump_line_counters () { - ++ physical_input_line; - ++ logical_input_line; + ++ physical_input_line; + /* ++ logical_input_line; FIXME-now remove this. */ } /* @@ -245,183 +342,95 @@ bump_line_counters () * 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; +void new_logical_line(fname, line_number) +char *fname; /* DON'T destroy it! We point to it! */ +int line_number; { - if ( fname ) - { - logical_input_file = fname; - } - if ( line_number >= 0 ) - { - logical_input_line = line_number; - } -} + 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 ( ) + * 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; +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() */ - if (physical_input_file) - { /* we tried to read SOME source */ - if (input_file_is_open()) - { /* we can still read lines from source */ -#ifdef DONTDEF - fprintf (stderr," @ physical line %ld., file \"%s\"", - (long) physical_input_line, physical_input_file); - fprintf (stderr," @ logical line %ld., file \"%s\"\n", - (long) logical_input_line, logical_input_file); - (void)putc(' ', stderr); - as_howmuch (stderr); - (void)putc('\n', stderr); -#else - p = logical_input_file ? logical_input_file : physical_input_file; - line = logical_input_line ? logical_input_line : physical_input_line; - fprintf(stderr,"%s:%u:", p, line); -#endif - } - else - { -#ifdef DONTDEF - fprintf (stderr," After reading source.\n"); -#else - p = logical_input_file ? logical_input_file : physical_input_file; - line = logical_input_line ? logical_input_line : physical_input_line; - fprintf (stderr,"%s:unknown:", p); -#endif - } - } - else - { -#ifdef DONTDEF - fprintf (stderr," Before reading source.\n"); -#else -#endif - } -} - -/* - * Support for source file debugging. These functions handle - * logical lines and logical files. - */ -static char *saved_file; -static int saved_len; -static line_numberT saved_line; -void -filestab() -{ - char *file; - int len; - - if (!physical_input_file || - !input_file_is_open()) - return; - - file = logical_input_file ? logical_input_file : physical_input_file; - - if (saved_file == 0 || strcmp(file, saved_file) != 0) - { - stabs(file); - len = strlen(file) + 1; - if (len > saved_len) - { - if (saved_file == 0) - saved_file = xmalloc(len); - else - saved_file = xrealloc(saved_file, len); - memcpy(saved_file, file, len); - saved_len = len; - } - else - strcpy(saved_file, file); - saved_line = 0; - } -} - -void -funcstab(func) - char *func; -{ - if (now_seg != SEG_TEXT) - return; - - filestab(); - stabf(func); -} - -void -linestab() -{ - line_numberT line; - - if (now_seg != SEG_TEXT) - return; - - filestab(); - - line = logical_input_line ? logical_input_line : physical_input_line; - if (saved_line == 0 || line != saved_line) - { - stabd(line); - saved_line = line; - } -} /* - * a s _ h o w m u c h ( ) + * 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. */ + 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); - } + register char * p; /* Scan input line. */ + /* register char c; JF unused */ + + for (p = input_line_pointer - 1; * p != '\n'; --p) + { + } + ++ p; /* p->1st char of line. */ + for (; p <= input_line_pointer; p++) + { + /* Assume ASCII. EBCDIC & other micro-computer char sets ignored. */ + /* c = *p & 0xFF; JF unused */ + as_1_char(*p, stream); + } } -static void -as_1_char (c,stream) - unsigned char c; - FILE * stream; +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); + if (c > 127) + { + (void)putc('%', stream); + c -= 128; + } + if (c < 32) + { + (void)putc('^', stream); + c += '@'; + } + (void)putc(c, stream); } -/* end: input_scrub.c */ +/* + * 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 0000000..a035ca8 --- /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 0000000..2f8b1f0 --- /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/10/02 20:57:40 pk 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 0000000..37a8e87 --- /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/10/02 20:57:41 pk 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 0000000..cb3064d --- /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 0000000..89c74c7 --- /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/10/02 20:57:43 pk 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 index a7b1205..b1ba3f7 100644 --- a/gnu/usr.bin/as/messages.c +++ b/gnu/usr.bin/as/messages.c @@ -1,63 +1,115 @@ /* messages.c - error reporter - - Copyright (C) 1987 Free Software Foundation, Inc. + 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. */ -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifndef lint +static char rcsid[] = "$Id: messages.c,v 1.3 1993/10/02 20:57:45 pk Exp $"; +#endif -#include <stdio.h> /* define stderr */ -#ifdef VMS -#include <errno.h> /* Need this to make errno declaration right */ -#include <perror.h> /* Need this to make sys_errlist/sys_nerr right */ -#endif /* VMS */ +#include <stdio.h> /* define stderr */ +#include <errno.h> #include "as.h" +#ifndef NO_STDARG +#include <stdarg.h> +#else #ifndef NO_VARARGS #include <varargs.h> -#endif +#endif /* NO_VARARGS */ +#endif /* NO_STDARG */ /* - 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(). + * 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. + */ -as_fatal(fmt,args) Like as_warn() but exit with a fatal status. +/* + 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 */ -int bad_error = 0; +static int error_count = 0; + +int had_errors() { + return(error_count); +} /* had_errors() */ /* @@ -65,27 +117,22 @@ int bad_error = 0; * * Like perror(3), but with more info. */ -/* JF moved from input-scrub.c to here. */ -void -as_perror(gripe, filename) - char * gripe; /* Unpunctuated error theme. */ - char * filename; -{ - extern int errno; /* See perror(3) for details. */ - extern int sys_nerr; - extern char * sys_errlist[]; - - as_where(); - fprintf (stderr,gripe,filename); - if (errno > sys_nerr) - fprintf (stderr, "Unknown error #%d.\n", errno); - else - fprintf (stderr, "%s.\n", sys_errlist [errno]); - errno = 0; /* After reporting, clear it. */ -} +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 _ w a r n ( ) + * 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). @@ -93,51 +140,138 @@ as_perror(gripe, filename) * Please explain in string (which may have '\n's) what recovery was done. */ -#ifdef NO_VARARGS -/*VARARGS1*/ -as_warn(Format,args) -char *Format; +#ifndef NO_STDARG +void as_tsktsk(Format) +const char *Format; { - if ( ! flagseen ['W']) /* -W supresses warning messages. */ - { - as_where(); - _doprnt (Format, &args, stderr); - (void)putc ('\n', stderr); - /* as_where(); */ - } -} + va_list args; + + as_where(); + va_start(args, Format); + vfprintf(stderr, Format, args); + va_end(args); + (void) putc('\n', stderr); +} /* as_tsktsk() */ #else -void -as_warn(Format,va_alist) +#ifndef NO_VARARGS +void as_tsktsk(Format,va_alist) char *Format; va_dcl { - va_list args; - - if( ! flagseen['W']) - { - as_where(); - va_start(args); - vfprintf(stderr, Format, args); - va_end(args); - (void) putc('\n', stderr); - } -} + 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) +void as_warn(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) char *format; { - if(!flagseen['W']) { + 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 ( ) + * 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). @@ -146,46 +280,76 @@ char *format; * Please explain in string (which may have '\n's) what recovery was done. */ -#ifdef NO_VARARGS -/*VARARGS1*/ -as_bad(Format,args) -char *Format; +#ifndef NO_STDARG +void as_bad(Format) +const char *Format; { - bad_error=1; - as_where(); - _doprnt (Format, &args, stderr); - (void)putc ('\n', stderr); - /* as_where(); */ -} + 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 -void -as_bad(Format,va_alist) +#ifndef NO_VARARGS +void as_bad(Format,va_alist) char *Format; va_dcl { - va_list args; - - bad_error=1; - as_where(); - va_start(args); - vfprintf(stderr, Format, args); - va_end(args); - (void) putc('\n', stderr); -} + 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) +void as_bad(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) char *format; { + ++error_count; as_where(); - bad_error=1; fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an); (void)putc('\n',stderr); -} +} /* as_bad() */ #endif + /* - * a s _ f a t a l ( ) + * 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). @@ -193,46 +357,61 @@ char *format; * It exit()s with a warning status. */ -#ifdef NO_VARARGS -/*VARARGS1*/ -as_fatal (Format, args) -char *Format; +#ifndef NO_STDARG +void as_fatal(Format) +const char *Format; { - as_where(); - fprintf(stderr,"FATAL:"); - _doprnt (Format, &args, stderr); - (void)putc ('\n', stderr); - /* as_where(); */ - exit(42); /* What is a good exit status? */ -} + 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 -void -as_fatal(Format,va_alist) +#ifndef NO_VARARGS +void as_fatal(Format,va_alist) char *Format; va_dcl { - va_list args; + 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 */ - as_where(); - va_start(args); - fprintf (stderr, "FATAL:"); - vfprintf(stderr, Format, args); - (void) putc('\n', stderr); - va_end(args); - exit(42); -} -#endif #ifdef DONTDEF -void -as_fatal(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) +void as_fatal(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) char *Format; { - as_where(); - fprintf (stderr, "FATAL:"); - fprintf(stderr, Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an); - (void) putc('\n', stderr); - exit(42); -} + as_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: messages.c */ +/* 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 0000000..ac5b158 --- /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/10/02 20:57:45 pk 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 index c9cf561..d7302ea 100644 --- a/gnu/usr.bin/as/obstack.c +++ b/gnu/usr.bin/as/obstack.c @@ -3,7 +3,7 @@ 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 +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, @@ -15,6 +15,10 @@ 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.3 1993/10/02 20:57:47 pk Exp $"; +#endif + #include "obstack.h" #ifdef __STDC__ @@ -87,8 +91,10 @@ _obstack_begin (h, size, alignment, chunkfun, freefun) 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; + = (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 @@ -140,8 +146,9 @@ _obstack_newchunk (h, length) new_chunk->contents[i] = h->object_base[i]; /* If the object just copied was the only data in OLD_CHUNK, - free that chunk and remove it from the chain. */ - if (h->object_base == old_chunk->contents) + 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); @@ -149,6 +156,8 @@ _obstack_newchunk (h, length) 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. @@ -164,62 +173,90 @@ _obstack_allocated_p (h, obj) register struct _obstack_chunk* plp; /* point to previous chunk if any */ lp = (h)->chunk; - while (lp != 0 && ((POINTER)lp > obj || (POINTER)(lp)->limit < obj)) + /* 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; + plp = lp->prev; lp = plp; } return lp != 0; } - + /* Free objects in obstack H, including OBJ and everything allocate more recently than OBJ. If OBJ is zero, free everything in H. */ -void -#ifdef __STDC__ #undef obstack_free -obstack_free (struct obstack *h, POINTER obj) -#else + +/* 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; -#endif { register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */ register struct _obstack_chunk* plp; /* point to previous chunk if any */ - lp = (h)->chunk; + 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; + 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; + h->object_base = h->next_free = (char *)(obj); + h->chunk_limit = lp->limit; + h->chunk = lp; } else if (obj != 0) /* obj is not in any of the chunks! */ abort (); } -/* Let same .o link with output of gcc and other compilers. */ +/* This function is used from ANSI code. */ -#ifdef __STDC__ void -_obstack_free (h, obj) +obstack_free (h, obj) struct obstack *h; POINTER obj; { - obstack_free (h, 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 (); } -#endif #if 0 /* These are now turned off because the applications do not use it diff --git a/gnu/usr.bin/as/obstack.h b/gnu/usr.bin/as/obstack.h index fd779c4..880015f 100644 --- a/gnu/usr.bin/as/obstack.h +++ b/gnu/usr.bin/as/obstack.h @@ -3,7 +3,7 @@ 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 +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, @@ -14,6 +14,10 @@ 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.3 1993/10/02 20:57:48 pk Exp $ + */ + /* Summary: @@ -133,6 +137,10 @@ struct obstack /* control current object in current chunk */ 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. */ @@ -211,17 +219,20 @@ int obstack_chunk_size (struct obstack *obstack); #define obstack_init(h) \ _obstack_begin ((h), 0, 0, \ - (void *(*) ()) obstack_chunk_alloc, obstack_chunk_free) + (void *(*) ()) obstack_chunk_alloc, (void (*) ())obstack_chunk_free) #define obstack_begin(h, size) \ _obstack_begin ((h), (size), 0, \ - (void *(*) ()) obstack_chunk_alloc, obstack_chunk_free) + (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 @@ -229,10 +240,12 @@ int obstack_chunk_size (struct obstack *obstack); 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); }) @@ -242,25 +255,28 @@ int obstack_chunk_size (struct obstack *obstack); 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); \ - bcopy (where, __o->next_free, __len); \ + 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), \ - bcopy (where, __o->next_free, __len), \ + 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), \ @@ -272,23 +288,26 @@ int obstack_chunk_size (struct obstack *obstack); 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 ***)&__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); \ + *(*(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_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) \ @@ -297,33 +316,42 @@ int obstack_chunk_size (struct obstack *obstack); (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) \ -({ struct obstack *__o = (OBSTACK); \ - void *value = (void *) __o->object_base; \ - __o->next_free \ - = __INT_TO_PTR ((__PTR_TO_INT (__o->next_free)+__o->alignment_mask)\ - & ~ (__o->alignment_mask)); \ - ((__o->next_free - (char *)__o->chunk \ - > __o->chunk_limit - (char *)__o->chunk) \ - ? (__o->next_free = __o->chunk_limit) : 0); \ - __o->object_base = __o->next_free; \ +__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) \ @@ -342,14 +370,14 @@ int obstack_chunk_size (struct obstack *obstack); ( (h)->temp = (length), \ (((h)->next_free + (h)->temp > (h)->chunk_limit) \ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \ - bcopy (where, (h)->next_free, (h)->temp), \ + 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), \ - bcopy (where, (h)->next_free, (h)->temp), \ + memcpy ((h)->next_free, where, (h)->temp), \ (h)->next_free += (h)->temp, \ *((h)->next_free)++ = 0) @@ -361,16 +389,15 @@ int obstack_chunk_size (struct obstack *obstack); #define obstack_ptr_grow(h,datum) \ ( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \ ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \ - *((char **)(((h)->next_free+=sizeof(char *))-sizeof(char *))) = ((char *)datum)) + *(*(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+=sizeof(int))-sizeof(int))) = ((int)datum)) - -#define obstack_ptr_grow_fast(h,aptr) (*((char **)(h)->next_free)++ = (char *)aptr) -#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint) + *(*(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) \ @@ -387,7 +414,10 @@ int obstack_chunk_size (struct obstack *obstack); (obstack_grow0 ((h), (where), (length)), obstack_finish ((h))) #define obstack_finish(h) \ -( (h)->temp = __PTR_TO_INT ((h)->object_base), \ +( ((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)), \ @@ -400,14 +430,14 @@ int obstack_chunk_size (struct obstack *obstack); #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)\ + (((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)\ + (((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))) diff --git a/gnu/usr.bin/as/opcode/ChangeLog b/gnu/usr.bin/as/opcode/ChangeLog new file mode 100644 index 0000000..dcb0498 --- /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 0000000..8c36167 --- /dev/null +++ b/gnu/usr.bin/as/opcode/a29k.h @@ -0,0 +1,327 @@ +/* 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/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 0000000..f4702a8 --- /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 0000000..cc8fe1c --- /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.2 1993/10/04 22:53:32 pk 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 0000000..0842786 --- /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 0000000..e9c8cb4 --- /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/10/02 21:00:44 pk 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 0000000..dda8337 --- /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 0000000..5f685b9 --- /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 0000000..a65678a --- /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 0000000..6546825 --- /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 0000000..2a7621a --- /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 0000000..fde4764 --- /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 0000000..06632b8 --- /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 0000000..3c52464 --- /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/10/02 21:00:55 pk 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 0000000..27099a4 --- /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 0000000..d604e3f --- /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 index ff71f40..7439e86 100644 --- a/gnu/usr.bin/as/output-file.c +++ b/gnu/usr.bin/as/output-file.c @@ -1,21 +1,21 @@ /* output-file.c - Deal with the output file - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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. @@ -24,58 +24,99 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ * Note we don't need to #include the "as.h" file. No common coupling! */ -/* #include "style.h" */ +/* note that we do need config info. xoxorich. */ + +#ifndef lint +static char rcsid[] = "$Id: output-file.c,v 1.3 1993/10/02 20:57:49 pk Exp $"; +#endif + #include <stdio.h> -void as_perror(); +#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() */ -static FILE * -stdoutput; -void -output_file_create (name) - char * name; +void output_file_close(filename) +char *filename; { - if(name[0]=='-' && name[1]=='\0') - stdoutput=stdout; - else if ( ! (stdoutput = fopen( name, "w" )) ) - { - as_perror ("FATAL: Can't create %s", name); - exit(42); - } -} + /* 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_close (filename) - char * filename; +void output_file_create(name) +char *name; { - if ( EOF == fclose( stdoutput ) ) - { - as_perror ("FATAL: Can't close %s", filename); - exit(42); - } - stdoutput = NULL; /* Trust nobody! */ -} - -void -output_file_append (where, length, filename) - char * where; - long int length; - char * filename; + 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() */ - 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"); +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: output-file.c */ +/* 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 0000000..e7d7b97 --- /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/10/02 20:57:49 pk 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 index 8357107..61e9a3e 100644 --- a/gnu/usr.bin/as/read.c +++ b/gnu/usr.bin/as/read.c @@ -1,1083 +1,1068 @@ -/*- - * This code is derived from software copyrighted by the Free Software - * Foundation. - * - * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. - */ - -#ifndef lint -static char sccsid[] = "@(#)read.c 6.4 (Berkeley) 5/8/91"; -#endif /* not lint */ - /* read.c - read a source file - - Copyright (C) 1986,1987 Free Software Foundation, Inc. -This file is part of GAS, the GNU Assembler. + 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. */ -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifndef lint +static char rcsid[] = "$Id: read.c,v 1.3 1993/10/02 20:57:51 pk 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. */ +/* This is the largest known floating point */ +/* format (for now). It will grow when we */ +/* do 4361 style flonums. */ /* Routines that read assembler source text to build spagetti in memory. */ /* Another group of these functions is in the as-expr.c module */ -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> #include "as.h" -#include "read.h" -#include "md.h" -#include "hash.h" + #include "obstack.h" -#include "frags.h" -#include "flonum.h" -#include "struc-symbol.h" -#include "expr.h" -#include "symbols.h" - -#ifdef SPARC -#include "sparc.h" -#define OTHER_ALIGN -#endif -#ifdef I860 -#include "i860.h" -#endif -char * input_line_pointer; /* -> next char of source file to parse. */ +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!) ! + a char does not have exactly 256 states (hopefully 0:255!) ! +#endif + +#ifdef ALLOW_ATSIGN +#define AT 2 +#else +#define AT 0 #endif -const char /* used by is_... macros. our ctype[] */ -lex_type [256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ABCDEFGHIJKLMNO */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* PQRSTUVWXYZ[\]^_ */ - 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0123456789:;<=>? */ - 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, /* PQRSTUVWXYZ[\]^_ */ - 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, /* pqrstuvwxyz{|}~. */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; +#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: TRUE if this character ends a line. + * Out: 1 if this character ends a line. */ #define _ (0) -const char is_end_of_line [256] = { - _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, _, /* @abcdefghijklmno */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, /* 0123456789:;<=>? */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ /* */ -}; +char is_end_of_line[256] = { +#ifdef CR_EOL + _, _, _, _, _, _, _, _, _, _,99, _, _, 99, _, _,/* @abcdefghijklmno */ +#else + _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, _, /* @abcdefghijklmno */ +#endif + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, /* 0123456789:;<=>? */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ /* */ + }; #undef _ - /* Functions private to this file. */ -void equals(); -void big_cons(); -void cons(); -static char* demand_copy_C_string(); -static char* demand_copy_string(); -void demand_empty_rest_of_line(); -void float_cons(); -long int get_absolute_expression(); -static char get_absolute_expression_and_terminator(); -static segT get_known_segmented_expression(); -void ignore_rest_of_line(); -static int is_it_end_of_statement(); -static void pobegin(); -static void pseudo_set(); -static void stab(); -static void stringer(); - -extern char line_comment_chars[]; - -static char * buffer_limit; /* -> 1 + last char in buffer. */ - -static char * bignum_low; /* Lowest char of bignum. */ -static char * bignum_limit; /* 1st illegal address of bignum. */ -static char * bignum_high; /* Highest char of bignum. */ - /* May point to (bignum_start-1). */ - /* Never >= bignum_limit. */ +/* 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 -static void grow_bignum (); -static int next_char_of_string (); +#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() + read_begin() { - pobegin(); - obstack_begin( ¬es, 5000 ); + 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; + 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 */ -static struct hash_control * -po_hash = NULL; /* use before set up: NULL-> address error */ - - -void s_abort(), s_align(), s_comm(), s_data(); -void s_desc(), s_even(), s_file(), s_fill(); -void s_globl(), s_lcomm(), s_line(), s_lsym(); -void s_org(), s_set(), s_space(), s_text(); -#ifdef VMS -char const_flag = 0; -void s_const(); -#endif - -#ifdef DONTDEF -void s_gdbline(), s_gdblinetab(); -void s_gdbbeg(), s_gdbblock(), s_gdbend(), s_gdbsym(); -#endif - -void stringer(); -void cons(); -void float_cons(); -void big_cons(); -void stab(); +struct hash_control * + po_hash = NULL; /* use before set up: NULL->address error */ static const pseudo_typeS -potable[] = + potable[] = { - { "abort", s_abort, 0 }, - { "align", s_align, 0 }, - { "ascii", stringer, 0 }, - { "asciz", stringer, 1 }, - { "byte", cons, 1 }, - { "comm", s_comm, 0 }, -#ifdef VMS - { "const", s_const, 0 }, -#endif - { "data", s_data, 0 }, - { "desc", s_desc, 0 }, - { "double", float_cons, 'd' }, - { "file", s_file, 0 }, - { "fill", s_fill, 0 }, - { "float", float_cons, 'f' }, -#ifdef DONTDEF - { "gdbbeg", s_gdbbeg, 0 }, - { "gdbblock", s_gdbblock, 0 }, - { "gdbend", s_gdbend, 0 }, - { "gdbsym", s_gdbsym, 0 }, - { "gdbline", s_gdbline, 0 }, - { "gdblinetab",s_gdblinetab, 0 }, -#endif - { "globl", s_globl, 0 }, - { "int", cons, 4 }, - { "lcomm", s_lcomm, 0 }, - { "line", s_line, 0 }, - { "long", cons, 4 }, - { "lsym", s_lsym, 0 }, - { "octa", big_cons, 16 }, - { "org", s_org, 0 }, - { "quad", big_cons, 8 }, - { "set", s_set, 0 }, - { "short", cons, 2 }, - { "single", float_cons, 'f' }, - { "space", s_space, 0 }, - { "stabd", stab, 'd' }, - { "stabn", stab, 'n' }, - { "stabs", stab, 's' }, - { "text", s_text, 0 }, -#ifndef SPARC - { "word", cons, 2 }, -#endif - { NULL} /* end sentinel */ + { "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(); - errtxt = ""; /* OK so far */ - for (pop=potable; pop->poc_name && !*errtxt; pop++) - { - errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop); - } - - for(pop=md_pseudo_table; pop->poc_name && !*errtxt; pop++) - errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop); - - if (*errtxt) - { - as_fatal ("error constructing pseudo-op table"); - } -} /* pobegin() */ +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() */ -/* read_a_source_file() - * - * File has already been opened, and will be closed by our caller. +#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 (buffer) - char * buffer; /* 1st character of each buffer of lines is here. */ +void read_a_source_file(name) +char *name; { - register char c; - register char * s; /* string of symbol, '\0' appended */ - register int temp; - /* register struct frag * fragP; JF unused */ /* a frag we just made */ - pseudo_typeS *pop; -#ifdef DONTDEF - void gdb_block_beg(); - void gdb_block_position(); - void gdb_block_end(); - void gdb_symbols_fixup(); -#endif - - subseg_new (SEG_TEXT, 0); - while ( buffer_limit = input_scrub_next_buffer (&buffer) ) - { /* We have another line to parse. */ - know( buffer_limit [-1] == '\n' ); /* Must have a sentinel. */ - input_line_pointer = buffer; - contin: /* JF this goto is my fault I admit it. Someone brave please re-write + 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 (); - } - /* - * We are at the begining of a line, or similar place. - * We expect a well-formed assembler statement. - * A "symbol-name:" is a statement. - * - * Depending on what compiler is used, the order of these tests - * may vary to catch most common case 1st. - * Each test is independent of all other tests at the (top) level. - * PLEASE make a compiler that doesn't use this assembler. - * It is crufty to waste a compiler's time encoding things for this - * assembler, which then wastes more time decoding it. - * (And communicating via (linear) files is silly! - * If you must pass stuff, please pass a tree!) - */ - if ( (c= * input_line_pointer ++) == '\t' || c == ' ' || c=='\f') - { - c = * input_line_pointer ++; - } - know( c != ' ' ); /* No further leading whitespace. */ - /* - * C is the 1st significant character. - * Input_line_pointer points after that character. - */ - if ( is_name_beginner(c) ) - { /* want user-defined label or pseudo/opcode */ - s = -- input_line_pointer; - c = get_symbol_end(); /* name's delimiter */ - /* - * C is character after symbol. - * That character's place in the input line is now '\0'. - * S points to the beginning of the symbol. - * [In case of pseudo-op, s -> '.'.] - * Input_line_pointer -> '\0' where c was. - */ - if ( c == ':' ) - { - if (flagseen['g']) - /* set line number for function definition */ - funcstab(s); - colon(s); /* user-defined label */ - * input_line_pointer ++ = ':'; /* Put ':' back for error messages' sake. */ - /* Input_line_pointer -> after ':'. */ - SKIP_WHITESPACE(); - } - else if(c=='=' || input_line_pointer[1]=='=') /* JF deal with FOO=BAR */ - { - equals(s); - demand_empty_rest_of_line(); - } - else - { /* expect pseudo-op or machine instruction */ - if ( *s=='.' ) - { - /* - * PSEUDO - OP. - * - * WARNING: c has next char, which may be end-of-line. - * We lookup the pseudo-op table with s+1 because we - * already know that the pseudo-op begins with a '.'. - */ - - pop= (pseudo_typeS *) hash_find (po_hash, s+1); - - /* Print the error msg now, while we still can */ - if(!pop) - as_bad("Unknown pseudo-op: '%s'",s); - - /* Put it back for error messages etc. */ - * input_line_pointer = c; - /* The following skip of whitespace is compulsory. */ - /* A well shaped space is sometimes all that seperates keyword from operands. */ - if ( c == ' ' || c == '\t' ) - { /* Skip seperator after keyword. */ - input_line_pointer ++; - } - /* - * Input_line is restored. - * Input_line_pointer -> 1st non-blank char - * after pseudo-operation. - */ - if(!pop) { - ignore_rest_of_line(); - break; - } - else - (*pop->poc_handler)(pop->poc_val); - } - else - { /* machine instruction */ - /* If source file debugging, emit a stab. */ - if (flagseen['g']) - linestab(); - - /* WARNING: c has char, which may be end-of-line. */ - /* Also: input_line_pointer -> `\0` where c was. */ - * input_line_pointer = c; - while ( ! is_end_of_line [* input_line_pointer] ) - { - input_line_pointer ++; + 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++; } - c = * input_line_pointer; - * input_line_pointer = '\0'; - md_assemble (s); /* Assemble 1 instruction. */ - * input_line_pointer ++ = c; - /* We resume loop AFTER the end-of-line from this instruction */ - } /* if (*s=='.') */ - } /* if c==':' */ - continue; - } /* if (is_name_beginner(c) */ - - - if ( is_end_of_line [c] ) - { /* empty statement */ - continue; - } - - if ( isdigit(c) ) - { /* local label ("4:") */ - temp = c - '0'; -#ifdef SUN_ASM_SYNTAX - if( *input_line_pointer=='$') - input_line_pointer++; + 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 - if ( * input_line_pointer ++ == ':' ) - { - local_colon (temp); - } - else - { - as_bad( "Spurious digit %d.", temp); - input_line_pointer -- ; - ignore_rest_of_line(); - } - continue; - } - if(c && index(line_comment_chars,c)) { /* Its a comment. Better say APP or NO_APP */ - char *ends; - char *strstr(); - char *new_buf; - char *new_tmp; - int new_length; - char *tmp_buf = 0; - extern char *scrub_string,*scrub_last_string; - int scrub_from_string(); - void scrub_to_string(); - - bump_line_counters(); - s=input_line_pointer; - if(strncmp(s,"APP\n",4)) - continue; /* We ignore it */ - s+=4; - - ends=strstr(s,"#NO_APP\n"); - - if(!ends) { - int tmp_len; - int num; - - /* The end of the #APP wasn't in this buffer. We - keep reading in buffers until we find the #NO_APP - that goes with this #APP There is one. The specs - guarentee it. . .*/ - tmp_len=buffer_limit-s; - tmp_buf=xmalloc(tmp_len); - bcopy(s,tmp_buf,tmp_len); - do { - new_tmp = input_scrub_next_buffer(&buffer); - if(!new_tmp) - break; - else - buffer_limit = new_tmp; - input_line_pointer = buffer; - ends = strstr(buffer,"#NO_APP\n"); - if(ends) - num=ends-buffer; - else - num=buffer_limit-buffer; - - tmp_buf=xrealloc(tmp_buf,tmp_len+num); - bcopy(buffer,tmp_buf+tmp_len,num); - tmp_len+=num; - } while(!ends); - - input_line_pointer= ends ? ends+8 : NULL; - - s=tmp_buf; - ends=s+tmp_len; - - } else { - input_line_pointer=ends+8; - } - new_buf=xmalloc(100); - new_length=100; - new_tmp=new_buf; - - scrub_string=s; - scrub_last_string = ends; - for(;;) { - int ch; - - ch=do_scrub_next_char(scrub_from_string,scrub_to_string); - if(ch==EOF) break; - *new_tmp++=ch; - if(new_tmp==new_buf+new_length) { - new_buf=xrealloc(new_buf,new_length+100); - new_tmp=new_buf+new_length; - new_length+=100; + ) { + /* + * 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() */ - if(tmp_buf) - free(tmp_buf); - old_buffer=buffer; - old_input=input_line_pointer; - old_limit=buffer_limit; - buffer=new_buf; - input_line_pointer=new_buf; - buffer_limit=new_tmp; - continue; - } - - as_bad("Junk character %d.",c); - ignore_rest_of_line(); - } /* while (input_line_pointer<buffer_limit )*/ - if(old_buffer) { - bump_line_counters(); - if(old_input == 0) - return; - buffer=old_buffer; - input_line_pointer=old_input; - buffer_limit=old_limit; - old_buffer = 0; - goto contin; - } - } /* while (more bufrers to scan) */ -} /* read_a_source_file() */ - -void -s_abort() -{ +void s_abort() { as_fatal(".abort detected. Abandoning ship."); -} +} /* s_abort() */ -#ifdef OTHER_ALIGN -static void -s_align() +/* 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 int temp_fill; - unsigned int i; - - temp = get_absolute_expression (); -#define MAX_ALIGNMENT (1 << 15) - if ( temp > MAX_ALIGNMENT ) { - as_bad("Alignment too large: %d. assumed.", temp = MAX_ALIGNMENT); - } - - /* - * For the sparc, `.align (1<<n)' actually means `.align n' - * so we have to convert it. - */ - if (temp != 0) { - for (i = 0; (temp & 1) == 0; temp >>= 1, ++i) - ; - } - if (temp != 1) - as_bad("Alignment not a power of 2"); - - temp = i; - if (*input_line_pointer == ',') { - input_line_pointer ++; - temp_fill = get_absolute_expression (); - } else { - temp_fill = 0; - } - /* Only make a frag if we HAVE to. . . */ - if (temp && ! need_pass_2) - frag_align (temp, (int)temp_fill); - - demand_empty_rest_of_line(); -} -#else + 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() */ -void -s_align() -{ +/* For machines where ".align 4" means align to 2**4 boundary. */ +void s_align_ptwo() { register int temp; - register long int temp_fill; - - temp = get_absolute_expression (); -#define MAX_ALIGNMENT (15) - if ( temp > MAX_ALIGNMENT ) - as_bad("Alignment too large: %d. assumed.", temp = MAX_ALIGNMENT); - else if ( temp < 0 ) { + 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 == ',' ) { + if (*input_line_pointer == ',') { input_line_pointer ++; - temp_fill = get_absolute_expression (); + temp_fill = get_absolute_expression(); } else - temp_fill = 0; - /* Only make a frag if we HAVE to. . . */ - if ( temp && ! need_pass_2 ) - frag_align (temp, (int)temp_fill); + 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(); -} -#endif +} /* s_align_ptwo() */ -void -s_comm() -{ +void s_comm() { register char *name; register char c; register char *p; register int temp; - register symbolS * symbolP; - + 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"); + 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 ) { + 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); + symbolP = symbol_find_or_make(name); *p = c; - if ( (symbolP -> sy_type & N_TYPE) != N_UNDF || - symbolP -> sy_other != 0 || symbolP -> sy_desc != 0) { - as_warn( "Ignoring attempt to re-define symbol"); + if (S_IS_DEFINED(symbolP)) { + as_bad("Ignoring attempt to re-define symbol"); ignore_rest_of_line(); return; } - if (symbolP -> sy_value) { - if (symbolP -> sy_value != temp) - as_warn( "Length of .comm \"%s\" is already %d. Not changed to %d.", - symbolP -> sy_name, symbolP -> sy_value, temp); + 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 { - symbolP -> sy_value = temp; - symbolP -> sy_type |= N_EXT; + S_SET_VALUE(symbolP, temp); + S_SET_EXTERNAL(symbolP); } -#ifdef VMS - if(!temp) - symbolP->sy_other = const_flag; -#endif - know( symbolP -> sy_frag == &zero_address_frag ); +#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() */ -#ifdef VMS void -s_const() + s_data() { register int temp; - - temp = get_absolute_expression (); + + temp = get_absolute_expression(); +#ifdef MANY_SEGMENTS + subseg_new (SEG_E1, (subsegT)temp); +#else subseg_new (SEG_DATA, (subsegT)temp); - const_flag = 1; - demand_empty_rest_of_line(); -} #endif - -void -s_data() -{ - register int temp; - - temp = get_absolute_expression (); - subseg_new (SEG_DATA, (subsegT)temp); -#ifdef VMS + +#ifdef OBJ_VMS const_flag = 0; -#endif - demand_empty_rest_of_line(); -} - -void -s_desc() -{ - register char *name; - register char c; - register char *p; - register symbolS * symbolP; - register int temp; - - /* - * Frob invented at RMS' request. Set the n_desc of a symbol. - */ - name = input_line_pointer; - c = get_symbol_end(); - p = input_line_pointer; - symbolP = symbol_table_lookup (name); - * p = c; - SKIP_WHITESPACE(); - if ( * input_line_pointer != ',' ) { - *p = 0; - as_bad("Expected comma after name \"%s\"", name); - *p = c; - ignore_rest_of_line(); - } else { - input_line_pointer ++; - temp = get_absolute_expression (); - *p = 0; - symbolP = symbol_find_or_make (name); - *p = c; - symbolP -> sy_desc = temp; - } +#endif /* not OBJ_VMS */ demand_empty_rest_of_line(); } -void -s_file() -{ +void s_app_file() { register char *s; - int length; - + int length; + /* Some assemblers tolerate immediately following '"' */ - if ( s = demand_copy_string( & length ) ) { - new_logical_line (s, -1); + if ((s = demand_copy_string(&length)) != 0) { + new_logical_line(s, -1); demand_empty_rest_of_line(); } -} - -void -s_fill() -{ - long int temp_repeat; - long int temp_size; - register long int temp_fill; - char *p; - - if ( get_absolute_expression_and_terminator(& temp_repeat) != ',' ) { +#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_warn("Expect comma after rep-size in .fill"); + 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_warn("Expected comma after 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 ) { + 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 ) { + } if (temp_size < 0) { as_warn("Size negative: .fill ignored."); temp_size = 0; - } else if ( temp_repeat <= 0 ) { + } else if (temp_repeat <= 0) { as_warn("Repeat < 0, .fill ignored"); temp_size = 0; } - temp_fill = get_absolute_expression (); - if ( temp_size && !need_pass_2 ) { - p = frag_var (rs_fill, (int)temp_size, (int)temp_size, (relax_substateT)0, (symbolS *)0, temp_repeat, (char *)0); - bzero (p, (int)temp_size); -/* - * The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX flavoured AS. - * The following bizzare behaviour is to be compatible with above. - * I guess they tried to take up to 8 bytes from a 4-byte expression - * and they forgot to sign extend. Un*x Sux. - */ + 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. - */ + /* + * Note: .fill (),0 emits no frag (since we are asked to .fill 0 bytes) + * but emits no error message because it seems a legal thing to do. + * It is a degenerate case of .fill but could be emitted by a compiler. + */ } demand_empty_rest_of_line(); } -#ifdef DONTDEF -void -s_gdbbeg() -{ - register int temp; - - temp = get_absolute_expression (); - if (temp < 0) - as_warn( "Block number <0. Ignored." ); - else if (flagseen ['G']) - gdb_block_beg ( (long int) temp, frag_now, (long int)(obstack_next_free(& frags) - frag_now -> fr_literal)); - demand_empty_rest_of_line (); -} - -void -s_gdbblock() -{ - register int position; - int temp; - - if (get_absolute_expression_and_terminator (&temp) != ',') { - as_warn( "expected comma before position in .gdbblock"); - --input_line_pointer; - ignore_rest_of_line (); - return; - } - position = get_absolute_expression (); - if (flagseen ['G']) - gdb_block_position ((long int) temp, (long int) position); - demand_empty_rest_of_line (); -} - -void -s_gdbend() -{ - register int temp; - - temp = get_absolute_expression (); - if (temp < 0) - as_warn( "Block number <0. Ignored." ); - else if (flagseen ['G']) - gdb_block_end ( (long int) temp, frag_now, (long int)(obstack_next_free(& frags) - frag_now -> fr_literal)); - demand_empty_rest_of_line (); -} - -void -s_gdbsym() -{ - register char *name, - *p; - register char c; - register symbolS * symbolP; - register int temp; - - name = input_line_pointer; - c = get_symbol_end(); - p = input_line_pointer; - symbolP = symbol_find_or_make (name); - *p = c; - SKIP_WHITESPACE(); - if ( * input_line_pointer != ',' ) { - as_warn("Expected comma after name"); - ignore_rest_of_line(); - return; - } - input_line_pointer ++; - if ( (temp = get_absolute_expression ()) < 0 ) { - as_warn("Bad GDB symbol file offset (%d.) <0! Ignored.", temp); - ignore_rest_of_line(); - return; - } - if (flagseen ['G']) - gdb_symbols_fixup (symbolP, (long int)temp); - demand_empty_rest_of_line (); -} - -void -s_gdbline() -{ - int file_number, - lineno; - - if(get_absolute_expression_and_terminator(&file_number) != ',') { - as_warn("expected comman after filenum in .gdbline"); - ignore_rest_of_line(); - return; - } - lineno=get_absolute_expression(); - if(flagseen['G']) - gdb_line(file_number,lineno); - demand_empty_rest_of_line(); -} - - -void -s_gdblinetab() -{ - int file_number, - offset; - - if(get_absolute_expression_and_terminator(&file_number) != ',') { - as_warn("expected comman after filenum in .gdblinetab"); - ignore_rest_of_line(); - return; - } - offset=get_absolute_expression(); - if(flagseen['G']) - gdb_line_tab(file_number,offset); - demand_empty_rest_of_line(); -} -#endif - -void -s_globl() -{ +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); + symbolP = symbol_find_or_make(name); * input_line_pointer = c; SKIP_WHITESPACE(); - symbolP -> sy_type |= N_EXT; - if(c==',') { + S_SET_EXTERNAL(symbolP); + if (c == ',') { input_line_pointer++; SKIP_WHITESPACE(); - if(*input_line_pointer=='\n') - c='\n'; + if (*input_line_pointer == '\n') + c='\n'; } - } while(c==','); + } while (c == ','); demand_empty_rest_of_line(); -} +} /* s_globl() */ -void -s_lcomm() +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_warn("Expected comma after name"); + if (*input_line_pointer != ',') { + as_bad("Expected comma after name"); ignore_rest_of_line(); return; } - input_line_pointer ++; - if ( (temp = get_absolute_expression ()) < 0 ) { + + ++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); + symbolP = symbol_find_or_make(name); *p = c; - if ( symbolP -> sy_other == 0 - && symbolP -> sy_desc == 0 - && ( ( symbolP -> sy_type == N_BSS - && symbolP -> sy_value == local_bss_counter) - || ( (symbolP -> sy_type & N_TYPE) == N_UNDF - && symbolP -> sy_value == 0))) { - symbolP -> sy_value = local_bss_counter; - symbolP -> sy_type = N_BSS; - symbolP -> sy_frag = & bss_address_frag; + + 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_warn( "Ignoring attempt to re-define symbol from %d. to %d.", - symbolP -> sy_value, local_bss_counter ); - demand_empty_rest_of_line(); -} - -void -s_line() -{ - /* Assume delimiter is part of expression. */ - /* BSD4.2 as fails with delightful bug, so we */ - /* are not being incompatible here. */ - new_logical_line ((char *)NULL, (int)(get_absolute_expression ())); + } 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() + s_long() { cons(4); } void -s_int() + s_int() { cons(4); } -void -s_lsym() -{ +void s_lsym() { register char *name; register char c; register char *p; register segT segment; expressionS exp; register symbolS *symbolP; - - /* we permit ANY expression: BSD4.2 demands constants */ + + /* 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 != ',' ) { + if (* input_line_pointer != ',') { *p = 0; - as_warn("Expected comma after name \"%s\"", name); + as_bad("Expected comma after name \"%s\"", name); *p = c; ignore_rest_of_line(); return; } input_line_pointer ++; - segment = expression (& exp); - if ( segment != SEG_ABSOLUTE && segment != SEG_DATA && - segment != SEG_TEXT && segment != SEG_BSS) { - as_bad("Bad expression: %s", seg_name [(int)segment]); + 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; } - know( segment == SEG_ABSOLUTE || segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS ); *p = 0; - symbolP = symbol_new (name,(unsigned char)(seg_N_TYPE [(int) segment]), - 0, 0, (valueT)(exp . X_add_number), & zero_address_frag); + 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() -{ +void s_org() { register segT segment; expressionS exp; - register long int temp_fill; + 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==TRUE. - */ - segment = get_known_segmented_expression(& exp); - if ( *input_line_pointer == ',' ) { + /* + * 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 (); + temp_fill = get_absolute_expression(); } else - temp_fill = 0; - if ( ! need_pass_2 ) { + temp_fill = 0; + if (! need_pass_2) { if (segment != now_seg && segment != SEG_ABSOLUTE) - as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.", - seg_name [(int) segment], seg_name [(int) now_seg]); - p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp . X_add_symbol, - exp . X_add_number, (char *)0); + 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() -{ +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! @@ -1088,386 +1073,301 @@ s_set() end_name = input_line_pointer; *end_name = delim; SKIP_WHITESPACE(); - if ( * input_line_pointer != ',' ) { + + if (*input_line_pointer != ',') { *end_name = 0; - as_warn("Expected comma after name \"%s\"", name); + 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_warn("Illegal segment \"%s\". Segment \"%s\" assumed.", - seg_name [(int) segment], seg_name [(int) now_seg]); - ptr = frag_var (rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol, - exp.X_add_number, (char *)0); - *ptr= 0; - } /* if (ok to make frag) */ - *end_name = delim; - return; + + 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; } - symbolP = symbol_find_or_make (name); + + 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 (); -} + pseudo_set(symbolP); + demand_empty_rest_of_line(); +} /* s_set() */ -void -s_space() -{ - long int temp_repeat; - register long int temp_fill; +void s_size() { + 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(".size 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 (symbolP->sy_size && symbolP->sy_size != temp) { + as_bad("Size of .size \"%s\" is already %d. Not changed to %d.", + symbolP->sy_size, + temp); + } else + symbolP->sy_size = temp; + demand_empty_rest_of_line(); +} /* s_size() */ + +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 (); + 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 ) { + if (temp_repeat <= 0) { as_warn("Repeat < 0, .space ignored"); ignore_rest_of_line(); return; } - if ( ! need_pass_2 ) { + if (! need_pass_2) { p = frag_var (rs_fill, 1, 1, (relax_substateT)0, (symbolS *)0, - temp_repeat, (char *)0); + temp_repeat, (char *)0); * p = temp_fill; } demand_empty_rest_of_line(); -} +} /* s_space() */ void -s_text() + s_text() { register int temp; - - temp = get_absolute_expression (); + + 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. */ +/*(JF was static, but can't be if machine dependent pseudo-ops are to use it */ +void demand_empty_rest_of_line() { + SKIP_WHITESPACE(); + if (is_end_of_line[*input_line_pointer]) { + input_line_pointer++; + } else { + ignore_rest_of_line(); + } + /* Return having already swallowed end-of-line. */ +} /* Return pointing just after end-of-line. */ void -ignore_rest_of_line() /* For suspect lines: gives warning. */ -{ - if ( ! is_end_of_line [* input_line_pointer]) - { - as_warn("Rest of line ignored. 1st junk character valued %d (%c)." - , * input_line_pointer, *input_line_pointer); - while ( input_line_pointer < buffer_limit - && ! is_end_of_line [* input_line_pointer] ) - { - input_line_pointer ++; - } - } - input_line_pointer ++; /* Return pointing just after end-of-line. */ - know( is_end_of_line [input_line_pointer [-1]] ); -} - -/* - * stab() - * - * Handle .stabX directives, which used to be open-coded. - * So much creeping featurism overloaded the semantics that we decided - * to put all .stabX thinking in one place. Here. - * - * We try to make any .stabX directive legal. Other people's AS will often - * do assembly-time consistency checks: eg assigning meaning to n_type bits - * and "protecting" you from setting them to certain values. (They also zero - * certain bits before emitting symbols. Tut tut.) - * - * If an expression is not absolute we either gripe or use the relocation - * information. Other people's assemblers silently forget information they - * don't need and invent information they need that you didn't supply. - * - * .stabX directives always make a symbol table entry. It may be junk if - * the rest of your .stabX directive is malformed. - */ -static void -stab (what) -int what; + ignore_rest_of_line() /* For suspect lines: gives warning. */ { - register symbolS * symbolP; - register char * string; - int saved_type; - int length; - int goof; /* TRUE if we have aborted. */ - long int longint; - -/* - * Enter with input_line_pointer pointing past .stabX and any following - * whitespace. - */ - goof = FALSE; /* JF who forgot this?? */ - if (what == 's') { - string = demand_copy_C_string (& length); - SKIP_WHITESPACE(); - if (* input_line_pointer == ',') - input_line_pointer ++; - else { - as_warn( "I need a comma after symbol's name" ); - goof = TRUE; - } - } else - string = ""; - -/* - * Input_line_pointer->after ','. String -> symbol name. - */ - if (! goof) { - symbolP = symbol_new (string, 0,0,0,0,(struct frag *)0); - switch (what) { - case 'd': - symbolP->sy_name = NULL; /* .stabd feature. */ - symbolP->sy_value = obstack_next_free(& frags) - frag_now->fr_literal; - symbolP->sy_frag = frag_now; - break; - - case 'n': - symbolP->sy_frag = &zero_address_frag; - break; - - case 's': - symbolP->sy_frag = & zero_address_frag; - break; - - default: - BAD_CASE( what ); - break; - } - if (get_absolute_expression_and_terminator (& longint) == ',') - symbolP->sy_type = saved_type = longint; - else { - as_warn( "I want a comma after the n_type expression" ); - goof = TRUE; - input_line_pointer --; /* Backup over a non-',' char. */ - } - } - if (! goof) { - if (get_absolute_expression_and_terminator (& longint) == ',') - symbolP->sy_other = longint; - else { - as_warn( "I want a comma after the n_other expression" ); - goof = TRUE; - input_line_pointer --; /* Backup over a non-',' char. */ - } - } - if (! goof) { - symbolP->sy_desc = get_absolute_expression (); - if (what == 's' || what == 'n') { - if (* input_line_pointer != ',') { - as_warn( "I want a comma after the n_desc expression" ); - goof = TRUE; - } else { + 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 ++; } - } - } - if ((! goof) && (what=='s' || what=='n')) { - pseudo_set (symbolP); - symbolP->sy_type = saved_type; - } - if (goof) - ignore_rest_of_line (); - else - demand_empty_rest_of_line (); + } + 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. + * Input_line_pointer->expression. * - * Out: Input_line_pointer -> just after any whitespace after expression. + * Out: Input_line_pointer->just after any whitespace after expression. * Tried to set symbol to value of expression. - * Will change sy_type, sy_value, sy_frag; - * May set need_pass_2 == TRUE. + * Will change symbols type, value, and frag; + * May set need_pass_2 == 1. */ -static void -pseudo_set (symbolP) - symbolS * symbolP; -{ - expressionS exp; - register segT segment; - int ext; - - know( symbolP ); /* NULL pointer is logic error. */ - ext=(symbolP->sy_type&N_EXT); - if ((segment = expression( & exp )) == SEG_NONE) - { - as_warn( "Missing expression: absolute 0 assumed" ); - exp . X_seg = SEG_ABSOLUTE; - exp . X_add_number = 0; - } - switch (segment) - { - case SEG_BIG: - as_warn( "%s number illegal. Absolute 0 assumed.", - exp . X_add_number > 0 ? "Bignum" : "Floating-Point" ); - symbolP -> sy_type = N_ABS | ext; - symbolP -> sy_value = 0; - symbolP -> sy_frag = & zero_address_frag; - break; - - case SEG_NONE: - as_warn("No expression: Using absolute 0"); - symbolP -> sy_type = N_ABS | ext; - symbolP -> sy_value = 0; - symbolP -> sy_frag = & zero_address_frag; - break; - - case SEG_DIFFERENCE: - if (exp.X_add_symbol && exp.X_subtract_symbol - && (exp.X_add_symbol->sy_type & N_TYPE) - == (exp.X_subtract_symbol->sy_type & N_TYPE)) { - if(exp.X_add_symbol->sy_frag != exp.X_subtract_symbol->sy_frag) { - as_bad("Unknown expression: symbols %s and %s are in different frags.",exp.X_add_symbol->sy_name, exp.X_subtract_symbol->sy_name); - need_pass_2++; - } - exp.X_add_number+=exp.X_add_symbol->sy_value - exp.X_subtract_symbol->sy_value; - } else - as_warn( "Complex expression. Absolute segment assumed." ); - case SEG_ABSOLUTE: - symbolP -> sy_type = N_ABS | ext; - symbolP -> sy_value = exp . X_add_number; - symbolP -> sy_frag = & zero_address_frag; - break; - - case SEG_DATA: - case SEG_TEXT: - case SEG_BSS: - symbolP -> sy_type = seg_N_TYPE [(int) segment] | ext; - symbolP -> sy_value= exp . X_add_number + exp . X_add_symbol -> sy_value; - symbolP -> sy_frag = exp . X_add_symbol -> sy_frag; - break; - - case SEG_PASS1: /* Not an error. Just try another pass. */ - symbolP->sy_forward=exp.X_add_symbol; - as_warn("Unknown expression"); - know( need_pass_2 == TRUE ); - break; - - case SEG_UNKNOWN: - symbolP->sy_forward=exp.X_add_symbol; - /* as_warn("unknown symbol"); */ - /* need_pass_2 = TRUE; */ - break; - - default: - BAD_CASE( segment ); - break; - } -} - -/* - * stabs(file), stabf(func) and stabd(line) -- for the purpose of - * source file debugging of assembly files, generate file, - * function and line number stabs, respectively. - * These functions have corresponding functions named - * filestab(), funcstab() and linestab() in input-scrub.c, - * where logical files and logical line numbers are handled. - */ - -#include <stab.h> - -stabs(file) - char *file; -{ - /* .stabs "file",100,0,0,. */ - (void) symbol_new(file, - N_SO, - 0, - 0, - obstack_next_free(& frags) - frag_now->fr_literal, - frag_now); -} - -stabf(func) - char *func; -{ - symbolS *symbolP; - static int void_undefined = 1; - - /* crudely filter uninteresting labels: require an initial '_' */ - if (*func++ != '_') - return; - - /* assembly functions are assumed to have void type */ - if (void_undefined) - { - /* .stabs "void:t15=15",128,0,0,0 */ - (void) symbol_new("void:t1=1", - N_LSYM, - 0, - 0, - 0, - &zero_address_frag); - void_undefined = 0; - } - - /* .stabs "func:F1",36,0,0,. */ - symbolP = symbol_new((char *) 0, - N_FUN, - 0, - 0, - obstack_next_free(& frags) - frag_now->fr_literal, - frag_now); - obstack_grow(¬es, func, strlen(func)); - obstack_1grow(¬es, ':'); - obstack_1grow(¬es, 'F'); - obstack_1grow(¬es, '1'); - obstack_1grow(¬es, '\0'); - symbolP->sy_name = obstack_finish(¬es); -} - -stabd(line) - unsigned line; +void + pseudo_set (symbolP) +symbolS * symbolP; { - /* .stabd 68,0,line */ - (void) symbol_new((char *)0, - N_SLINE, - 0, - line, - obstack_next_free(& frags) - frag_now->fr_literal, - frag_now); + 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 TRUE then emit no frag(s). + * Should need_pass_2 be 1 then emit no frag(s). * This understands EXPRESSIONS, as opposed to big_cons(). * * Bug (?) @@ -1477,154 +1377,263 @@ stabd(line) * But we can't detect if expression() discarded significant digits * in the case of a long. Not worth the crocks required to fix it. */ -void -cons(nbytes) /* worker to do .byte etc statements */ - /* clobbers input_line_pointer, checks */ - /* end-of-line. */ - register int nbytes; /* 1=.byte, 2=.word, 4=.long */ -{ - register char c; - register long int mask; /* High-order bits we will left-truncate, */ - /* but includes sign bit also. */ - register long int get; /* what we get */ - register long int use; /* get after truncation. */ - register long int unmask; /* what bits we will store */ - register char * p; - register segT segment; - expressionS exp; -#ifdef NS32K - void fix_new_ns32k(); -#else - void fix_new(); -#endif - /* - * Input_line_pointer -> 1st char after pseudo-op-code and could legally - * be a end-of-line. (Or, less legally an eof - which we cope with.) - */ - /* JF << of >= number of bits in the object is undefined. In particular - SPARC (Sun 4) has problems */ - if(nbytes>=sizeof(long int)) - mask = 0; - else - mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */ - unmask = ~ mask; /* Do store these bits. */ +/* 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. */ + "Do this mod if you want every overflow check to assume SIGNED 2's complement data."; + mask = ~ (unmask >> 1); /* Includes sign bit now. */ #endif - /* - * The following awkward logic is to parse ZERO or more expressions, - * comma seperated. Recall an expression includes its leading & - * trailing blanks. We fake a leading ',' if there is (supposed to - * be) a 1st expression, and keep demanding 1 expression for each ','. - */ - if (is_it_end_of_statement()) - { - c = 0; /* Skip loop. */ - input_line_pointer ++; /* Matches end-of-loop 'correction'. */ - } - else - c = ','; /* Do loop. */ - while ( c == ',' ) - { - segment = expression( &exp ); /* At least scan over the expression. */ - if ( ! need_pass_2 ) - { /* Still worthwhile making frags. */ - - /* Don't call this if we are going to junk this pass anyway! */ - know( segment != SEG_PASS1 ); - - if ( segment == SEG_DIFFERENCE && exp . X_add_symbol == NULL ) - { - as_warn( "Subtracting symbol \"%s\"(segment\"%s\") is too hard. Absolute segment assumed.", - exp . X_subtract_symbol -> sy_name, - seg_name [(int) N_TYPE_seg [exp . X_subtract_symbol -> sy_type & N_TYPE]]); - segment = SEG_ABSOLUTE; - /* Leave exp . X_add_number alone. */ - } - p = frag_more (nbytes); - switch (segment) - { - case SEG_BIG: - as_warn( "%s number illegal. Absolute 0 assumed.", - exp . X_add_number > 0 ? "Bignum" : "Floating-Point"); - md_number_to_chars (p, (long)0, nbytes); - break; - - case SEG_NONE: - as_warn( "0 assumed for missing expression" ); - exp . X_add_number = 0; - know( exp . X_add_symbol == NULL ); - /* fall into SEG_ABSOLUTE */ - case SEG_ABSOLUTE: - get = exp . X_add_number; - use = get & unmask; - if ( (get & mask) && (get & mask) != mask ) - { /* Leading bits contain both 0s & 1s. */ - as_warn("Value x%x truncated to x%x.", get, use); - } - md_number_to_chars (p, use, nbytes); /* put bytes in right order. */ - break; + + /* + * 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. */ + } - case SEG_DIFFERENCE: + 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 - case SEG_BSS: - case SEG_UNKNOWN: - case SEG_TEXT: - case SEG_DATA: -#if defined(SPARC) || defined(I860) - fix_new (frag_now, p - frag_now -> fr_literal, nbytes, - exp . X_add_symbol, exp . X_subtract_symbol, - exp . X_add_number, 0, RELOC_32); -#endif -#ifdef NS32K - fix_new_ns32k (frag_now, p - frag_now -> fr_literal, nbytes, - exp . X_add_symbol, exp . X_subtract_symbol, - exp . X_add_number, 0, 0, 2, 0, 0); + 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 -#if !defined(SPARC) && !defined(NS32K) && !defined(I860) - fix_new (frag_now, p - frag_now -> fr_literal, nbytes, - exp . X_add_symbol, exp . X_subtract_symbol, - exp . X_add_number, 0); + 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 - break; - - default: - BAD_CASE( segment ); - break; - } /* switch(segment) */ - } /* if(!need_pass_2) */ - c = * input_line_pointer ++; - } /* while(c==',') */ - input_line_pointer --; /* Put terminator back into stream. */ - demand_empty_rest_of_line(); -} /* cons() */ +#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 == TRUE, generate no frag. + * If need_pass_2 == 1, generate no frag. * This understands only bignums, not expressions. Cons() understands * expressions. * @@ -1639,138 +1648,138 @@ cons(nbytes) /* worker to do .byte etc statements */ * It would be nicer to permit bignums in expressions and only * complain if the result overflowed. However, due to "efficiency"... */ -void -big_cons(nbytes) /* worker to do .quad etc statements */ - /* clobbers input_line_pointer, checks */ - /* end-of-line. */ - register int nbytes; /* 8=.quad 16=.octa ... */ +/* 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 int length; /* Number of chars in an object. */ - register int digit; /* Value of 1 digit. */ - register int carry; /* For multi-precision arithmetic. */ - register int work; /* For multi-precision arithmetic. */ - register char * p; /* For multi-precision arithmetic. */ - - extern char hex_value[]; /* In hex_value.c. */ - - /* - * The following awkward logic is to parse ZERO or more strings, - * comma seperated. Recall an expression includes its leading & - * trailing blanks. We fake a leading ',' if there is (supposed to - * be) a 1st expression, and keep demanding 1 expression for each ','. - */ - if (is_it_end_of_statement()) - { - c = 0; /* Skip loop. */ - } - else - { - c = ','; /* Do loop. */ - -- input_line_pointer; - } - while (c == ',') - { - ++ input_line_pointer; - SKIP_WHITESPACE(); - c = * input_line_pointer; - /* C contains 1st non-blank character of what we hope is a number. */ - if (c == '0') - { - c = * ++ input_line_pointer; - if (c == 'x' || c=='X') - { - c = * ++ input_line_pointer; - radix = 16; - } - else + 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()) { - radix = 8; + c = 0; /* Skip loop. */ } - } - else - { - radix = 10; - } - /* - * This feature (?) is here to stop people worrying about - * mysterious zero constants: which is what they get when - * they completely omit digits. - */ - if (hex_value[c] >= radix) - { - as_warn( "Missing digits. 0 assumed." ); - } - bignum_high = bignum_low - 1; /* Start constant with 0 chars. */ - for( ; (digit = hex_value [c]) < radix; c = * ++ input_line_pointer) - { - /* Multiply existing number by radix, then add digit. */ - carry = digit; - for (p=bignum_low; p <= bignum_high; p++) + else { - work = (*p & MASK_CHAR) * radix + carry; - *p = work & MASK_CHAR; - carry = work >> BITS_PER_CHAR; + c = ','; /* Do loop. */ + -- input_line_pointer; } - if (carry) + while (c == ',') { - grow_bignum(); - * bignum_high = carry & MASK_CHAR; - know( (carry & ~ MASK_CHAR) == 0); + ++ 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. */ } - } - length = bignum_high - bignum_low + 1; - if (length > nbytes) - { - as_warn( "Most significant bits truncated in integer constant." ); - } - else - { - register long int leading_zeroes; - - for(leading_zeroes = nbytes - length; - leading_zeroes; - leading_zeroes --) + 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) { - grow_bignum(); - * bignum_high = 0; + length = bignum_limit - bignum_low; + bignum_low = xrealloc(bignum_low, length + length); + bignum_high = bignum_low + length; + bignum_limit = bignum_low + length + length; } - } - if (! need_pass_2) - { - p = frag_more (nbytes); - bcopy (bignum_low, p, (int)nbytes); - } - /* C contains character after number. */ - SKIP_WHITESPACE(); - c = * input_line_pointer; - /* C contains 1st non-blank character after number. */ - } - demand_empty_rest_of_line(); -} /* big_cons() */ - -static void -grow_bignum() /* Extend bignum by 1 char. */ -{ - register long int length; - - bignum_high ++; - if (bignum_high >= bignum_limit) - { - length = bignum_limit - bignum_low; - bignum_low = xrealloc (bignum_low, length + length); - bignum_high = bignum_low + length; - bignum_limit = bignum_low + length + length; - } -} /* grow_bignum(); */ +} /* grow_bignum(); */ /* * float_cons() * * CONStruct some more frag chars of .floats .ffloats etc. * Makes 0 or more new frags. - * If need_pass_2 == TRUE, no frags are emitted. + * 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 @@ -1781,290 +1790,304 @@ grow_bignum() /* Extend bignum by 1 char. */ * 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. + * In: input_line_pointer->whitespace before, or '0' of flonum. * */ void /* JF was static, but can't be if VAX.C is goning to use it */ -float_cons(float_type) /* Worker to do .float etc statements. */ - /* Clobbers input_line-pointer, checks end-of-line. */ - register float_type; /* 'f':.ffloat ... 'F':.float ... */ + 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_warn( "Bad floating literal: %s", err); - ignore_rest_of_line(); - /* Input_line_pointer -> just after end-of-line. */ - c = 0; /* Break out of loop. */ - } - else - { - if ( ! need_pass_2) + 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 { - p = frag_more (length); - bcopy (temp, p, length); + c = ','; /* Do loop. */ } - SKIP_WHITESPACE(); - c = * input_line_pointer ++; - /* C contains 1st non-white character after number. */ - /* input_line_pointer -> just after terminator (c). */ + 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() */ + --input_line_pointer; /*->terminator (is not ','). */ + demand_empty_rest_of_line(); +} /* float_cons() */ /* - * stringer() + * 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. */ -static void -stringer(append_zero) /* Worker to do .ascii etc statements. */ - /* Checks end-of-line. */ - register int append_zero; /* 0: don't append '\0', else 1 */ + +void stringer(append_zero) +int append_zero; /* 0: don't append '\0', else 1 */ { - /* register char * p; JF unused */ - /* register int length; JF unused */ /* Length of string we read, excluding */ - /* trailing '\0' implied by closing quote. */ - /* register char * where; JF unused */ - /* register fragS * fragP; JF unused */ - register int c; - - /* - * The following awkward logic is to parse ZERO or more strings, - * comma seperated. Recall a string expression includes spaces - * before the opening '\"' and spaces after the closing '\"'. - * We fake a leading ',' if there is (supposed to be) - * a 1st, expression. We keep demanding expressions for each - * ','. - */ - if (is_it_end_of_statement()) - { - c = 0; /* Skip loop. */ - ++ input_line_pointer; /* Compensate for end of loop. */ - } - else - { - c = ','; /* Do loop. */ - } - for ( ; c == ','; c = *input_line_pointer ++) - { - SKIP_WHITESPACE(); - if (* input_line_pointer == '\"') - { - ++ input_line_pointer; /* -> 1st char of string. */ - while ( (c = next_char_of_string()) >= 0) - { - FRAG_APPEND_1_CHAR( c ); - } - if (append_zero) - { - FRAG_APPEND_1_CHAR( 0 ); - } - know( input_line_pointer [-1] == '\"' ); + 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. */ } - else - { - as_warn( "Expected \"-ed string" ); + + 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; } - SKIP_WHITESPACE(); - } - -- input_line_pointer; - demand_empty_rest_of_line(); -} /* stringer() */ + + demand_empty_rest_of_line(); +} /* stringer() */ -static int -next_char_of_string () -{ - register int c; - - c = * input_line_pointer ++; - switch (c) - { - case '\"': - c = -1; - break; - - case '\\': - switch (c = * input_line_pointer ++) - { - case 'b': - c = '\b'; - break; - - case 'f': - c = '\f'; - break; - - case 'n': - c = '\n'; - break; - - case 'r': - c = '\r'; - break; - - case 't': - c = '\t'; - break; - +/* 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 '\\': - case '"': - break; /* As itself. */ - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - long int number; - - for (number = 0; isdigit(c); c = * input_line_pointer ++) - { - number = number * 8 + c - '0'; - } - c = number; - } - -- input_line_pointer; - break; - - case '\n': -/* as_fatal( "Unterminated string - use app!" ); */ -/* To be compatible with BSD 4.2 as: give the luser a linefeed!! */ - c = '\n'; - break; - + 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: - as_warn( "Bad escaped character in string, '?' assumed" ); - c = '?'; - break; - } - break; - - default: - break; - } - return (c); -} + break; + } /* switch on char */ + return(c); +} /* next_char_of_string() */ static segT -get_segmented_expression ( expP ) - register expressionS * expP; + get_segmented_expression (expP) +register expressionS * expP; { - register segT retval; - - if ( (retval = expression( expP )) == SEG_PASS1 || retval == SEG_NONE || retval == SEG_BIG ) - { - as_warn("Expected address expression: absolute 0 assumed"); - retval = expP -> X_seg = SEG_ABSOLUTE; - expP -> X_add_number = 0; - expP -> X_add_symbol = expP -> X_subtract_symbol = 0; - } - return (retval); /* SEG_ ABSOLUTE,UNKNOWN,DATA,TEXT,BSS */ + 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; +static segT get_known_segmented_expression(expP) +register expressionS *expP; { - register segT retval; - register char * name1; - register char * name2; - - if ( (retval = get_segmented_expression (expP)) == SEG_UNKNOWN - ) - { - name1 = expP -> X_add_symbol ? expP -> X_add_symbol -> sy_name : ""; - name2 = expP -> X_subtract_symbol ? expP -> X_subtract_symbol -> sy_name : ""; - if ( name1 && name2 ) - { - as_warn("Symbols \"%s\" \"%s\" are undefined: absolute 0 assumed.", - name1, name2); - } - else - { - as_warn("Symbol \"%s\" undefined: absolute 0 assumed.", - name1 ? name1 : name2); - } - retval = expP -> X_seg = SEG_ABSOLUTE; - expP -> X_add_number = 0; - expP -> X_add_symbol = expP -> X_subtract_symbol = NULL; - } - know( retval == SEG_ABSOLUTE || retval == SEG_DATA || retval == SEG_TEXT || retval == SEG_BSS || retval == SEG_DIFFERENCE ); - return (retval); + 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 int /* JF was static, but can't be if the MD pseudos are to use it */ -get_absolute_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_NONE ) - { - as_warn( "Bad Absolute Expression, absolute 0 assumed."); + 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; } - exp . X_add_number = 0; - } - return (exp . X_add_number); -} + return(exp.X_add_number); +} /* get_absolute_expression() */ -static char /* return terminator */ -get_absolute_expression_and_terminator( val_pointer) - long int * val_pointer; /* return value of 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 ++ ); + *val_pointer = get_absolute_expression(); + return (*input_line_pointer++); } /* @@ -2073,30 +2096,27 @@ get_absolute_expression_and_terminator( val_pointer) * Like demand_copy_string, but return NULL if the string contains any '\0's. * Give a warning if that happens. */ -static char * -demand_copy_C_string (len_pointer) - int * len_pointer; +char * + demand_copy_C_string (len_pointer) +int *len_pointer; { - register char * s; - - if (s = demand_copy_string (len_pointer)) - { - register int len; - - for (len = * len_pointer; - len > 0; - len--) - { - if (* s == 0) - { - s = 0; - len = 1; - * len_pointer = 0; - as_warn( "This string may not contain \'\\0\'" ); - } + 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); + return(s); } /* @@ -2105,84 +2125,157 @@ demand_copy_C_string (len_pointer) * 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; +static char *demand_copy_string(lenP) +int *lenP; { - register int c; - register int len; - char * retval; - - len = 0; - SKIP_WHITESPACE(); - if (* input_line_pointer == '\"') - { - input_line_pointer ++; /* Skip opening quote. */ - while ( (c = next_char_of_string()) >= 0 ) { - obstack_1grow ( ¬es, c ); - len ++; + 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(); } - /* 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); -} + *lenP = len; + return(retval); +} /* demand_copy_string() */ /* * is_it_end_of_statement() * - * In: Input_line_pointer -> next character. + * In: Input_line_pointer->next character. * * Do: Skip input_line_pointer over all whitespace. * - * Out: TRUE if input_line_pointer -> end-of-line. + * Out: 1 if input_line_pointer->end-of-line. */ -static int -is_it_end_of_statement() -{ - SKIP_WHITESPACE(); - return (is_end_of_line [* input_line_pointer]); -} +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) +void equals(sym_name) char *sym_name; { - register struct symbol * symbolP; /* symbol we are working with */ - - input_line_pointer++; - if(*input_line_pointer=='=') - input_line_pointer++; - - while(*input_line_pointer==' ' || *input_line_pointer=='\t') - input_line_pointer++; - - if(sym_name[0]=='.' && sym_name[1]=='\0') { - /* Turn '. = mumble' into a .org mumble */ - register segT segment; - expressionS exp; - register char *p; - - segment = get_known_segmented_expression(& exp); - if ( ! need_pass_2 ) { - if (segment != now_seg && segment != SEG_ABSOLUTE) - as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.", - seg_name [(int) segment], seg_name [(int) now_seg]); - p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol, - exp.X_add_number, (char *)0); - * p = 0; - } /* if (ok to make frag) */ - } else { - symbolP=symbol_find_or_make(sym_name); - pseudo_set(symbolP); - } -} + 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: read.c */ +/* end of read.c */ diff --git a/gnu/usr.bin/as/read.h b/gnu/usr.bin/as/read.h index 6b46e8f..5d8c391 100644 --- a/gnu/usr.bin/as/read.h +++ b/gnu/usr.bin/as/read.h @@ -1,47 +1,147 @@ /* read.h - of read.c - Copyright (C) 1986 Free Software Foundation, Inc. -This file is part of GAS, the GNU Assembler. + 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/10/02 20:57:53 pk Exp $ + */ -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -extern char * input_line_pointer; /* -> char we are parsing now. */ +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 +/* many syntactically unnecessary places. */ +/* Normally undefined. For compatibility */ +/* with ancient GNU cc. */ +/* #undef PERMIT_WHITESPACE */ #ifdef PERMIT_WHITESPACE #define SKIP_WHITESPACE() {if (* input_line_pointer == ' ') ++ input_line_pointer;} #else -#define SKIP_WHITESPACE() ASSERT( * input_line_pointer != ' ' ) +#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); + +#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(); + +#endif /* not __STDC__ */ -void read_begin(); -void read_end(); -void read_a_source_file(); +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ -/* end: read.h */ +/* end of read.h */ diff --git a/gnu/usr.bin/as/struc-symbol.h b/gnu/usr.bin/as/struc-symbol.h index 11eab6b..787bcfe 100644 --- a/gnu/usr.bin/as/struc-symbol.h +++ b/gnu/usr.bin/as/struc-symbol.h @@ -1,58 +1,64 @@ /* struct_symbol.h - Internal symbol structure - Copyright (C) 1987 Free Software Foundation, Inc. + 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.4 1993/10/02 20:57:53 pk Exp $ + */ -This file is part of GAS, the GNU Assembler. -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef VMS -#include "a.out.gnu.h" /* Needed to define struct nlist. Sigh. */ -#else -#include "a_out.h" -#endif +#ifndef __struc_symbol_h__ +#define __struc_symbol_h__ struct symbol /* our version of an nlist node */ { - struct nlist sy_nlist; /* what we write in .o file (if permitted) */ - long unsigned sy_name_offset; /* 4-origin position of sy_name in symbols */ - /* part of object file. */ - /* 0 for (nameless) .stabd symbols. */ - /* Not used until write_object_file() time. */ - long int sy_number; /* 24 bit symbol number. */ - /* Symbol numbers start at 0 and are */ - /* unsigned. */ - struct symbol * sy_next; /* forward chain, or NULL */ - struct frag * sy_frag; /* NULL or -> frag this symbol attaches to. */ - struct symbol *sy_forward; /* value is really that of this other symbol */ + 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 */ + int sy_size; }; typedef struct symbol symbolS; -#define sy_name sy_nlist .n_un. n_name - /* Name field always points to a string. */ - /* 0 means .stabd-like anonymous symbol. */ -#define sy_type sy_nlist. n_type -#define sy_other sy_nlist. n_other -#define sy_desc sy_nlist. n_desc -#define sy_value sy_nlist. n_value - /* Value of symbol is this value + object */ - /* file address of sy_frag. */ +#ifdef PIC +symbolS *GOT_symbol; /* Pre-defined "__GLOBAL_OFFSET_TABLE" */ +int got_referenced; +#endif typedef unsigned valueT; /* The type of n_value. Helps casting. */ -/* end: struct_symbol.h */ #ifndef WORKING_DOT_WORD struct broken_word { struct broken_word *next_broken_word;/* One of these strucs per .word x-y */ @@ -63,10 +69,59 @@ struct broken_word { 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 */ + /* 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 +#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 index c9eea3d..af2d4e7 100644 --- a/gnu/usr.bin/as/subsegs.c +++ b/gnu/usr.bin/as/subsegs.c @@ -1,114 +1,119 @@ /* subsegs.c - subsegments - - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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.3 1993/10/02 20:57:54 pk Exp $"; +#endif + #include "as.h" + #include "subsegs.h" #include "obstack.h" -#include "frags.h" -#include "struc-symbol.h" -#include "write.h" - -frchainS* frchain_root, - * frchain_now, /* Commented in "subsegs.h". */ - * data0_frchainP; +#ifdef MANY_SEGMENTS +segment_info_type segment_info[SEG_MAXIMUM_ORDINAL]; -const int /* in: segT out: N_TYPE bits */ -seg_N_TYPE[] = { - N_ABS, - N_TEXT, - N_DATA, - N_BSS, - N_UNDF, - N_UNDF, - N_UNDF, - N_UNDF, - N_UNDF, - N_UNDF -}; +frchainS* frchain_root, + * frchain_now; +#else +frchainS* frchain_root, + * frchain_now, /* Commented in "subsegs.h". */ + * data0_frchainP; -char * const /* in: segT out: char* */ -seg_name[] = { - "absolute", - "text", - "data", - "bss", - "unknown", - "absent", - "pass1", - "ASSEMBLER-INTERNAL-LOGIC-ERROR!", - "bignum/flonum", - "difference", - "" - }; /* Used by error reporters, dumpers etc. */ +#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. */ -const segT N_TYPE_seg [N_TYPE+2] = /* N_TYPE == 0x1E = 32-2 */ -{ - SEG_UNKNOWN, /* N_UNDF == 0 */ - SEG_GOOF, - SEG_ABSOLUTE, /* N_ABS == 2 */ - SEG_GOOF, - SEG_TEXT, /* N_TEXT == 4 */ - SEG_GOOF, - SEG_DATA, /* N_DATA == 6 */ - SEG_GOOF, - SEG_BSS, /* N_BSS == 8 */ - SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, - SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, - SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF -}; void -subsegs_begin() + subsegs_begin() { - /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */ - know( SEG_ABSOLUTE ==0 ); - know( SEG_TEXT ==1 ); - know( SEG_DATA ==2 ); - know( SEG_BSS ==3 ); - know( SEG_UNKNOWN ==4 ); - know( SEG_NONE ==5 ); - know( SEG_PASS1 ==6 ); - know( SEG_GOOF ==7 ); - know( SEG_BIG ==8 ); - know( SEG_DIFFERENCE ==9 ); - know( SEG_MAXIMUM_ORDINAL == SEG_DIFFERENCE ); - know( seg_name [(int) SEG_MAXIMUM_ORDINAL + 1] [0] == 0 ); - - obstack_begin( &frags, 5000); - frchain_root = NULL; - frchain_now = NULL; /* Warn new_subseg() that we are booting. */ - /* Fake up 1st frag. */ - /* It won't be used=> is ok if obstack... */ - /* pads the end of it for alignment. */ - frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG); - /* obstack_1blank( &frags, SIZEOF_STRUCT_FRAG, & frag_now ); */ - /* This 1st frag will not be in any frchain. */ - /* We simply give subseg_new somewhere to scribble. */ - now_subseg = 42; /* Lie for 1st call to subseg_new. */ - subseg_new (SEG_DATA, 0); /* .data 0 */ - data0_frchainP = frchain_now; + /* 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 + } /* @@ -122,21 +127,25 @@ subsegs_begin() * segment context correct. */ void -subseg_change (seg, subseg) - register segT seg; - register int subseg; + subseg_change (seg, subseg) +register segT seg; +register int subseg; { - now_seg = seg; - now_subseg = subseg; - if (seg == SEG_DATA) - { - seg_fix_rootP = & data_fix_root; - } - else - { - know (seg == SEG_TEXT); - seg_fix_rootP = & text_fix_root; - } + 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 } /* @@ -146,7 +155,7 @@ subseg_change (seg, subseg) * * 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 + * 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. @@ -156,137 +165,144 @@ subseg_change (seg, subseg) */ void -subseg_new (seg, subseg) /* begin assembly for a new sub-segment */ - register segT seg; /* SEG_DATA or SEG_TEXT */ - register subsegT subseg; + subseg_new (seg, subseg) /* begin assembly for a new sub-segment */ +register segT seg; /* SEG_DATA or SEG_TEXT */ +register subsegT subseg; { - long tmp; /* JF for obstack alignment hacking */ - - know( seg == SEG_DATA || seg == SEG_TEXT ); - - if (seg != now_seg || subseg != now_subseg) - { /* we just changed sub-segments */ - register frchainS * frcP; /* crawl frchain chain */ - register frchainS** lastPP; /* address of last pointer */ - frchainS * newP; /* address of new frchain */ - register fragS * former_last_fragP; - register fragS * new_fragP; - - if (frag_now) /* If not bootstrapping. */ - { - frag_now -> fr_fix = obstack_next_free(& frags) - frag_now -> fr_literal; - frag_wane(frag_now); /* Close off any frag in old subseg. */ - } -/* - * It would be nice to keep an obstack for each subsegment, if we swap - * subsegments a lot. Hence we would have much fewer frag_wanes(). - */ - { - - obstack_finish( &frags); - /* - * If we don't do the above, the next object we put on obstack frags - * will appear to start at the fr_literal of the current frag. - * Also, above ensures that the next object will begin on a - * address that is aligned correctly for the engine that runs - * this program. - */ - } - subseg_change (seg, (int)subseg); - /* - * Attempt to find or make a frchain for that sub seg. - * Crawl along chain of frchainSs, begins @ frchain_root. - * If we need to make a frchainS, link it into correct - * position of chain rooted in frchain_root. - */ - for (frcP = * (lastPP = & frchain_root); - frcP - && (int)(frcP -> frch_seg) <= (int)seg; - frcP = * ( lastPP = & frcP -> frch_next) - ) - { - if ( (int)(frcP -> frch_seg) == (int)seg - && frcP -> frch_subseg >= subseg) - { - break; - } - } - /* - * frcP: Address of the 1st frchainS in correct segment with - * frch_subseg >= subseg. - * We want to either use this frchainS, or we want - * to insert a new frchainS just before it. - * - * If frcP==NULL, then we are at the end of the chain - * of frchainS-s. A NULL frcP means we fell off the end - * of the chain looking for a - * frch_subseg >= subseg, so we - * must make a new frchainS. - * - * If we ever maintain a pointer to - * the last frchainS in the chain, we change that pointer - * ONLY when frcP==NULL. - * - * lastPP: Address of the pointer with value frcP; - * Never NULL. - * May point to frchain_root. - * - */ - if ( ! frcP - || ( (int)(frcP -> frch_seg) > (int)seg - || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */ - { - /* - * This should be the only code that creates a frchainS. - */ - newP=(frchainS *)obstack_alloc(&frags,sizeof(frchainS)); - /* obstack_1blank( &frags, sizeof(frchainS), &newP); */ + 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) */ + *lastPP = newP; + newP->frch_next = frcP; /* perhaps NULL */ + (frcP = newP)->frch_subseg = subseg; + newP->frch_seg = seg; + newP->frch_last = NULL; + } + /* + * Here with frcP->ing to the frchainS for subseg. + */ + frchain_now = frcP; + /* + * Make a fresh frag for the subsegment. + */ + /* We expect this to happen on a correct */ + /* boundary since it was proceeded by a */ + /* obstack_done(). */ + tmp=obstack_alignment_mask(&frags); /* JF disable alignment */ + obstack_alignment_mask(&frags)=0; + frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG); + obstack_alignment_mask(&frags)=tmp; + /* know(frags.obstack_c_next_free == frag_now->fr_literal); */ + /* But we want any more chars to come */ + /* immediately after the structure we just made. */ + new_fragP = frag_now; + new_fragP->fr_next = NULL; + /* + * Append new frag to current frchain. + */ + former_last_fragP = frcP->frch_last; + if (former_last_fragP) + { + know( former_last_fragP->fr_next == NULL ); + know( frchain_now->frch_root ); + former_last_fragP->fr_next = new_fragP; + } + else + { + frcP->frch_root = new_fragP; + } + frcP->frch_last = new_fragP; + } /* if (changing subsegments) */ } /* subseg_new() */ -/* end: subsegs.c */ +/* + * 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 index b8dbaf7..4b8e3ce 100644 --- a/gnu/usr.bin/as/subsegs.h +++ b/gnu/usr.bin/as/subsegs.h @@ -1,21 +1,26 @@ /* subsegs.h -> subsegs.c - Copyright (C) 1987 Free Software Foundation, Inc. -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + 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.3 1993/10/02 20:57:55 pk Exp $ + */ -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * For every sub-segment the user mentions in the ASsembler program, @@ -38,28 +43,51 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 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 */ + 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 */ +/* 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. */ +/* 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; - /* Sentinel for frchain crawling. */ - /* Points to the 1st data-segment frchain. */ - /* (Which is pointed to by the last text- */ - /* segment frchain.) */ +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: subsegs.h */ +/* end of subsegs.h */ diff --git a/gnu/usr.bin/as/symbols.c b/gnu/usr.bin/as/symbols.c index ce7197a..066f54e 100644 --- a/gnu/usr.bin/as/symbols.c +++ b/gnu/usr.bin/as/symbols.c @@ -1,51 +1,51 @@ /* symbols.c -symbol table- - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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.3 1993/10/02 20:57:56 pk Exp $"; +#endif #include "as.h" -#include "hash.h" + #include "obstack.h" /* For "symbols.h" */ -#include "struc-symbol.h" -#include "symbols.h" -#include "frags.h" +#include "subsegs.h" #ifndef WORKING_DOT_WORD extern int new_broken_words; #endif -#ifdef VMS -extern char const_flag; -#endif static -struct hash_control * -sy_hash; /* symbol-name => struct symbol pointer */ + struct hash_control * + sy_hash; /* symbol-name => struct symbol pointer */ - /* Below are commented in "symbols.h". */ +/* Below are commented in "symbols.h". */ unsigned int local_bss_counter; symbolS * symbol_rootP; symbolS * symbol_lastP; symbolS abs_symbol; -struct obstack notes; +symbolS* dot_text_symbol; +symbolS* dot_data_symbol; +symbolS* dot_bss_symbol; - -symbolS * symbol_find(); /* Keep C compiler happy. */ +struct obstack notes; /* * Un*x idea of local labels. They are made by "n:" where n @@ -67,29 +67,29 @@ symbolS * symbol_find(); /* Keep C compiler happy. */ */ typedef short unsigned int -local_label_countT; + local_label_countT; static local_label_countT -local_label_counter[10]; + local_label_counter[10]; static /* Returned to caller, then copied. */ - char symbol_name_build[12]; /* used for created names ("4f") */ + char symbol_name_build[12]; /* used for created names ("4f") */ -#ifdef SUN_ASM_SYNTAX +#ifdef LOCAL_LABELS_DOLLAR int local_label_defined[10]; #endif void -symbol_begin() + symbol_begin() { - symbol_lastP = NULL; - symbol_rootP = NULL; /* In case we have 0 symbols (!!) */ - sy_hash = hash_new(); - bzero ((char *)(& abs_symbol), sizeof(abs_symbol)); - abs_symbol . sy_type = N_ABS; /* Can't initialise a union. Sigh. */ - bzero ((char *)(local_label_counter), sizeof(local_label_counter) ); - local_bss_counter = 0; + 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; } /* @@ -99,51 +99,49 @@ symbol_begin() */ 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 */ + local_label_name(n, augend) +register int n; /* we just saw "n:", "nf" or "nb" : n a digit */ +register int augend; /* 0 for nb, 1 for n:, nf */ { - register char * p; - register char * q; - char symbol_name_temporary[10]; /* build up a number, BACKWARDS */ - - know( n >= 0 ); - know( augend == 0 || augend == 1 ); - p = symbol_name_build; - * p ++ = 'L'; - * p ++ = n + '0'; /* Make into ASCII */ - * p ++ = 1; /* ^A */ - n = local_label_counter [ n ] + augend; - /* version number of this local label */ - /* - * Next code just does sprintf( {}, "%d", n); - * It is more elegant to do the next part recursively, but a procedure - * call for each digit emitted is considered too costly. - */ - q = symbol_name_temporary; - for (*q++=0; n; q++) /* emits NOTHING if n starts as 0 */ - { - know(n>0); /* We expect n > 0 always */ - *q = n % 10 + '0'; - n /= 10; - } - while ( * p ++ = * -- q ) - { - } - /* The label, as a '\0' ended string, starts at symbol_name_build. */ - return (symbol_name_build); -} + 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:" */ +void local_colon (n) +int n; /* just saw "n:" */ { - local_label_counter [n] ++; -#ifdef SUN_ASM_SYNTAX - local_label_defined[n]=1; + local_label_counter[n] ++; +#ifdef LOCAL_LABELS_DOLLAR + local_label_defined[n]=1; #endif - colon (local_label_name (n, 0)); + colon (local_label_name (n, 0)); } /* @@ -158,58 +156,61 @@ local_colon (n) * 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, type, other, desc, value, frag) - char * name; /* We copy this: OK to alter your copy. */ - unsigned char type; /* As in <a.out.h>. */ - char other; /* As in <a.out.h>. */ - short int desc; /* As in <a.out.h>. */ - valueT value; /* As in <a.out.h>, often an address. */ - /* Often used as offset from frag address. */ - struct frag * frag; /* For sy_frag. */ +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 */ { - register symbolS * symbolP; - register char * preserved_copy_of_name; - register unsigned int name_length; - char * p; - - name_length = strlen(name) + 1; - obstack_grow(¬es,name,name_length); - p=obstack_finish(¬es); - /* obstack_1done( ¬es, name, name_length, &p ); */ - preserved_copy_of_name = p; - p=obstack_alloc(¬es,sizeof(struct symbol)); - /* obstack_1blank( ¬es, sizeof(struct symbol), &p ); */ - symbolP = (symbolS *) p; - symbolP -> sy_name = preserved_copy_of_name; - symbolP -> sy_type = type; - symbolP -> sy_other = other; - symbolP -> sy_desc = desc; - symbolP -> sy_value = value; - symbolP -> sy_frag = frag; - symbolP -> sy_next = NULL; /* End of chain. */ - symbolP -> sy_forward = NULL; /* JF */ -#ifdef SUSPECT - symbolP -> sy_name_offset = ~ 0; /* Impossible offset catches errors. */ - symbolP -> sy_number = ~ 0; /* Ditto. */ -#endif - /* - * Link to end of symbol chain. - */ - if (symbol_lastP) - { - symbol_lastP -> sy_next = symbolP; - } - else - { - symbol_rootP = symbolP; - } - symbol_lastP = symbolP; - - return (symbolP); -} + 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() @@ -220,159 +221,176 @@ symbol_new (name, type, other, desc, value, frag) * 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. */ +void colon(sym_name) /* just seen "x:" - rattle symbols & frags */ +register char * sym_name; /* symbol name, as a cannonical string */ +/* We copy this string: OK to alter later. */ { - register struct symbol * symbolP; /* symbol we are working with */ - -#ifdef SUN_ASM_SYNTAX - /* Sun local labes go out of scope whenever a non-local symbol is - defined. */ - - if(*sym_name !='L') - bzero((void *)local_label_defined,sizeof(local_label_defined)); + 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 md_short_jump_size; - extern md_long_jump_size; - - possible_bytes=md_short_jump_size+new_broken_words*md_long_jump_size; - frag_tmp=frag_now; - frag_opcode=frag_var(rs_broken_word,possible_bytes,possible_bytes,(relax_substateT)0,(symbolS *)broken_words,(long int)0,(char *)0); - - /* We want to store the pointer to where to insert the jump table in the - fr_opcode of the rs_broken_word frag. This requires a little hackery */ - while(frag_tmp && (frag_tmp->fr_type!=rs_broken_word || frag_tmp->fr_opcode)) - frag_tmp=frag_tmp->fr_next; - know(frag_tmp); - frag_tmp->fr_opcode=frag_opcode; - new_broken_words = 0; - - for(a=broken_words;a && a->dispfrag==0;a=a->next_broken_word) - a->dispfrag=frag_tmp; - } + 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_table_lookup( sym_name )) - { -#ifdef VMS - /* - * If the new symbol is .comm AND it has a size of zero, - * we ignore it (i.e. the old symbol overrides it) - */ - if ((seg_N_TYPE [(int) now_seg] == (N_UNDF | N_EXT)) && - ((obstack_next_free(& frags) - frag_now -> fr_literal) == 0)) - return; - /* - * If the old symbol is .comm and it has a size of zero, - * we override it with the new symbol value. - */ - if ((symbolP -> sy_type == (N_UNDF | N_EXT)) && - (symbolP->sy_value == 0)) { - symbolP -> sy_frag = frag_now; - symbolP -> sy_other = const_flag; - symbolP -> sy_value = obstack_next_free(& frags) - frag_now -> fr_literal; - symbolP -> sy_type |= seg_N_TYPE [(int) now_seg]; /* keep N_EXT bit */ - return; - } -#endif /* VMS */ - /* - * Now check for undefined symbols - */ - if ((symbolP -> sy_type & N_TYPE) == N_UNDF) - { - if( symbolP -> sy_other == 0 - && symbolP -> sy_desc == 0 - && symbolP -> sy_value == 0) - { - symbolP -> sy_frag = frag_now; -#ifdef VMS - symbolP -> sy_other = const_flag; + 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 - symbolP -> sy_value = obstack_next_free(& frags) - frag_now -> fr_literal; - know( N_UNDF == 0 ); - symbolP -> sy_type |= seg_N_TYPE [(int) now_seg]; /* keep N_EXT bit */ - } - else - { -#ifdef VMS - /* - * There are still several cases to check: - * A .comm/.lcomm symbol being redefined as - * initialized data is OK - * A .comm/.lcomm symbol being redefined with - * a larger size is also OK - */ - char New_Type = seg_N_TYPE [(int) now_seg]; - if (((symbolP->sy_type == (N_UNDF | N_EXT)) || - (symbolP->sy_type == N_BSS)) && - (((New_Type & ~N_EXT) == N_DATA) || - (New_Type == symbolP->sy_type))) { - /* - * Select which of the 2 cases this is - */ - if (New_Type == symbolP->sy_type) { - /* - * If the new size is larger we just - * change its value. If the new size - * is smaller, we ignore this symbol - */ - if (symbolP->sy_value < - (obstack_next_free(& frags) - - frag_now -> fr_literal)) { - symbolP -> sy_value = - obstack_next_free(& frags) - - frag_now -> fr_literal; - } + 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 { /* - * It is a .comm/.lcomm being converted - * to initialized data. + * 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. */ - symbolP -> sy_frag = frag_now; - symbolP -> sy_other = const_flag; - symbolP -> sy_value = obstack_next_free(& frags) - frag_now -> fr_literal; - symbolP -> sy_type |= seg_N_TYPE [(int) now_seg]; /* keep N_EXT bit */ - } - } else { -#endif /* VMS */ - as_fatal( "Symbol \"%s\" is already defined as \"%s\"/%d.%d.%d.", - sym_name, - seg_name [(int) N_TYPE_seg [symbolP -> sy_type & N_TYPE]], - symbolP -> sy_other, symbolP -> sy_desc, - symbolP -> sy_value); -#ifdef VMS - } -#endif /* VMS */ - } - } - else - { - as_fatal("Symbol %s already defined.",sym_name); - } - } - else - { - symbolP = symbol_new (sym_name, - (unsigned char)(seg_N_TYPE [(int) now_seg]), -#ifdef VMS - const_flag, -#else - 0, + /* char New_Type = SEGMENT_TO_SYMBOL_TYPE((int) now_seg); */ +#ifdef MANY_SEGMENTS +#define SEG_BSS SEG_E2 +#define SEG_DATA SEG_E1 #endif - 0, - (valueT)(obstack_next_free(&frags)-frag_now->fr_literal), - frag_now); - symbol_table_insert (symbolP); - } -} + + 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() */ /* @@ -382,20 +400,19 @@ colon (sym_name) /* just seen "x:" - rattle symbols & frags */ * */ -void -symbol_table_insert (symbolP) - struct symbol * symbolP; +void symbol_table_insert(symbolP) +symbolS *symbolP; { - register char * error_string; - - know( symbolP ); - know( symbolP -> sy_name ); - if ( * (error_string = hash_jam (sy_hash, symbolP -> sy_name, (char *)symbolP))) - { - as_fatal( "Inserting \"%s\" into symbol table failed: %s", - symbolP -> sy_name, error_string); - } -} + 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() @@ -403,20 +420,39 @@ symbol_table_insert (symbolP) * 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; +symbolS *symbol_find_or_make(name) +char *name; { - register symbolS * symbolP; - - symbolP = symbol_table_lookup (name); - if (symbolP == NULL) - { - symbolP = symbol_new (name, N_UNDF, 0, 0, 0, & zero_address_frag); - symbol_table_insert (symbolP); - } - return (symbolP); -} + 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() @@ -427,12 +463,196 @@ symbol_find_or_make (name) * of a struct symbol associated with that name. */ -symbolS * -symbol_find (name) - char * 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; { - return ( (symbolS *) hash_find( sy_hash, name )); + 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: symbols.c */ +/* end of symbols.c */ diff --git a/gnu/usr.bin/as/symbols.h b/gnu/usr.bin/as/symbols.h index 5a52790..535933f 100644 --- a/gnu/usr.bin/as/symbols.h +++ b/gnu/usr.bin/as/symbols.h @@ -1,42 +1,82 @@ /* symbols.h - - Copyright (C) 1987 Free Software Foundation, Inc. -This file is part of GAS, the GNU Assembler. + 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.3 1993/10/02 20:57:57 pk Exp $ + */ -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ extern struct obstack notes; /* eg FixS live here. */ -#define symbol_table_lookup(name) ((symbolS *)(symbol_find (name))) +extern 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. */ +/* 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(); -extern symbolS * symbol_rootP; /* all the symbol nodes */ -extern symbolS * symbol_lastP; /* last struct symbol we made, or NULL */ +#endif /* not __STDC__ */ -extern symbolS abs_symbol; -symbolS * symbol_find(); -void symbol_begin(); -char * local_label_name(); -void local_colon(); -symbolS * symbol_new(); -void colon(); -void symbol_table_insert(); -symbolS * symbol_find_or_make(); +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ -/* end: symbols.h */ +/* 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 0000000..f36629c --- /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/10/02 20:57:58 pk 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 0000000..6b46a03 --- /dev/null +++ b/gnu/usr.bin/as/testscripts/doboth @@ -0,0 +1,20 @@ +#!/bin/sh +# $Id: doboth,v 1.1 1993/10/02 21:01:07 pk 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 0000000..6c90cf9 --- /dev/null +++ b/gnu/usr.bin/as/testscripts/doobjcmp @@ -0,0 +1,89 @@ +#!/bin/sh +# $Id: doobjcmp,v 1.1 1993/10/02 21:01:08 pk 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 0000000..aa734c0 --- /dev/null +++ b/gnu/usr.bin/as/testscripts/dostriptest @@ -0,0 +1,15 @@ +#!/bin/sh +# $Id: dostriptest,v 1.1 1993/10/02 21:01:09 pk 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 0000000..051ee11e --- /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/10/02 21:01:10 pk 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 0000000..0a4771c --- /dev/null +++ b/gnu/usr.bin/as/testscripts/dounsortreloc @@ -0,0 +1,9 @@ +#!/bin/sh +# $Id: dounsortreloc,v 1.1 1993/10/02 21:01:11 pk 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 0000000..2dc5acd --- /dev/null +++ b/gnu/usr.bin/as/testscripts/dounsortsymbols @@ -0,0 +1,9 @@ +#!/bin/sh +# $Id: dounsortsymbols,v 1.1 1993/10/02 21:01:12 pk 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 index f94d3f4..c6ce12d 100644 --- a/gnu/usr.bin/as/version.c +++ b/gnu/usr.bin/as/version.c @@ -1,23 +1,30 @@ -#if defined(__STDC__) || defined(const) +#if (__STDC__ == 1) || defined(const) const #endif -char version_string[] = "GNU assembler version 1.38\n"; - -/* DO NOT PUT COMMENTS ABOUT CHANGES IN THIS FILE. +/* 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. + */ -Thu Jan 1 00:00:00 1970 Dennis Ritchie (dmr at alice) +#ifndef lint +static char rcsid[] = "$Id: version.c,v 1.3 1993/10/02 20:57:59 pk Exp $"; +#endif - * universe.c (temporal_reality): Began Time. -*/ +char version_string[] = "GNU assembler version 1.92.3, NetBSD $Revision: 1.3 $\n"; -#ifdef VMS +#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 index a850555..7cb1808 100644 --- a/gnu/usr.bin/as/write.c +++ b/gnu/usr.bin/as/write.c @@ -1,689 +1,602 @@ -/* write.c - emit .o file - Copyright(C)1986 Free Software Foundation, Inc. - Copyright (C) 1986,1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* - - Umm, with real good luck, this thing should be set up to do byteordering - correctly, but I may have managed to miss a place or two. Treat a.out - very carefully until you're SURE that it works. . . - - In order to cross-assemble the target machine must have an a.out header - similar to the one in a.out.h on THIS machine. Byteorder doesn't matter; - we take special care of it, but the numbers must be the same SIZE (# of - bytes) and in the same PLACE. If this is not true, you will have some - trouble. - */ +/* 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.6 1993/10/27 00:14:14 pk Exp $"; +#endif #include "as.h" -#include "md.h" #include "subsegs.h" #include "obstack.h" -#include "struc-symbol.h" -#include "write.h" -#include "symbols.h" +#include "output-file.h" -#ifdef SPARC -#include "sparc.h" -#endif -#ifdef I860 -#include "i860.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 -void append(); +#ifndef MANY_SEGMENTS +static struct frag *text_frag_root; +static struct frag *data_frag_root; -#ifdef hpux -#define EXEC_MACHINE_TYPE HP9000S200_ID +static struct frag *text_last_frag; /* Last frag in segment. */ +static struct frag *data_last_frag; /* Last frag in segment. */ #endif -#ifdef DOT_LABEL_PREFIX -#define LOCAL_LABEL(name) (name[0] =='.' \ - && ( name [1] == 'L' || name [1] == '.' )) -#else /* not defined DOT_LABEL_PREFIX */ -#define LOCAL_LABEL(name) (name [0] == 'L' ) -#endif /* not defined DOT_LABEL_PREFIX */ - -/* - * In: length of relocation (or of address) in chars: 1, 2 or 4. - * Out: GNU LD relocation length code: 0, 1, or 2. - */ +#ifndef WORKING_DOT_WORD +extern const int md_short_jump_size; +extern const int md_long_jump_size; +#endif -static unsigned char +static object_headers headers; -nbytes_r_length [] = { - 42, 0, 1, 42, 2 - }; +long string_byte_count; +static char *the_object_file; -static struct frag * text_frag_root; -static struct frag * data_frag_root; +char *next_object_file_charP; /* Tracks object file bytes. */ -static struct frag * text_last_frag; /* Last frag in segment. */ -static struct frag * data_last_frag; /* Last frag in segment. */ +/* static long length; JF unused */ /* String length, including trailing '\0'. */ -static struct exec the_exec; -static long int string_byte_count; +#if __STDC__ == 1 -static char * the_object_file; +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); -#if !defined(SPARC) && !defined(I860) -static -#endif -char * next_object_file_charP; /* Tracks object file bytes. */ +#else -static long int size_of_the_object_file; /* # bytes in object file. */ +static int is_dnrange(); +static long fixup_segment(); +static relax_addressT relax_align(); +void relax_segment(); -/* static long int length; JF unused */ /* String length, including trailing '\0'. */ +#endif /* not __STDC__ */ -static void relax_segment(); -void emit_segment(); -static relax_addressT relax_align(); -static long int fixup_segment(); -#if !defined(SPARC) && !defined(I860) -static void emit_relocations(); -#endif -/* +/* * fix_new() * * Create a fixS in obstack 'notes'. */ -void -#if defined(SPARC) || defined(I860) -fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type) +#ifdef PIC +fixS *fix_new(frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type, got_symbol) #else -fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel) +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. */ - long int offset; /* X_add_number. */ - int pcrel; /* TRUE if PC-relative relocation. */ -#if defined(SPARC) || defined(I860) - int r_type; +fragS *frag; /* Which frag? */ +int where; /* Where in that frag? */ +short int size; /* 1, 2, or 4 usually. */ +symbolS *add_symbol; /* X_add_symbol. */ +symbolS *sub_symbol; /* X_subtract_symbol. */ +#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 */ { - register fixS * fixP; - - fixP = (fixS *)obstack_alloc(¬es,sizeof(fixS)); - - fixP -> fx_frag = frag; - fixP -> fx_where = where; - fixP -> fx_size = size; - fixP -> fx_addsy = add_symbol; - fixP -> fx_subsy = sub_symbol; - fixP -> fx_offset = offset; - fixP -> fx_pcrel = pcrel; - fixP -> fx_next = * seg_fix_rootP; - - /* JF these 'cuz of the NS32K stuff */ - fixP -> fx_im_disp = 0; - fixP -> fx_pcrel_adjust = 0; - fixP -> fx_bsr = 0; - fixP ->fx_bit_fixP = 0; - -#if defined(SPARC) || defined(I860) - fixP->fx_r_type = r_type; + 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() */ - * seg_fix_rootP = fixP; -} - -void -write_object_file() +#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; - register symbolS * symbolP; - register symbolS ** symbolPP; - /* register fixS * fixP; JF unused */ - unsigned - text_siz, - data_siz, - syms_siz, - tr_siz, - dr_siz; - void output_file_create(); - void output_file_append(); - void output_file_close(); -#ifdef DONTDEF - void gdb_emit(); - void gdb_end(); -#endif - extern long omagic; /* JF magic # to write out. Is different for - Suns and Vaxen and other boxes */ - -#ifdef VMS - /* - * Under VMS we try to be compatible with VAX-11 "C". Thus, we - * call a routine to check for the definition of the procedure - * "_main", and if so -- fix it up so that it can be program - * entry point. - */ - VMS_Check_For_Main(); -#endif /* VMS */ - /* - * After every sub-segment, we fake an ".align ...". This conforms to BSD4.2 - * brane-damage. We then fake ".fill 0" because that is the kind of frag - * that requires least thought. ".align" frags like to have a following - * frag since that makes calculating their intended length trivial. - */ + 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. + */ #define SUB_SEGMENT_ALIGN (2) - for ( frchainP=frchain_root; frchainP; frchainP=frchainP->frch_next ) - { -#ifdef VMS - /* - * Under VAX/VMS, the linker (and PSECT specifications) - * take care of correctly aligning the segments. - * Doing the alignment here (on initialized data) can - * mess up the calculation of global data PSECT sizes. - */ + 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 /* VMS */ - subseg_new (frchainP -> frch_seg, frchainP -> frch_subseg); - frag_align (SUB_SEGMENT_ALIGN, 0); - /* frag_align will have left a new frag. */ - /* Use this last frag for an empty ".fill". */ - /* - * For this segment ... - * Create a last frag. Do not leave a "being filled in frag". - */ - frag_wane (frag_now); - frag_now -> fr_fix = 0; - know( frag_now -> fr_next == NULL ); - /* know( frags . obstack_c_base == frags . obstack_c_next_free ); */ - /* Above shows we haven't left a half-completed object on obstack. */ - } - - /* - * From now on, we don't care about sub-segments. - * Build one frag chain for each segment. Linked thru fr_next. - * We know that there is at least 1 text frchain & at least 1 data frchain. - */ - prev_fragPP = &text_frag_root; - for ( frchainP=frchain_root; frchainP; frchainP=next_frchainP ) - { - know( frchainP -> frch_root ); - * prev_fragPP = frchainP -> frch_root; - prev_fragPP = & frchainP -> frch_last -> fr_next; - if ( ((next_frchainP = frchainP->frch_next) == NULL) - || next_frchainP == data0_frchainP) - { - prev_fragPP = & data_frag_root; - if ( next_frchainP ) - { - text_last_frag = frchainP -> frch_last; - } - else - { - data_last_frag = frchainP -> frch_last; - } - } - } /* for(each struct frchain) */ - - /* - * We have two segments. If user gave -R flag, then we must put the - * data frags into the text segment. Do this before relaxing so - * we know to take advantage of -R and make shorter addresses. - */ - if ( flagseen [ 'R' ] ) - { - fixS *tmp; - - text_last_frag -> fr_next = data_frag_root; - text_last_frag = data_last_frag; - data_last_frag = NULL; - data_frag_root = NULL; - if(text_fix_root) { - for(tmp=text_fix_root;tmp->fx_next;tmp=tmp->fx_next) - ; - tmp->fx_next=data_fix_root; - } else - text_fix_root=data_fix_root; - data_fix_root=NULL; - } - - relax_segment (text_frag_root, SEG_TEXT); - relax_segment (data_frag_root, SEG_DATA); - /* - * Now the addresses of frags are correct within the segment. - */ - - know( text_last_frag -> fr_type == rs_fill && text_last_frag -> fr_offset == 0 ); - text_siz=text_last_frag->fr_address; -#ifdef SPARC - text_siz= (text_siz+7)&(~7); - text_last_frag->fr_address=text_siz; -#endif - md_number_to_chars((char *)&the_exec.a_text,text_siz, sizeof(the_exec.a_text)); - /* the_exec . a_text = text_last_frag -> fr_address; */ - - /* - * Join the 2 segments into 1 huge segment. - * To do this, re-compute every rn_address in the SEG_DATA frags. - * Then join the data frags after the text frags. - * - * Determine a_data [length of data segment]. - */ - if (data_frag_root) - { - register relax_addressT slide; - - know( text_last_frag -> fr_type == rs_fill && text_last_frag -> fr_offset == 0 ); - data_siz=data_last_frag->fr_address; -#ifdef SPARC - data_siz += (8 - (data_siz % 8)) % 8; - data_last_frag->fr_address = data_siz; -#endif - md_number_to_chars((char *)&the_exec.a_data,data_siz,sizeof(the_exec.a_data)); - /* the_exec . a_data = data_last_frag -> fr_address; */ - slide = text_siz; /* Address in file of the data segment. */ - for (fragP = data_frag_root; - fragP; - fragP = fragP -> fr_next) - { - fragP -> fr_address += slide; - } - know( text_last_frag ); - text_last_frag -> fr_next = data_frag_root; - } - else { - md_number_to_chars((char *)&the_exec.a_data,0,sizeof(the_exec.a_data)); - data_siz = 0; - } - - bss_address_frag . fr_address = text_siz + data_siz; -#ifdef SPARC - local_bss_counter=(local_bss_counter+7)&(~7); -#endif - md_number_to_chars((char *)&the_exec.a_bss,local_bss_counter,sizeof(the_exec.a_bss)); - - - /* - * - * Crawl the symbol chain. - * - * For each symbol whose value depends on a frag, take the address of - * that frag and subsume it into the value of the symbol. - * After this, there is just one way to lookup a symbol value. - * Values are left in their final state for object file emission. - * We adjust the values of 'L' local symbols, even if we do - * not intend to emit them to the object file, because their values - * are needed for fix-ups. - * - * Unless we saw a -L flag, remove all symbols that begin with 'L' - * from the symbol chain. - * - * Count the (length of the nlists of the) (remaining) symbols. - * Assign a symbol number to each symbol. - * Count the number of string-table chars we will emit. - * - */ - know( zero_address_frag . fr_address == 0 ); - string_byte_count = sizeof( string_byte_count ); - - /* JF deal with forward references first. . . */ - for(symbolP=symbol_rootP;symbolP;symbolP=symbolP->sy_next) { - if(symbolP->sy_forward) { - symbolP->sy_value+=symbolP->sy_forward->sy_value+symbolP->sy_forward->sy_frag->fr_address; - symbolP->sy_forward=0; +#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; } - } - symbolPP = & symbol_rootP; /* -> last symbol chain link. */ - { - register long int symbol_number; - - symbol_number = 0; - while (symbolP = * symbolPP) - { - name = symbolP -> sy_name; - if(flagseen['R'] && (symbolP->sy_nlist.n_type&N_DATA)) { - symbolP->sy_nlist.n_type&= ~N_DATA; - symbolP->sy_nlist.n_type|= N_TEXT; + + 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; } - /* if(symbolP->sy_forward) { - symbolP->sy_value += symbolP->sy_forward->sy_value + symbolP->sy_forward->sy_frag->fr_address; - } */ - symbolP -> sy_value += symbolP -> sy_frag -> fr_address; - /* JF the 128 bit is a hack so stabs like - "LET_STMT:23. . ." don't go away */ - /* CPH: 128 bit hack is moby loser. N_SO for file "Lower.c" - fell through the cracks. I think that N_STAB should be - used instead of 128. */ - /* JF the \001 bit is to make sure that local labels - ( 1: - 9: don't make it into the symtable either */ -#ifndef VMS /* Under VMS we need to keep local symbols */ - if ( !name || (symbolP->sy_nlist.n_type&N_STAB) - || (name[2]!='\001' && (flagseen ['L'] || ! LOCAL_LABEL(name) ))) -#endif /* not VMS */ - { - symbolP -> sy_number = symbol_number ++; -#ifndef VMS - if (name) - { /* Ordinary case. */ - symbolP -> sy_name_offset = string_byte_count; - string_byte_count += strlen (symbolP -> sy_name) + 1; - } - else /* .Stabd case. */ -#endif /* not VMS */ - symbolP -> sy_name_offset = 0; - symbolPP = & (symbolP -> sy_next); - } -#ifndef VMS - else - * symbolPP = symbolP -> sy_next; -#endif /* not VMS */ - } /* for each symbol */ - - syms_siz = sizeof( struct nlist) * symbol_number; - md_number_to_chars((char *)&the_exec.a_syms,syms_siz,sizeof(the_exec.a_syms)); - /* the_exec . a_syms = sizeof( struct nlist) * symbol_number; */ - } - - /* - * Addresses of frags now reflect addresses we use in the object file. - * Symbol values are correct. - * Scan the frags, converting any ".org"s and ".align"s to ".fill"s. - * Also converting any machine-dependent frags using md_convert_frag(); - */ - subseg_change( SEG_TEXT, 0); - - for (fragP = text_frag_root; fragP; fragP = fragP -> fr_next) - { - switch (fragP -> fr_type) - { - case rs_align: - case rs_org: - fragP -> fr_type = rs_fill; - know( fragP -> fr_var == 1 ); - know( fragP -> fr_next ); - fragP -> fr_offset - = fragP -> fr_next -> fr_address - - fragP -> fr_address - - fragP -> fr_fix; - break; - - case rs_fill: - break; - - case rs_machine_dependent: - md_convert_frag (fragP); - /* - * After md_convert_frag, we make the frag into a ".space 0". - * Md_convert_frag() should set up any fixSs and constants - * required. - */ - frag_wane (fragP); - break; - + 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; - extern md_short_jump_size; - extern md_long_jump_size; - - if(fragP->fr_subtype) { - fragP->fr_fix+=md_short_jump_size; - for(lie=(struct broken_word *)(fragP->fr_symbol);lie && lie->dispfrag==fragP;lie=lie->next_broken_word) - if(lie->added==1) - fragP->fr_fix+=md_long_jump_size; - } - frag_wane(fragP); - } - break; + 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) */ - } /* for each frag. */ - + + 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) { -#if defined(SPARC) || defined(I860) - fix_new( lie->frag, lie->word_goes_here - lie->frag->fr_literal, - 2, lie->add, - lie->sub, lie->addnum, - 0, NO_RELOC); -#endif -#ifdef NS32K - fix_new_ns32k(lie->frag, - lie->word_goes_here - lie->frag->fr_literal, - 2, - lie->add, - lie->sub, - lie->addnum, - 0, 0, 2, 0, 0); -#endif -#if !defined(SPARC) && !defined(NS32K) && !defined(I860) - fix_new( lie->frag, lie->word_goes_here - lie->frag->fr_literal, - 2, lie->add, - lie->sub, lie->addnum, - 0); + { + 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 - /* md_number_to_chars(lie->word_goes_here, - lie->add->sy_value +#endif /* TC_NS32K */ + /* md_number_to_chars(lie->word_goes_here, + S_GET_VALUE(lie->add) + lie->addnum - - (lie->sub->sy_value), - 2); */ - *prevP=lie->next_broken_word; - } else - prevP= &(lie->next_broken_word); - - for(lie=broken_words;lie;) { - struct broken_word *untruth; - char *table_ptr; - long table_addr; - long from_addr, - to_addr; - int n, - m; - - extern md_short_jump_size; - extern md_long_jump_size; - void md_create_short_jump(); - void md_create_long_jump(); - - - - fragP=lie->dispfrag; - - /* Find out how many broken_words go here */ - n=0; - for(untruth=lie;untruth && untruth->dispfrag==fragP;untruth=untruth->next_broken_word) - if(untruth->added==1) - n++; - - table_ptr=lie->dispfrag->fr_opcode; - table_addr=lie->dispfrag->fr_address+(table_ptr - lie->dispfrag->fr_literal); - /* Create the jump around the long jumps */ - /* This is a short jump from table_ptr+0 to table_ptr+n*long_jump_size */ - from_addr=table_addr; - to_addr = table_addr + md_short_jump_size + n * md_long_jump_size; - md_create_short_jump(table_ptr,from_addr,to_addr,lie->dispfrag,lie->add); - table_ptr+=md_short_jump_size; - table_addr+=md_short_jump_size; - - for(m=0;lie && lie->dispfrag==fragP;m++,lie=lie->next_broken_word) { - if(lie->added==2) - continue; - /* Patch the jump table */ - /* This is the offset from ??? to table_ptr+0 */ - to_addr = table_addr - - (lie->sub->sy_value); - md_number_to_chars(lie->word_goes_here,to_addr,2); - for(untruth=lie->next_broken_word;untruth && untruth->dispfrag==fragP;untruth=untruth->next_broken_word) { - if(untruth->use_jump==lie) - md_number_to_chars(untruth->word_goes_here,to_addr,2); - } - - /* Install the long jump */ - /* this is a long jump from table_ptr+0 to the final target */ - from_addr=table_addr; - to_addr=lie->add->sy_value+lie->addnum; - md_create_long_jump(table_ptr,from_addr,to_addr,lie->dispfrag,lie->add); - table_ptr+=md_long_jump_size; - table_addr+=md_long_jump_size; + - 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 -#ifndef VMS - /* - * Scan every FixS performing fixups. We had to wait until now to do - * this because md_convert_frag() may have made some fixSs. - */ - /* the_exec . a_trsize - = sizeof(struct relocation_info) * fixup_segment (text_fix_root, N_TEXT); - the_exec . a_drsize - = sizeof(struct relocation_info) * fixup_segment (data_fix_root, N_DATA); */ - - tr_siz=sizeof(struct relocation_info) * fixup_segment (text_fix_root, N_TEXT); - md_number_to_chars((char *)&the_exec.a_trsize, tr_siz ,sizeof(the_exec.a_trsize)); - dr_siz=sizeof(struct relocation_info) * fixup_segment (data_fix_root, N_DATA); - md_number_to_chars((char *)&the_exec.a_drsize, dr_siz, sizeof(the_exec.a_drsize)); - md_number_to_chars((char *)&the_exec.a_info,omagic,sizeof(the_exec.a_info)); - md_number_to_chars((char *)&the_exec.a_entry,0,sizeof(the_exec.a_entry)); - -#ifdef EXEC_MACHINE_TYPE - md_number_to_chars((char *)&the_exec.a_machtype, EXEC_MACHINE_TYPE, sizeof(the_exec.a_machtype)); -#endif -#ifdef EXEC_VERSION - md_number_to_chars((char *)&the_exec.a_version,EXEC_VERSION,sizeof(the_exec.a_version)); -#endif - - /* the_exec . a_entry = 0; */ - - size_of_the_object_file = - sizeof( the_exec ) + - text_siz + - data_siz + - syms_siz + - tr_siz + - dr_siz + - string_byte_count; +#endif /* not WORKING_DOT_WORD */ - next_object_file_charP - = the_object_file - = xmalloc ( size_of_the_object_file ); - - output_file_create (out_file_name); - - append (& next_object_file_charP, (char *)(&the_exec), (unsigned long)sizeof(the_exec)); - - /* - * Emit code. - */ - for (fragP = text_frag_root; fragP; fragP = fragP -> fr_next) - { - register long int count; - register char * fill_literal; - register long int fill_size; - - know( fragP -> fr_type == rs_fill ); - append (& next_object_file_charP, fragP -> fr_literal, (unsigned long)fragP -> fr_fix); - fill_literal= fragP -> fr_literal + fragP -> fr_fix; - fill_size = fragP -> fr_var; - know( fragP -> fr_offset >= 0 ); - for (count = fragP -> fr_offset; count; count --) - append (& next_object_file_charP, fill_literal, (unsigned long)fill_size); - } /* for each code frag. */ - - /* - * Emit relocations. - */ - emit_relocations (text_fix_root, (relax_addressT)0); - emit_relocations (data_fix_root, text_last_frag -> fr_address); - /* - * Emit all symbols left in the symbol chain. - * Any symbol still undefined is made N_EXT. - */ - for ( symbolP = symbol_rootP; symbolP; symbolP = symbolP -> sy_next ) - { - register char * temp; - - temp = symbolP -> sy_nlist . n_un . n_name; - /* JF fix the numbers up. Call by value RULES! */ - md_number_to_chars((char *)&(symbolP -> sy_nlist . n_un . n_strx ),symbolP -> sy_name_offset,sizeof(symbolP -> sy_nlist . n_un . n_strx )); - md_number_to_chars((char *)&(symbolP->sy_nlist.n_desc),symbolP->sy_nlist.n_desc,sizeof(symbolP -> sy_nlist . n_desc)); - md_number_to_chars((char *)&(symbolP->sy_nlist.n_value),symbolP->sy_nlist.n_value,sizeof(symbolP->sy_nlist.n_value)); - /* symbolP -> sy_nlist . n_un . n_strx = symbolP -> sy_name_offset; JF replaced by md above */ - if (symbolP -> sy_type == N_UNDF) - symbolP -> sy_type |= N_EXT; /* Any undefined symbols become N_EXT. */ - append (& next_object_file_charP, (char *)(& symbolP -> sy_nlist), - (unsigned long)sizeof(struct nlist)); - symbolP -> sy_nlist . n_un . n_name = temp; - } /* for each symbol */ - - /* - * next_object_file_charP -> slot for next object byte. - * Emit strings. - * Find strings by crawling along symbol table chain. - */ -/* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */ - md_number_to_chars((char *)&string_byte_count, string_byte_count, sizeof(string_byte_count)); - - append (& next_object_file_charP, (char *)&string_byte_count, (unsigned long)sizeof(string_byte_count)); - for ( symbolP = symbol_rootP; symbolP; symbolP = symbolP -> sy_next ) - { - if (symbolP -> sy_name) - { /* Ordinary case: not .stabd. */ - append (& next_object_file_charP, symbolP -> sy_name, - (unsigned long)(strlen (symbolP -> sy_name) + 1)); - } - } /* for each symbol */ - - know( next_object_file_charP == the_object_file + size_of_the_object_file ); - - output_file_append (the_object_file, size_of_the_object_file, out_file_name); - -#ifdef DONTDEF - if (flagseen['G']) /* GDB symbol file to be appended? */ - { - gdb_emit (out_file_name); - gdb_end (); - } +#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 - output_file_close (out_file_name); -#else /* VMS */ - /* - * Now do the VMS-dependent part of writing the object file - */ - VMS_write_object_file(text_siz, data_siz, text_frag_root, data_frag_root); -#endif /* VMS */ -} /* write_object_file() */ - /* * relax_segment() * @@ -696,564 +609,589 @@ write_object_file() * within the segment. Since segments live in different file addresses, * these frag addresses may not be the same as final object-file addresses. */ -#ifndef VMS -static -#endif /* not VMS */ -void -relax_segment (segment_frag_root, segment_type) - struct frag * segment_frag_root; - segT segment_type; /* N_DATA or N_TEXT */ -{ - register struct frag * fragP; - register relax_addressT address; - /* register relax_addressT old_address; JF unused */ - /* register relax_addressT new_address; JF unused */ - - know( segment_type == SEG_DATA || segment_type == SEG_TEXT ); - - /* In case md_estimate_size_before_relax() wants to make fixSs. */ - subseg_change (segment_type, 0); - - /* - * For each frag in segment: count and store (a 1st guess of) fr_address. - */ - address = 0; - for ( fragP = segment_frag_root; fragP; fragP = fragP -> fr_next ) - { - fragP -> fr_address = address; - address += fragP -> fr_fix; - switch (fragP -> fr_type) - { - case rs_fill: - address += fragP -> fr_offset * fragP -> fr_var; - break; - case rs_align: - address += relax_align (address, fragP -> fr_offset); - break; - case rs_org: - /* - * Assume .org is nugatory. It will grow with 1st relax. - */ - break; - - case rs_machine_dependent: - address += md_estimate_size_before_relax - (fragP, seg_N_TYPE [(int) segment_type]); - break; +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; + /* Broken words don't concern us yet */ + case rs_broken_word: + break; #endif - - default: - BAD_CASE( fragP -> fr_type ); - break; - } /* switch(fr_type) */ - } /* for each frag in the segment */ - - /* - * Do relax(). - */ - { - register long int stretch; /* May be any size, 0 or negative. */ - /* Cumulative number of addresses we have */ - /* relaxed this pass. */ - /* We may have relaxed more than one address. */ - register long int stretched; /* Have we stretched on this pass? */ - /* This is 'cuz stretch may be zero, when, - in fact some piece of code grew, and - another shrank. If a branch instruction - doesn't fit anymore, we could be scrod */ - - do - { - stretch = stretched = 0; - for (fragP = segment_frag_root; fragP; fragP = fragP -> fr_next) - { - register long int growth; - register long int was_address; - /* register long int var; */ - register long int offset; - register symbolS * symbolP; - register long int target; - register long int after; - register long int aim; - - was_address = fragP -> fr_address; - address = fragP -> fr_address += stretch; - symbolP = fragP -> fr_symbol; - offset = fragP -> fr_offset; - /* var = fragP -> fr_var; */ - switch (fragP -> fr_type) - { - case rs_fill: /* .fill never relaxes. */ - growth = 0; - break; - + + 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; - extern int md_short_jump_size; - extern int md_long_jump_size; - - /* Yes this is ugly (storing the broken_word pointer - in the symbol slot). Still, this whole chunk of - code is ugly, and I don't feel like doing anything - about it. Think of it as stubbornness in action */ - growth=0; - for(lie=(struct broken_word *)(fragP->fr_symbol); - lie && lie->dispfrag==fragP; - lie=lie->next_broken_word) { - - if(lie->added) - continue; - offset= lie->add->sy_frag->fr_address+lie->add->sy_value + lie->addnum - - (lie->sub->sy_frag->fr_address+lie->sub->sy_value); - if(offset<=-32768 || offset>=32767) { - if(flagseen['k']) - as_warn(".word %s-%s+%ld didn't fit",lie->add->sy_name,lie->sub->sy_name,lie->addnum); - lie->added=1; - if(fragP->fr_subtype==0) { - fragP->fr_subtype++; - growth+=md_short_jump_size; - } - for(untruth=lie->next_broken_word;untruth && untruth->dispfrag==lie->dispfrag;untruth=untruth->next_broken_word) - if(untruth->add->sy_frag==lie->add->sy_frag && untruth->add->sy_value==lie->add->sy_value) { - untruth->added=2; - untruth->use_jump=lie; + /* 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; + } } - growth+=md_long_jump_size; - } - } - } - break; + + 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) - { - know( ((symbolP -> sy_type & N_TYPE) == N_ABS) || ((symbolP -> sy_type & N_TYPE) == N_DATA) || ((symbolP -> sy_type & N_TYPE) == N_TEXT)); - know( symbolP -> sy_frag ); - know( (symbolP->sy_type&N_TYPE)!=N_ABS || symbolP->sy_frag==&zero_address_frag ); - target += - symbolP -> sy_value - + symbolP -> sy_frag -> fr_address; - } - know( fragP -> fr_next ); - after = fragP -> fr_next -> fr_address; - growth = ((target - after ) > 0) ? (target - after) : 0; - /* Growth may be -ve, but variable part */ - /* of frag cannot have < 0 chars. */ - /* That is, we can't .org backwards. */ - - growth -= stretch; /* This is an absolute growth factor */ - break; - - case rs_machine_dependent: - { - register const relax_typeS * this_type; - register const relax_typeS * start_type; - register relax_substateT next_state; - register relax_substateT this_state; - - start_type = this_type - = md_relax_table + (this_state = fragP -> fr_subtype); - target = offset; - if (symbolP) - { - know( ((symbolP -> sy_type & N_TYPE) == N_ABS) || ((symbolP -> sy_type & - N_TYPE) == N_DATA) || ((symbolP -> sy_type & N_TYPE) == N_TEXT)); - know( symbolP -> sy_frag ); - know( (symbolP->sy_type&N_TYPE)!=N_ABS || symbolP->sy_frag==&zero_address_frag ); - target += - symbolP -> sy_value - + symbolP -> sy_frag -> fr_address; - - /* If frag has yet to be reached on this pass, - assume it will move by STRETCH just as we did. - If this is not so, it will be because some frag - between grows, and that will force another pass. */ - - /* JF was just address */ - /* JF also added is_dnrange hack */ - /* There's gotta be a better/faster/etc way - to do this. . . */ - /* gnu@cygnus.com: I changed this from > to >= - because I ran into a zero-length frag (fr_fix=0) - which was created when the obstack needed a new - chunk JUST AFTER the opcode of a branch. Since - fr_fix is zero, fr_address of this frag is the same - as fr_address of the next frag. This - zero-length frag was variable and jumped to .+2 - (in the next frag), but since the > comparison - below failed (the two were =, not >), "stretch" - was not added to the target. Stretch was 178, so - the offset appeared to be .-176 instead, which did - not fit into a byte branch, so the assembler - relaxed the branch to a word. This didn't compare - with what happened when the same source file was - assembled on other machines, which is how I found it. - You might want to think about what other places have - trouble with zero length frags... */ - - if (symbolP->sy_frag->fr_address >= was_address && is_dnrange(fragP,symbolP->sy_frag)) - target += stretch; - - } - aim = target - address - fragP -> fr_fix; - /* The displacement is affected by the instruction size - * for the 32k architecture. I think we ought to be able - * to add fragP->fr_pcrel_adjust in all cases (it should be - * zero if not used), but just in case it breaks something - * else we'll put this inside #ifdef NS32K ... #endif - */ -#ifdef NS32K - aim += fragP->fr_pcrel_adjust; + 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 - - 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 - { + 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 */ - } + /* JF these next few lines of code are for the mc68020 which can't handle short + offsets of zero in branch instructions. What a kludge! */ + if (aim == 0 && this_state == (1<<2+0)) { /* FOO hard encoded from m.c */ + aim=this_type->rlx_forward+1; /* Force relaxation into word mode */ + } #endif -/* JF end of 68020 code */ - /* Look forwards. */ - for (next_state = this_type -> rlx_more; next_state; ) - { - if (aim <= this_type -> rlx_forward) - next_state = 0; - else - { /* Grow to next state. */ - this_type = md_relax_table + (this_state = next_state); - next_state = this_type -> rlx_more; - } - } - } - if (growth = this_type -> rlx_length - start_type -> rlx_length) - fragP -> fr_subtype = this_state; - } - break; - - default: - BAD_CASE( fragP -> fr_type ); - break; - } - if(growth) { - stretch += growth; - stretched++; - } - } /* For each frag in the segment. */ - } while (stretched); /* Until nothing further to relax. */ - } - - /* - * We now have valid fr_address'es for each frag. - */ +#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() */ - /* - * All fr_address's are correct, relative to their own segment. - * We have made all the fixS we will ever make. - */ -} /* relax_segment() */ - /* * Relax_align. Advance location counter to next address that has 'alignment' * lowest order bits all 0s. */ -static relax_addressT /* How many addresses does the .align take? */ -relax_align (address, alignment) - register relax_addressT address; /* Address now. */ - register long int alignment; /* Alignment (binary). */ +/* 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); -} - -/* - * fixup_segment() - */ -static long int -fixup_segment (fixP, this_segment_type) - register fixS * fixP; - int this_segment_type; /* N_TYPE bits for segment. */ + 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 int seg_reloc_count; - /* JF these all used to be local to the for loop, but GDB doesn't seem to be able to deal with them there, so I moved them here for a bit. */ - register symbolS * add_symbolP; - register symbolS * sub_symbolP; - register long int add_number; - register int size; - register char * place; - register long int where; - register char pcrel; - register fragS * fragP; - register int add_symbol_N_TYPE; - - - seg_reloc_count = 0; - for ( ; fixP; fixP = fixP -> fx_next) - { - fragP = fixP -> fx_frag; - know( fragP ); - where = fixP -> fx_where; - place = fragP -> fr_literal + where; - size = fixP -> fx_size; - add_symbolP = fixP -> fx_addsy; - sub_symbolP = fixP -> fx_subsy; - add_number = fixP -> fx_offset; - pcrel = fixP -> fx_pcrel; - if(add_symbolP) - add_symbol_N_TYPE = add_symbolP -> sy_type & N_TYPE; - if (sub_symbolP) - { - if(!add_symbolP) /* Its just -sym */ - { - if(sub_symbolP->sy_type!=N_ABS) - as_warn("Negative of non-absolute symbol %s", sub_symbolP->sy_name); - add_number-=sub_symbolP->sy_value; - } - else if ( ((sub_symbolP -> sy_type ^ add_symbol_N_TYPE) & N_TYPE) == 0 - && ( add_symbol_N_TYPE == N_DATA - || add_symbol_N_TYPE == N_TEXT - || add_symbol_N_TYPE == N_BSS - || add_symbol_N_TYPE == N_ABS)) - { - /* Difference of 2 symbols from same segment. */ - /* Can't make difference of 2 undefineds: 'value' means */ - /* something different for N_UNDF. */ - add_number += add_symbolP -> sy_value - sub_symbolP -> sy_value; - add_symbolP = NULL; - fixP -> fx_addsy = NULL; - } - else - { - /* Different segments in subtraction. */ - know( sub_symbolP -> sy_type != (N_ABS | N_EXT)) - if (sub_symbolP -> sy_type == N_ABS) - add_number -= sub_symbolP -> sy_value; - else - { - as_warn("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %d.", - seg_name[(int)N_TYPE_seg[sub_symbolP->sy_type&N_TYPE]], - sub_symbolP -> sy_name, fragP -> fr_address + where); - } - } - } - if (add_symbolP) - { - if (add_symbol_N_TYPE == this_segment_type && pcrel) - { - /* - * This fixup was made when the symbol's segment was - * SEG_UNKNOWN, but it is now in the local segment. - * So we know how to do the address without relocation. - */ - add_number += add_symbolP -> sy_value; - add_number -= -#ifndef NS32K - size + -#endif - where + fragP -> fr_address; -#if defined(NS32K) && defined(SEQUENT_COMPATABILITY) - if (fragP->fr_bsr) - add_number -= 0x12; /* FOO Kludge alert! */ + 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 - /* Kenny thinks this needs * - /* add_number +=size-2; */ - pcrel = 0; /* Lie. Don't want further pcrel processing. */ - fixP -> fx_addsy = NULL; /* No relocations please. */ - /* - * It would be nice to check that the address does not overflow. - * I didn't do this check because: - * + It is machine dependent in the general case (eg 32032) - * + Compiler output will never need this checking, so why - * slow down the usual case? - */ - } - else - { - switch (add_symbol_N_TYPE) - { - case N_ABS: - add_number += add_symbolP -> sy_value; - fixP -> fx_addsy = NULL; - add_symbolP = NULL; - break; - - case N_BSS: - case N_DATA: - case N_TEXT: - seg_reloc_count ++; - add_number += add_symbolP -> sy_value; - break; - - case N_UNDF: - seg_reloc_count ++; - break; - - default: - BAD_CASE( add_symbol_N_TYPE ); - break; - } /* switch on symbol seg */ - } /* if not in local seg */ - } /* if there was a + symbol */ - if (pcrel) - { - add_number -= -#ifndef NS32K - size + + 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; +#ifdef PIC + add_symbolP = fixP->fx_addsy = fixP->fx_gotsy; + if (add_symbolP) + add_symbol_segment = S_GET_SEGMENT(add_symbolP); #endif - where + fragP -> fr_address; - if (add_symbolP == 0) - { - fixP -> fx_addsy = & abs_symbol; - seg_reloc_count ++; - } - } - /* OVE added fx_im_disp for ns32k and others */ - if (!fixP->fx_bit_fixP) { - /* JF I hope this works . . . */ - if((size==1 && (add_number& ~0xFF) && (add_number&~0xFF!=(-1&~0xFF))) || - (size==2 && (add_number& ~0xFFFF) && (add_number&~0xFFFF!=(-1&~0xFFFF)))) - as_warn("Fixup of %d too large for field width of %d",add_number, size); - - switch (fixP->fx_im_disp) { - case 0: -#if defined(SPARC) || defined(I860) - fixP->fx_addnumber = add_number; - md_number_to_imm(place, add_number, size, fixP, this_segment_type); -#else - md_number_to_imm (place, add_number, size); - /* OVE: the immediates, like disps, have lsb at lowest address */ + } 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: + 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 && + (fixP->fx_r_type != RELOC_32 || + !S_IS_EXTERNAL(add_symbolP)))) #endif - break; - case 1: - md_number_to_disp (place, - fixP->fx_pcrel ? add_number+fixP->fx_pcrel_adjust:add_number, - size); - break; - case 2: /* fix requested for .long .word etc */ - md_number_to_chars (place, add_number, size); - break; - default: - as_fatal("Internal error in write.c in fixup_segment"); - } /* OVE: maybe one ought to put _imm _disp _chars in one md-func */ - } else { - md_number_to_field (place, add_number, fixP->fx_bit_fixP); - } - } /* For each fixS in this segment. */ - return (seg_reloc_count); -} /* fixup_segment() */ - - -/* The sparc needs its own emit_relocations() */ -#if !defined(SPARC) && !defined(I860) -/* - * emit_relocations() - * - * Crawl along a fixS chain. Emit the segment's relocations. - */ -static void -emit_relocations (fixP, segment_address_in_file) - register fixS * fixP; /* Fixup chain for this segment. */ - relax_addressT segment_address_in_file; -{ - struct relocation_info ri; - register symbolS * symbolP; - - /* JF this is for paranoia */ - bzero((char *)&ri,sizeof(ri)); - for ( ; fixP; fixP = fixP -> fx_next) - { - if (symbolP = fixP -> fx_addsy) + 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 { - -#ifdef NS32K - /* These two 'cuz of NS32K */ - ri . r_bsr = fixP -> fx_bsr; - ri . r_disp = fixP -> fx_im_disp; -#endif - - ri . r_length = nbytes_r_length [fixP -> fx_size]; - ri . r_pcrel = fixP -> fx_pcrel; - ri . r_address = fixP -> fx_frag -> fr_address - + fixP -> fx_where - - segment_address_in_file; - if ((symbolP -> sy_type & N_TYPE) == N_UNDF) - { - ri . r_extern = 1; - ri . r_symbolnum = symbolP -> sy_number; - } - else - { - ri . r_extern = 0; - ri . r_symbolnum = symbolP -> sy_type & N_TYPE; - } - - /* - The 68k machines assign bit-fields from higher bits to - lower bits ("left-to-right") within the int. VAXen assign - bit-fields from lower bits to higher bits ("right-to-left"). - Both handle multi-byte numbers in their usual fashion - (Big-endian and little-endian stuff). - Thus we need a machine dependent routine to make - sure the structure is written out correctly. FUN! - */ - md_ri_to_chars((char *) &ri, ri); - append (&next_object_file_charP, (char *)& ri, (unsigned long)sizeof(ri)); + 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() */ -} -#endif -int -is_dnrange(f1,f2) -struct frag *f1,*f2; +static int is_dnrange(f1,f2) +struct frag *f1; +struct frag *f2; { - while(f1) { - if(f1->fr_next==f2) - return 1; + 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; + } } -/* End: as-write.c */ + +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 index 7327690..01e7272 100644 --- a/gnu/usr.bin/as/write.h +++ b/gnu/usr.bin/as/write.h @@ -1,77 +1,120 @@ -/* write.h -> write.c - Copyright (C) 1987 Free Software Foundation, Inc. - -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* The bit_fix was implemented to support machines that need variables - to be inserted in bitfields other than 1, 2 and 4 bytes. - Furthermore it gives us a possibillity to mask in bits in the symbol - when it's fixed in the objectcode and check the symbols limits. - - The or-mask is used to set the huffman bits in displacements for the - ns32k port. - The acbi, addqi, movqi, cmpqi instruction requires an assembler that - can handle bitfields. Ie handle an expression, evaluate it and insert - the result in an some bitfield. ( ex: 5 bits in a short field of a opcode) +/* 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 */ -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; +#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 int fx_where; /* Where is the 1st byte to fix up? */ - symbolS * fx_addsy; /* NULL or Symbol whose value we add in. */ - symbolS * fx_subsy; /* NULL or Symbol whose value we subtract. */ - long int fx_offset; /* Absolute number we add in. */ - struct fix * fx_next; /* NULL or -> next fixS. */ - short int fx_size; /* How many bytes are involved? */ - char fx_pcrel; /* TRUE: pc-relative. */ - char fx_pcrel_adjust;/* pc-relative offset adjust */ - char fx_im_disp; /* TRUE: value is a displacement */ - bit_fixS * fx_bit_fixP; /* IF NULL no bitfix's to do */ - char fx_bsr; /* sequent-hack */ -#if defined(SPARC) || defined(I860) - char fx_r_type; /* Sparc hacks */ - long fx_addnumber; +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; +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 -COMMON fixS * text_fix_root; /* Chains fixSs. */ -COMMON fixS * data_fix_root; /* Chains fixSs. */ -COMMON fixS ** seg_fix_rootP; /* -> one of above. */ +#else /* not __STDC__ */ bit_fixS *bit_fix_new(); -/* end: write.h */ +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 index 78c8c7f..6962484 100644 --- a/gnu/usr.bin/as/xmalloc.c +++ b/gnu/usr.bin/as/xmalloc.c @@ -1,60 +1,75 @@ /* xmalloc.c - get memory or bust - Copyright (C) 1987 Free Software Foundation, Inc. -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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 * / + 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() + + */ -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. +#ifndef lint +static char rcsid[] = "$Id: xmalloc.c,v 1.3 1993/10/02 20:58:02 pk Exp $"; +#endif -SEE ALSO - malloc() +#include <stdio.h> -*/ +#if __STDC__ == 1 +#include <stdlib.h> +#else #ifdef USG #include <malloc.h> -#endif +#else +char * malloc(); +#endif /* USG */ +#endif /* not __STDC__ */ + +#define error as_fatal char * xmalloc(n) - long n; +long n; { - char * retval; - char * malloc(); - void error(); - - if ( ! (retval = malloc ((unsigned)n)) ) - { - error("virtual memory exceeded"); - } - return (retval); + char * retval; + void error(); + + if ((retval = malloc ((unsigned)n)) == NULL) + { + error("virtual memory exceeded"); + } + return (retval); } -/* end: xmalloc.c */ +/* end of xmalloc.c */ diff --git a/gnu/usr.bin/as/xrealloc.c b/gnu/usr.bin/as/xrealloc.c index a5010bc..1b26f43 100644 --- a/gnu/usr.bin/as/xrealloc.c +++ b/gnu/usr.bin/as/xrealloc.c @@ -1,61 +1,74 @@ -/* xrealloc.c -new memory or bust- - Copyright (C) 1987 Free Software Foundation, Inc. +/* xrealloc.c - new memory or bust -This file is part of GAS, the GNU Assembler. - -GAS is free software; you can 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. */ + 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 () + */ -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. +#ifndef lint +static char rcsid[] = "$Id: xrealloc.c,v 1.3 1993/10/02 20:58:03 pk Exp $"; +#endif -SEE ALSO - realloc () -*/ +#if __STDC__ == 1 +#include <stdlib.h> +#else #ifdef USG #include <malloc.h> -#endif +#else +char *realloc (); +#endif /* USG */ +#endif /* not __STDC__ */ + +#define error as_fatal char * -xrealloc (ptr, n) + xrealloc (ptr, n) register char *ptr; long n; { - char *realloc (); - void error(); - - if ((ptr = realloc (ptr, (unsigned)n)) == 0) - error ("virtual memory exceeded"); - return (ptr); + void error(); + + if ((ptr = realloc (ptr, (unsigned)n)) == 0) + error ("virtual memory exceeded"); + return (ptr); } -/* end: xrealloc.c */ +/* end of xrealloc.c */ |