diff options
53 files changed, 17038 insertions, 0 deletions
diff --git a/gnu/usr.bin/as/COPYING b/gnu/usr.bin/as/COPYING new file mode 100644 index 0000000..9a17037 --- /dev/null +++ b/gnu/usr.bin/as/COPYING @@ -0,0 +1,249 @@ + + GNU GENERAL PUBLIC LICENSE + Version 1, February 1989 + + Copyright (C) 1989 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The license agreements of most software companies try to keep users +at the mercy of those companies. By contrast, our General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. The +General Public License applies to the Free Software Foundation's +software and to any other program whose authors commit to using it. +You can use it for your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Specifically, the General Public License is designed to make +sure that you have the freedom to give away or sell copies of free +software, that you receive source code or can get it if you want it, +that you can change the software or use pieces of it in new free +programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of a such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must tell them their rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any program or other work which +contains a notice placed by the copyright holder saying it may be +distributed under the terms of this General Public License. The +"Program", below, refers to any such program or work, and a "work based +on the Program" means either the Program or any work containing the +Program or a portion of it, either verbatim or with modifications. Each +licensee is addressed as "you". + + 1. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this +General Public License and to the absence of any warranty; and give any +other recipients of the Program a copy of this General Public License +along with the Program. You may charge a fee for the physical act of +transferring a copy. + + 2. You may modify your copy or copies of the Program or any portion of +it, and copy and distribute such modifications under the terms of Paragraph +1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating that + you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, that + in whole or in part contains the Program or any part thereof, either + with or without modifications, to be licensed at no charge to all + third parties under the terms of this General Public License (except + that you may choose to grant warranty protection to some or all + third parties, at your option). + + c) If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive use + in the simplest and most usual way, to print or display an + announcement including an appropriate copyright notice and a notice + that there is no warranty (or else, saying that you provide a + warranty) and that users may redistribute the program under these + conditions, and telling the user how to view a copy of this General + Public License. + + d) You may charge a fee for the physical act of transferring a + copy, and you may at your option offer warranty protection in + exchange for a fee. + +Mere aggregation of another independent work with the Program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other work under the scope of these terms. + + 3. You may copy and distribute the Program (or a portion or derivative of +it, under Paragraph 2) in object code or executable form under the terms of +Paragraphs 1 and 2 above provided that you also do one of the following: + + a) accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal charge + for the cost of distribution) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +Source code for a work means the preferred form of the work for making +modifications to it. For an executable file, complete source code means +all the source code for all modules it contains; but, as a special +exception, it need not include source code for modules which are standard +libraries that accompany the operating system on which the executable +file runs, or for standard header files or definitions files that +accompany that operating system. + + 4. You may not copy, modify, sublicense, distribute or transfer the +Program except as expressly provided under this General Public License. +Any attempt otherwise to copy, modify, sublicense, distribute or transfer +the Program is void, and will automatically terminate your rights to use +the Program under this License. However, parties who have received +copies, or rights to use copies, from you under this General Public +License will not have their licenses terminated so long as such parties +remain in full compliance. + + 5. By copying, distributing or modifying the Program (or any work based +on the Program) you indicate your acceptance of this license to do so, +and all its terms and conditions. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the original +licensor to copy, distribute or modify the Program subject to these +terms and conditions. You may not impose any further restrictions on the +recipients' exercise of the rights granted herein. + + 7. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of the license which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +the license, you may choose any version ever published by the Free Software +Foundation. + + 8. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to humanity, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + + To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19xx name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and `show +c'; they could even be mouse-clicks or menu items--whatever suits your +program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + program `Gnomovision' (a program to direct compilers to make passes + at assemblers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/gnu/usr.bin/as/ChangeLog b/gnu/usr.bin/as/ChangeLog new file mode 100644 index 0000000..3e0e64f --- /dev/null +++ b/gnu/usr.bin/as/ChangeLog @@ -0,0 +1,917 @@ +Fri Jan 4 12:48:22 EST 1991 Jay Fenlason (hack@ai.mit.edu) + + * messages.c Moved as_perror from input-scrub.c Modified the + error messages to look better. + + * output-file.c Don't call as_fatal, just call exit() + + expr.c Slightly improve checking for foo-foo case in + clean_up_expression(). Detect foo: bar: ... foo-bar... + +Tue Dec 4 16:29:20 EST 1990 Jay Fenlason (hack@ai.mit.edu) + + * m68k.c Fixed an obscure bug involving AOFF mode with a + large constant displacement (Was forgetting to output the + extension word.) + + make-gas.com Added a three line patch from Eric Youngdale that + makes it possible to submit make-gas.com to a batch queue. + +Wed Nov 21 15:07:51 EST 1990 Jay Fenlason (hack@ai.mit.edu) + + * vms.c (VMS_TBT_Routine_END) Add a four line patch from + Eric Youngdale. + +Tue Nov 13 14:02:15 EST 1990 Jay Fenlason (hack@ai.mti.edu) + + * vms-dbg.c (VMS_DBG_record()) Another one character patch from + Eric Youngdale. + +Mon Oct 29 15:49:21 EST 1990 Jay Fenlason (hack@ai.mit.edu) + + * read.c Replace some as_warn calls with as_bad. + +Fri Oct 26 15:21:15 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * i386.c, i860.c, ns32k.c Add const changes. + +Mon Oct 22 14:04:26 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * sparc.c Add const changes. + + * make-gas.com define const= for VMS, since many older versions of + GCC don't work correctly with const under VMS. + +Thu Oct 18 12:44:11 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * i860.c i860-opcode.h Added patches from rgb@mcc.com + + * read.c, symbols.c, vms.c, + new_file vms-dbg-module.c + Added Eric Youngdale's <YOUNGDALE@v6550c.nrl.navy.mil> VMS debugging + patches, so debugging GCC output now works. + + * hash.c (hash_grow) Remember to blank out the wall entry in the new + hash table. This is important on systems where malloc() returns + non-zero storage. . . + +Tue Oct 16 10:11:35 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * output-file.c (output_file_create) if output filename is given as + '-', write to stdout. + + * m68k.c Finally get the PCREL code to work right. Add relaxation of + PCREL stuff This small fix from Ken Woodland + (kenny%datacube.uucp@uunet.uu.net). + + * m68k.c Added some const declarations to constants. (md_relax_table, + md_pseudo_table, etc. . .) + +Thu Oct 11 11:15:10 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * Makefile, read.c, write.c Include the i860 port. + (New files i860.c i860-opcode.h i860.h) + + * m68k.c Fix some addressing modes, (AOFF, AINDEX, etc) to work in + PC relative mode. + + * (all over) Raeburn's const hacking. This reduces the data-space size by + declaring many tables, etc, as 'const'. + +Thu Sep 27 13:43:49 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * m68k.c (get_num) Fix so that 1:w is treated properly. + + * Makefile Replace references to a.out.h with a.out.gnu.h + +Tue Sep 25 15:50:36 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * sparc.c (md_number_to_imm) Fix so that RELOC_32 locations contain + zero, so that it will work with some sparc loaders which don't assume + that the locations in question do. A xix line patch from Michael Bloom + (usc!srhqla!quad1!psivax!ttidca!mb@zaphod.mps.ohio-state.edu) + +Mon Sep 24 11:43:15 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * as.c #include <sys/types.h> if _POSIX_SOURCE defined. This because + <signal.h> uses pid_t that's defined in it. + + * m68k.c reverse the sense of -l option, and allow :w and :l to + override the default size of AOFF indexes. + + Also, allow -l to shorten branches to unknown labels from LONG to WORD. + +Thu Sep 13 17:05:09 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * vax.c (md_parse_option) Don't print a warning msg if given -J + +Wed Sep 5 14:26:14 EDT 1990 Jay Fenlason + + * expr.c (operand) Don't get garbaged high-order bits when given a + lot of leading zeroes. + +Tue Sep 4 11:40:21 EDT 1990 Jay Fenlason + + * read.c (pseudo_set) Compain if we're setting the symbol to the + difference of two symbols which are in different frags. (We can't + find out how far apart they are.) + +Wed Aug 15 12:18:58 EDT 1990 Jay Fenlason + + * m68k.c (m68k_ip_op) Dyke out the code that deals with parsing + :[wl] at the end of expressions since it is handled in get_num() + and this was putting the result in the wrong place anyway. + Corrected a couple of other references to ->isiz instead of con?->e_siz + +Mon Aug 13 15:53:46 EDT 1990 Jay Fenlason + + * read.c Handle .align specially on the sparc, or any other machine + where OTHER_ALIGN is defined. Added option and comments about it + to Makefile. + +Fri Aug 10 12:24:33 EDT 1990 Jay Fenlason + + * m68k.c (get_num) Handle SEG_PASS1 expressions. + +Mon Aug 6 16:32:29 EDT 1990 Jay Fenlason + + * write.c (fixup_segment) Added two patches for the NS32k + and SEQUENT A six line patch from Ian Dall + (asgard!aegir!hugin!augean!sibyl!ian@munnari.oz.au) + +Wed Aug 1 13:30:48 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * m68k.c Include REGISTER_PREFIX ifdefs. + + * write.c Include LOCAL_LABEL() and DOT_LABEL_PREFIX feature. + + * vax.c (md_parse_option) Accept -H option. + + * vms.c New version of case hasher, etc. These from Eric Youngdale + <YOUNGDALE@v6550c.nrl.navy.mil> + +Fri Jul 20 13:39:02 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * README Added README.APOLLO and README.COFF stuff + +Wed Jul 18 16:29:22 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * Makefile Added option for SEQUENT_COMPATABILITY + + * ns32k.c Add configurable syntax feature from + ian@sibyl.eleceng.ua.oz@augean.ua.oz.au + and SEQUENT_COMPATABILITY + + * ns32k-opcode.h Add configurable syntax feature. + +Mon Jul 16 11:44:14 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * write.c (relax_segment) On ns32k, add fragP->fr_pcrel_adjust to + aim. + (fixup_segment) On ns32k, don't subtract size from + add_number on pcrel external symbols. + + * ns32k.c (md_relax_table) Use correct max displacements. + This is a six-line patch from ian@sibyl.eleceng.ua.oz.au + + * ns32k.c (md_atof, convert_iif) Emit floating point numbers in + the correct byte order. A seven line patch from + ian@sibyl.eleceng.ua.oz.au + + * ns32k.c (all over) Some lint fixes. + +Mon Jul 9 13:17:00 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * app.c (do_scrub_next_char) If a comment is #{whitespace} + don't treat the next line as comment also. + + * m68k.c (...) Accept apc@(num:[wl]), etc. + + * i386.c (md_assemble) Get bitfields correct when doing cross + assembly to 386. A two line patch from Michael Bloom. + (usc!srhqla!quad1!ttidca!mb@zaphod.mps.ohio-state.edu). + + * README.APOLLO a new file with vasta@apollo's name, address + and phone # in it. + + * make-gas.com Deleted references to gdb source files. + +Fri Jul 6 14:34:27 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * i386.c Ignore the .optim directive + + * input-file.c Change from _IOLBF to _IOFBF in setbuffer emulation + for SYSV. + +Mon Jun 18 15:36:49 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * sparc.c #ifdef DONTDEF s_sparc_align, since it isn't called from + anywhere. + +Fri Jun 15 15:53:30 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * vax.c (md_parse_option) make the code agree with the documentation + on the behaviour of the -d option. + +Thu Jun 7 14:23:54 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * atof-ieee.c (gen_to_words) Assemble 0r-0 correctly. + + * Makefile Remove last references to gdb*.c files. + + * version.c New version 1.36 + +Tue May 22 13:22:26 EDT 1990 Jay Fenlason (hack@ai.mit.edu) + + * Makefile Mention a work-around for a possible problem with HPUX7.0 + +Mon May 21 14:06:04 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * sparc.c (sparc_ip): Change error message from "not in hash table" + to "unknown opcode". + +Wed May 16 15:33:14 EDT 1990 hack@wookumz + + * i386.c (i386_operand) Print error msg if given an operand like + 4(mumble) which we can't parse. + + * m68k.c (md_assemble) Add '3' to the list of operand-places that + can be found in 'symbol-dependent info'. Also change + 'confusing width' diagnostic to something more meaningful. + +Fri May 11 12:09:21 EDT 1990 hack@wookumz + + app.c (do_scrub_next_char) Don't flush the line after a line + consisting of a single '/' A one-line patch from Mike Kupfer + (kupfer@orc.olivetti.com) + + * i386.c (md_assemble) Call frag_wane() before calling frag_new() + A one line patch from Steve Bleazard (steve@robobar.co.uk + +Tue May 8 12:56:25 EDT 1990 hack@wookumz + + * atof-generic.c (atof-generic) Modified the Infinity detection code + to accept 0rinfinity and 0r-infinity as well as 0rinf and 0r-inf + +Thu Apr 26 15:17:31 EDT 1990 hack@wookumz + + * atof-ieee.c Change value of NaNs to 0x7fff ffff (float) and + 0x7fff ffff ffff ffff (double) If you want some other value for + NaN, use .long and spell it out yourself. + + atof-generic.c (atof_generic) Cleaned up code that detects NaN + and Inf. + + vax.c (md_assemble) print a useful error message if expression() + returns SEG_PASS1 or SEG_DIFFERENCE and we can't deal with those. + +Thu Apr 19 10:30:47 EDT 1990 hack@wookumz + + * input-scrub.c (AFTER_STRING) Make AFTER_STRING contain a null + so that the strstr() call when looking for "#NO_APP" after a "#APP" + will work. A two character patch from Bruce Robertson + (bruce@heather.pooh.com) + + * Makefile, i386.c Use atof-ieee.c instead of atof-i386.c + +Mon Apr 16 16:20:55 EDT 1990 hack@wookumz + + * m68k.c (md_relax_table) Many of the offsets were off by two. + Fixed some generic spacing problems thoughout the file. + +Thu Apr 12 12:22:35 EDT 1990 hack@wookumz + + * sparc.c (md_ri_to_chars) Handle little-endian cross assembly. + + * write.c (relax_segment) Compare addresses correctly to avoid + accidentally relaxing a branch that we don't have to. + These small changes from John Gilmore (gnu@toad.com) + +Fri Apr 6 12:52:15 EDT 1990 hack@wookumz + + * Makefile, expr.c symbols.c Correctly document the SUN_ASM_SYNTAX + option, and make it work. + +Tue Mar 20 12:46:59 EST 1990 + + * as.c (main) Only trap SIGHUP, SIGINT, SIGPIPE, and SIGTERM, + and only if they aren't being ignored. A three line patch + from Paul Eggert (eggert@twinsun.com) + + * write.c (relax_segment) Correct typo 'growth - ' should have been + growth = + + * atof-vax.c (next_bits, flonum_gen2vax) Clean up by sharing some + variables. While we're at it, fix next_bits so that it + doesn't use littlenums that don't exist. . . + +Tue Mar 13 16:23:21 EST 1990 hack@wookumz + + * Rename atof-m68k.c atof-ieee.c + + * Delete atof-ns32k.c + + * m68k.c sparc.c ns32k.c atof-ieee.c Call atof-ieee instead of + atof-m68k or atof-ns32k + + * Makefile Compile with atof-ieee.c instead of atof-ns32k.c or + atof-m68k.c + +Mon Mar 12 14:06:55 EST 1990 hack@wookumz + + * as.c If the signal handler gets called twice, exit immediatly. + + * ns32k.c Call gen_to_words with a pointer of the proper type, and + call md_number_to_chars to put the results in the proper byte-order. + Whoever wrote this code was *sloppy*! + + * Makefile ns32k.o depends on ns32k.c + + * vax.c (md_parse_option) If VMS, accept -+ and -h options. + + * vms.c (VMS_Case_Hack_Symbol) Replace #if NO_CASE_HACKING + with references to the -h option. These small VMS patches + from Angel Li (angel@flipper.miami.edu). + +Thu Mar 8 19:18:59 EST 1990 hack@wookumz + * vms.c Some trivial patches from Eric Youngdale + (YOUNGDALE@v6550c.nrl.navy.mil) + +Wed Mar 7 17:12:09 EST 1990 hack@wookumz + * make-gas.com (Define error as as_fatal when compiling vax.c and vms.c + A two line patch from Eric Youngdale + (YOUNGDALE@v6550c.nrl.navy.mil) + +Tue Mar 6 16:01:09 EST 1990 hack@wookumz + + * Makefile Include ns32k options in makefile. A small patch from + David Taylor (taylor@think.com). + + * as.c read.c write.c Makefile #ifdef DONTDEF out all the gdb + symbol stuff, since it isn't used anymore and it doesn't work. + +Mon Mar 5 14:51:04 EST 1990 hack@wookumz + + * i386.c (md_assemble) Replace memchr() with index(). + + * as.c Trap signals 1 through NSIG, print an error msg, and don't + produce an object file. + + * m68k.c Added a hack so that fsincosx fpx,fpy:fpz works. + + * messages.c New function: as_bad This is like as_warn, except + -W doesn't disable it, and calling it inhibits production of an + object file and causes a non-zero exit code. + +Tue Feb 13 14:25:53 EST 1990 hack@wookumz + * Makefile Include G0 and LOADLIBES for Sequent Symmetry. + Based on a small patch from Johan Widen (jw@sics.se) + +Thu Feb 1 14:08:58 EST 1990 hack@wookumz + * m68k.c Replace 'abort' with 'abort()' which will work. + +Wed Jan 24 17:15:08 EST 1990 hack@ai.mit.edu + + * read.c (ignore_rest_of_line) Have it print the first junk char + in both decimal and %c form. + + (read_a_source_file) On bad pseudo-op, print out the unknown + pseudo-op's name. + +Tue Jan 23 13:12:48 EST 1990 hack@ai.mit.edu + + * read.c (pseudo_set) If the symbol is external, have it remain + external. + + * i386-opcode.h Allow jc as a synonym for jb and jnc as a syn for jnb. + + +Wed Jan 3 09:35:31 EST 1990 hack@ai.mit.edu + + * ns32k.c [cpureg_032] Change register id of psr from 0x0b to 0x0d + * ns32k-opcode.h Change shift-counts for lsh and lshd + to one byte instead of 2 and 4. + A Trivial patch from John F. Peters (think!ames!practic.com!jfp@eddie) + +Tue Dec 5 16:37:44 EST 1989 hack@ai.mit.edu + + * ns32k.c (md_create_{long,short}_jump) Six line patch from + John F Peters (think!ames!vine!practice.com!jfp) to use the + correct addressing mode and byte-order for broken-word stuff. + + * write.c (write_object_file) One line patch to call fix_new_ns32k + with the correct # of args. + +Fri Dec 1 16:44:21 EST 1989 hack@ai.mit.edu + + * atof-generic.c, flonum-mult.c A real fix for the trailing-zeroes + problem from Georg Feil (ghfeil@white.toronto.edu) (two line change) + +Mon Nov 27 15:30:46 EST 1989 hack@ai.mit.edu + + * i386-opcode.h Fixed opcode-table entry for ljmp. A one char + patch from eliot@mgm.mit.edu + +Mon Nov 20 12:41:28 EST 1989 hack@ai.mit.edu + + * expr.c Replace the generic_buffer hack with a more portable one */ + + * atof-generic.c (atof_generic) Ignore trailing zeroes after a decimal + point. For some reason trailing zeroes (but not trailing nonzeroes) were + causing loss of precision. I don't know why. . . + + * vms.c Change copyright notice. Install changes from Kenneth Adelman + (adelman@tgv.com) for c++? (A dozen lines or so) + +Mon Nov 13 11:48:44 EST 1989 hack@ai.mit.edu + + * Makefile Add BINDIR and use it to control where the executable is + installed. + + * i386.c Use __builtin_alloca if possible (trivial patch from + Marco S. Hyman pacbell!dumbcat!marc) + +Mon Nov 6 18:24:47 EST 1989 hack@ai.mit.edu + + * version.c New version: 1.35 will be distributed with the + 1.36 gcc release. + +Mon Oct 30 10:38:11 EST 1989 hack@ai.mit.edu + + * atof-m68k.c (atof_m68k) Don't put the bits[] array on the stack, + since it may be pointed to after atof-m68k exits. + +Tue Oct 24 11:15:57 EDT 1989 hack@ai.mit.edu + + * atof-m68k.c Added #define for bcopy on USG systems. + #ifdef TEST the print_gen() function. + + * a.out.h if USE_HP_INC_HDR then use ../binutils/hp-include/a.out.h + +Fri Oct 13 14:36:48 EDT 1989 hack@ai.mit.edu + + * vax.c (all) Ran vax through indent -gnu to make it readable. + + vax.c (vip_op) Correctly assemble code like jmp $*0x11223344 + by setting vip_nbytes to 4 when using an immediate address. + I hope this works! + + m68k.c (s_proc (new)) Added s_proc no-op pseudo-op. + + Makefile Added instructions for compiling on Sequent Symmetry + and HP 9000/300. + + a.out.h Modified to compile on Sequent and HP above. (HP port + based on a msg from asjl@comp.vuw.ac.nz (real name unknown)). + +Tue Oct 10 14:39:44 EDT 1989 hack@ai.mit.edu + * vax.c (vip_op) Fixed a typo in an error msg and cleaned + up some spacing stuff. + +Wed Sep 27 19:07:12 EDT 1989 hack@ai.mit.edu + + * app.c (do_scrub_next_char) Fixed parsing of + # <line> "file" garbage + text so that it'll work again? (8 line patch from Mike Hibler + (mike@cs.utah.edu)) + +Mon Sep 18 16:26:01 EDT 1989 hack@ai.mit.edu + + * app.c (do_scrub_next_char): Modify parsing of /* ... */ to work + on the text /* ****/ + + * sparc.c (sparc_ip): Don't abort on insns that use the Alternate + Spaces. Try to assemble them correctly. + +Thu Sep 14 11:42:44 EDT 1989 hack@ai.mit.edu + + * sparc.c (md_number_to_imm) Dozen line patch from jkp@sauna.hut.fi + (Jyrki Kuoppala) so that gas output will work with shared libraries. + + * ns32k.c Include <string.h> instead of <strings.h> if USG defined. + + (md_end) free(freeptr_static) instead of free(freeptr) . + + * atof-ns32k.c Include as.h so that sysV stuff (bzero) will be + defined if needed. These ns32k changes from + nixbur!mollers.pad@seismo.css.gov (Josef Moellers) + +Fri Sep 1 11:39:52 EDT 1989 hack@ai.mit.edu + + * atof-m68k.c (gen_to_words) Get the sign right on negative + floating-point numbers. + +Wed Aug 30 13:59:57 EDT 1989 hack@ai.mit.edu + + * Makefile Remove the rest of the $< entries that kill sun make + +Fri Aug 25 15:00:30 EDT 1989 Nobody You Know (hack@ai.mit.edu) + + * atof-m68k.c (gen_to_words) deal with denormalized floating-point + numbers. + +Tue Aug 22 02:03:05 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * Makefile (gas-dist.tar): Put ChangeLog in the tar file. + + * version.c: Added comment telling Jay Fenl--I mean people--not to put + changes in version.c, but to use ChangeLog instead. + + * version.c (version_string): Put "GNU" in all-caps. + + * version.c: Moved all comments about changes to ChangeLog (this file). + Many anonymous entries have been attributed to Jay Fenlason (hack). + +Thu Aug 17 15:53:57 1989 Jay Fenlason (hack at apple-gunkies.ai.mit.edu) + + * Makefile: Removed $< references that seem + to choke some versions of make. + + * frags.c (frag_grow): Fixed to deal with requests for very + large frags (larger than frags.chunk_size). + + * app.c (do_scrub_next_char): Have it ignore any characters + after the filename in a # line "filename". + + * sparc.c (s_common): On an error, don't print out + input_line_pointer past the end of the line where the error is. + + * atof-generic.c (atof_generic): Accept any case for + inf and nan. + + * m68k.c (m68_ip): Don't use PC-relative mode for alterable + addressing modes. + +Tue Aug 15 04:58:36 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) + + * sparc.c (md_begin): Rewrote this function to perform consistency + checks with the new opcode table. + +Fri Aug 11 16:01:16 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) + + * sparc-opcode.h (struct sparc_opcode): Replaced `mask' field with + `lose'; removed `last' field. Updated all opcodes accordingly. + Fixed several opcodes that generated the wrong instructions. + sparc.c (md_begin, sparc_ip): Changed to use new struct sparc_opcode. + +Thu Aug 3 14:44:24 1989 Jay Fenlason (hack at apple-gunkies.ai.mit.edu) + + * Makefile (a32k): Use read- and write-ns32k.o + * ns32k.c (encode_operand): Make sure pcrel_adjust starts out zeroed. + * read.c (cons): Call fix_new_ns32k() if NS32K is defined. + * write.c (write_object_file): Ditto. + These so that .word sym-sym (etc) will produce values with + the proper byte-order. + +Wed Aug 2 12:55:?? 1989 Jay Fenlason (hack at apple-gunkies.ai.mit.edu) + + * sparc.c (comment_chars[]): Removed '|' because it was causing + problems. Probably not the best fix, since I suspect other + assemblers (68020) may get | in .stabs also, and the 68020 needs + the '|' comment character. + +Mon Jul 31 09:22:28 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) + + * sparc.c (sparc_ip): Allow the characters [0123] in opcodes. + +Tue Jul 25 16:32:12 1989 Jay Fenlason (hack) + + * atof-generic.c (atof_generic): Tried to keep + size_of_digits_in_littlenum from going negative. + + * sparc-opcode.h: Added duplicate [i+1] entries to go with + the [1+i] entries already there. A kludgy fix, but it works. + +Mon Jul 24 17:20:03 1989 Jay Fenlason (hack) + + * write.c (relax_segment): Modified rs_org code so it won't + occasionally dump core. + + * write.c (pseudo_set): Modified SEG_DIFFERENCE to (perhaps) + allow one to set a symbol to the difference of two other symbols. + + * ns32k.c (convert_iif): Moved size_so_far+=size and size=0 inside + the check for a valid type. + + * sparc-opcode.h: Modified the entries for std "q,[1+i]", "D,[1+i]", + and "Q,[1+i]". + +(In version 1.34) Jay Fenlason (hack) + + * Makefile: Reorganized, added stuff to make asparc. + + * sparc.c, sparc-opcode.h, sparc.h: Sparc port. + + * write.c: Set the size of text and bss segments to a multiple of eight + bytes. + + * m68k.c: Moved .single pseudo-op to machine independent part. + + * atof-generic.c: Fixed type in #ifdef __GNUC__. + + * sparc-opcode.h: Handle "mov REG, %y". + + * make-gas.com: Know that error.c no longer exists. + + * sparc.c: Handle [expr+reg]. + Don't call getExpression when looking for an immediate and getting + something that starts with % and isn't %hi or %lo. + + * Teach the 68k about long conditional branches. + +(In version 1.33) Jay Fenlason (hack) + + * Use __builtin_alloca if available. + + * README: Added more instructions for reporting bugs. + + * ns32k-opcode.h: Changed the acbb, acbw, and acbd insns. + + * vax.c: Replaced instances of LENGTH[STRING] with STRING[LENGTH]. + + * ns32k.c (encode_operand): Increased max size of bit field for exts + and inss instructions from 31 to 32 bits. + + * flonum-mult.c (flonum_multip): Fixed typo. + + * m68kc.: Allow #32 to be the same as #0 for bit-field ops. + + * make-gas.com, version.c, hex-value.c, flonum-const.c: VMS fixes. + + * ns32k.c, ns32k-opcode.h: More fixes from taylor@think.com. + Mostly typos in comments, etc. + + * ns32k-opcode.h: Fixed size of immediate operands to andw and andd + instructions. + +(In version 1.32) Jay Fenlason (hack) + + * read.c (s_set): Fixed misnamed variable. + + * as.c: Don't hang if given an invalid option. + + * m68k.c: Fixed bug in creating absolute long addresses for branches. + + * ns3k*: Some small ns32k patches. + + * m68k.c: Recognize 0rnan, 0rinf, 0r-inf. + + * app.c: Don't dump core on unterminated strings. + + * symbols.c: Give reasonable error messages. + + * ns32k*: Allow -m32032 and -m32532 options. + + * atof-*.c: Added support for NaN, Inf, and -Inf in atof_generic and + the various descriptions. + + * m68k.c (add_fix): Replace occurrences of "width==" with + "(width)==". This correct a precedence problem. + + * write.c, struc-symbol.h, m68k-opcode.h, m-hpux.h, Makefile: Changes + for HP-UX from Chris Hanson (cph@kleph.ai.mit.edu). + + * m68k-opcode.h: Reorder movem insns so gdb will see the ones using the + register list syntax first. + + * symbols.c (colon): Give more useful error messages when something was + defined as a .comm and is now trying to be defined locally. + Also, redefining a symbol is a fatal, not a warning. + + * m68k.c: Fixed a bug in using bignums as literal bit patterns for + floating-point numbers. + +(In version 1.31) Jay Fenlason (hack) + + * i386*: More patches. + + * Moved machine-dependent option parsing into the machine-dependent + source files. + +(In version 1.30) Jay Fenlason (hack) + + * i386*: New new version. + + * atof-m68k.c: Changed to be smaller, with somewhat better modularity. + Also fixed an obscure bug wherein next_bits would return random bits. + + * m68k.c: Be more careful about creating PC-relative addressing modes + on the 68000 and 68010. + + * frags.c (frag_new): Zero out the new frag. + + * Don't choke on "foo= bar" or on formfeeds. + + * read.c: Allow Sun-syntax local labels #ifdef SUN_ASM_SYNTAX. + * m-sun3.h: Defined SUN_ASM_SYNTAX. + +(In version 1.29) Jay Fenlason (hack) + + * i386.c: Newer version that fixes a bug wherein a jump instruction + would be split between two frags. + + * i386*: New version. + + * m68k.c: #ifdef M_SUN and -m68010, produce Sun-2 executables. + +(In version 1.28) Jay Fenlason (hack) + + * m68k.c: Added .single pseudo-op. + + * Made ". = X" and ".set .,X" equivalent to ".org X". + The pseudo-symbol "." has the value of the location the assembler is + currently assembling to. + +(In version 1.27) Jay Fenlason (hack) + + * Merged ns32k and i386 support. + +(In version 1.26) Jay Fenlason (hack) + + * Added partial ns32k support. + + * Added RMS's evil .word misfeature. Invented the -k (kludge) option + to warn that this misfeature was used. + + * Modified some files to get rid of warnings from GCC. + + * Added fix so that / can also be a comment character by itself. + +(In version 1.25) Jay Fenlason (hack) + + * Installed patches for VMS. + + * as.h (SIZEOF_STRUCT_FRAG): Added space before backslash-newline. + + * messages.c: Fixed typo. + + * app.c: Handle : correctly. + + * error.c: Removed; no longer used. + + * m68k-opcode.h: Added fnop. + Fixed to correctly handle fmovem with a register list and + non-predecriment addressing mode. + + * m68k-opcode.h: Fixed to know about long form of FBcc insns. + + * write.c: Warn if a fixup ended up being wider than its field width. + +(In version 1.24) Jay Fenlason (hack) + + * Accept and ignore -mc68010 and -m68010 switches. + + * Correctly assemble long subroutine calls on the 68000 without using a + 68020-specific instruction. + + * When calling with no filenames, read stdin. + +(In version 1.23) Jay Fenlason (hack) + + * app.c: Rewritten. + + * xmalloc.c, xrealloc.c: Replaced to work with GCC. + +(In version 1.22) Jay Fenlason (hack) + + * write.c: Fixed a VMS bug. + + * m68k.c: Fixed a bug having to do with turning absolute into + PC-relative. + + * atof-m68k.c (atof_m68k, gen_to_words): Try to avoid a problem with + running off the end of the LITTLENUMS. + + * vax.c: Fixed so parenthesized expressions work. + + * atof-generic.c: Added a cast that fixes problems with some C + compilers. + +(In version 1.21) + + * Changes for VMS support and correct bitfield order for + cross-assembly. + +(In version 1.20) + + * m68k*: Fixed "fmovel #N, fpcr". Added fpcr and fpsr to the list of + registers. + +(In version 1.19) + + * m68k.c? (md_convert_frag): Don't put the fixups for absolute long to + PC-relative in the data segment. + + * atof-generic.c: #include <alloca.h> #ifdef sparc. + +(In version 1.18) + + * Re-fixed _vfprintf stuff (?). + + * Made "movem REG, ADDR" work. + + * Improved preprocessing, without temporary files. + +(In version 1.17) + + * Don't produce an undefined empty symbol for ".globl foo," (a line + ending with a comma). + + * Fixed a bug wherein ".long X" became ".long 0" on the Sparc. + + * Fixed a bug which caused many "#APP" "#NO_APP" pairs to dump core. + + * Fixed calls to _doprnt to call _vfprintf #ifndef NO_VARARGS. + +(In version 1.16) + + * Merged HP-UX changes from Chris Hanson (cph@zurich.ai.mit.edu). + + * flonum-multip.c: Renamed to flonum-mult.c. + + * m-hpux.h: Created. + + * m68k.c (bcopy): Fixed. + +(In version 1.15) + + * struct-symbol.h: Renamed to struc-symbol.h. + +(In version 1.14) + + * vax.c: Added a quick fix for the offset of fixed-width branches not + fitting in the field given. + + * gdb-lines.c, read.c: Added support for .gdline and .gdbline + pseudo-ops. + +(In version 1.13) + + * read.c, atof-generic.c: Fixed bugs in reading in floating-point + numbers. + + * m68k-opcode.h: Made "fmovep a0@, fp0" work. + +(In version 1.12) + + * write.c: Fixed an obscure bug in relaction that would occasionally + cause the assembler to stop relaxing when it really had at least one + more pass to do. + +(In version 1.11) + + * m68k*: Allow register lists in fmovem. + + * Added more floating-point exponents. + + * Print an error message on exponent overflow. + +(In version 1.10) + + * Fixed floating point bugs that made it generate incorrect numbers for + values over 10^16 or so. + +(In version 1.09) + + * Fixed bug wherein you couldn't forward reference local label 0. + +(In version 1.08) + + * m68k.c, m68k-opcode.h: Added support for fmovem with register lists. + + * Fixed an obscure bug having to do with generating PC-relative + addressing mode for things in the middle of the instruction instead of + at the end. + +Wed Mar 1 15:29:24 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * *.*: Modified copyright notices to reflect new General Public + License. + + * Makefile: Added copyright notice. + +Fri Feb 17 09:42:01 1989 Jay Fenlason (hack at spiff) + + * Patched frags.c so that new frags start out bzero()ed. + +Thu Jan 26 14:23:44 1989 Jay Fenlason (hack at apple-gunkies.ai.mit.edu) + + * Added patches from pace to files as.h i386.c i386-opcode.h + imull foo,%eax no longer gets assembled into the 32-64 bit + multiply, which clobbers %edx behind gcc's back + + jcxz/jecxz were backwards + + There was a bug when using %ebp as a base register with no + displacement + + Instructions like andb $0xffffff, %al used to put out too many + immediate bytes + + The splitting jump instructions across frags could happen when + obstack_room()==6 too. + +Local Variables: +mode: indented-text +left-margin: 8 +version-control: never +End: diff --git a/gnu/usr.bin/as/Makefile b/gnu/usr.bin/as/Makefile new file mode 100644 index 0000000..e75351b6 --- /dev/null +++ b/gnu/usr.bin/as/Makefile @@ -0,0 +1,15 @@ +# @(#)Makefile 6.1 (Berkeley) 3/3/91 + +PROG= as +SRCS= app.c append.c as.c atof-generic.c bignum-copy.c \ + expr.c flonum-const.c flonum-copy.c flonum-mult.c \ + frags.c hash.c hex-value.c input-file.c input-scrub.c \ + messages.c obstack.c output-file.c read.c subsegs.c \ + symbols.c version.c write.c xmalloc.c xrealloc.c +CFLAGS+= -I$(.CURDIR) -I$(.CURDIR)/config \ + -DSIGTY=void -Derror=as_fatal +.PATH: $(.CURDIR)/config + +.include "config/Makefile.$(MACHINE)" + +.include <bsd.prog.mk> diff --git a/gnu/usr.bin/as/Makefile.gnu b/gnu/usr.bin/as/Makefile.gnu new file mode 100644 index 0000000..4b81b0c --- /dev/null +++ b/gnu/usr.bin/as/Makefile.gnu @@ -0,0 +1,356 @@ +# Makefile for GAS. +# Copyright (C) 1989, Free Software Foundation +# +# This file is part of GAS, the GNU Assembler. +# +# GAS is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. +# +# GAS is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GAS; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# This makefile may be used to make the VAX, 68020, 80386, +# SPARC, ns32k, or i860 assembler(s). + +BINDIR = /usr/local/bin +#CC=gcc + +# If you are on a BSD system, un-comment the next two lines, and comment out +# the lines for SystemV and HPUX below +G0 = -g -I. #-O -Wall +LDFLAGS = $(CFLAGS) +# +# To compile gas on a System Five machine, comment out the two lines above +# and un-comment out the next three lines +# Comment out the -lPW on the LOADLIBES line if you are using GCC. +# G0 = -g -I. -DUSG +# LDFLAGS = $(CFLAGS) +# LOADLIBES = -lmalloc -lPW +# +# To compile gas for HPUX, link m-hpux.h to m68k.h , and un-comment the +# next two lines. (If you are using GCC, comment out the alloca.o part) +# (Get alloca from the emacs distribution, or use GCC.) +# HPUX 7.0 may have a bug in setvbuf. gas gives an error message like +# 1:"Unknown operator" -- Statement 'NO_APP' ignored +# if setvbuf is broken. Re-compile input-file.c (and only input-file.c +# with -DVMS and the problem should go away. +# +# G0 = -g -I. -DUSG +# LOADLIBES = alloca.o +# +# To compile gas for a Sequent Symmetry, comment out all the above lines, +# and un-comment the next two lines. +# G0 = -g -I. -DUSE_SYSTEM_HDR -DEXEC_VERSION=1 +# LOADLIBES = -lc /usr/att/lib/libc.a + +# If you just want to compile the vax assembler, type 'make avax' + +# If you just want to compile the i386 assembler, type 'make a386' + +# If you just want to compile the ns32k assembler, type 'make a32k' + +# If you just want to compile the sparc assembler, type 'make asparc' + +# If you just want to compile the mc68020 assembler, make sure m68k.h +# is correctly set up, and type type 'make a68' (Except on HPUX machines, +# where you will have to make the changes marked below before typing +# 'make a68' +# m68k.h should be a symbolic or hard-link to one of +# m-sun3.h , m-hpux.h or m-generic.h +# depending on which machine you want to compile the 68020 assembler for. +# +# If you want the 68k assembler to be completely compatable with the the +# SUN one, un-comment the -DSUN_ASM_SYNTAX line below. +# +# If you machine does not have vfprintf, but does have _doprnt(), +# remove the # from the -DNO_VARARGS line below. +# +# If the return-type of a signal-hander is void (instead of int), +# remove the # from the -DSIGTY line below. +# +# To include the mc68851 mmu coprocessor instructions in the 68020 assembler, +# remove the # from the -Dm68851 line below. +# +# If you want the 68020 assembler use a register prefix character, un-comment +# the REGISTER_PREFIX line, and (maybe) change the '%' to the appropriate +# character. +# +# If you want the assembler to treat .L* or ..* symbols as local, instead of +# the usual L* symbols, un-comment the DOT_LABEL_PREFIX line. +# +# If you want the 80386 assembler to correctly handle fsub/fsubr and fdiv/fdivr +# opcodes (unlike most 80386 assemblers), remove the # from +# the -DNON_BROKEN_WORDS line below. +# +# To compile 80386 Gas for the Sequent Symmetry, un-comment the -DEXEC_VERSION +# and the -DUSE_SYSTEM_HDR lines below. +# +# To compile gas for the HP 9000/300 un-comment the -DUSE_HP_HDR line below. +# +# For the ns32k, the options are 32532 or 32032 CPU and 32381 or 32081 FPU. +# To select the NS32532, remove the # from the -DNS32532 line below. +# To compile in tne NS32381 opcodes in addition to the NS32081 opcodes +# (the 32381 is a superset of the 32081), remove the # from the -DNS32381 +# line below. +# +# For the ns32k on a Sequent, uncomment the SEQUENT_COMPATABILITY line below. +# +# If you want the .align N directive to align to the next N byte boundry, +# instead of the next 1<<N boundry, un-comment the OTHER_ALIGN line below. +# (This option is automatically enabled when building the sparc assembler. +# + +O1 = -DNO_VARARGS +O2 = # -DNON_BROKEN_WORDS +O3 = # -Dm68851 +O4 = # -DEXEC_VERSION=1 +O5 = # -DSIGTY=void +O6 = # -DNS32532 +O6 = # -DNS32381 +O7 = # -DDOT_LABEL_PREFIX +O8 = # -DSEQUENT_COMPATABILITY +O9 = # -DREGISTER_PREFIX=\'%\' +O10= # -DOTHER_ALIGN + +G1 = # -DUSE_SYSTEM_HDR +G2 = # -DUSE_HP_HDR +G3 = # -DSUN_ASM_SYNTAX + +OPTIONS = $(O1) $(O2) $(O3) $(O4) $(O5) $(O6) $(O7) $(O8) $(O9) $(O10) + +CFLAGS = $(G0) $(G1) $(G2) $(G3) $(G4) + +# +# To make the 68020 assembler compile as the default, un-comment the next +# line, and comment out all the other lines that start with DEFAULT_GAS +DEFAULT_GAS=a68 +# +# To make the VAX assembler compile as the default, un-comment the next +# line and commment out all the other lines that start with DEFAULT_GAS +#DEFAULT_GAS=avax +# +# To make the 80386 assembler compile as the default, un-comment the next +# line and commment out all the other lines that start with DEFAULT_GAS +#DEFAULT_GAS=a386 +# +# To make the ns32k assembler compile as the default, un-comment the next +# line and commment out all the other lines that start with DEFAULT_GAS +#DEFAULT_GAS=a32k +# +# To make the sparc assembler compile as the default, un-comment the next +# line and commment out all the other lines that start with DEFAULT_GAS +#DEFAULT_GAS=asparc +# +# To make the i860 assembler compile as the default, un-comment the next +# line and comment out all the other lines that start with DEFAULT_GAS +#DEFAULT_GAS=a860 + +# Global Sources ------------------------------------------------------------- + +a =\ +as.o xrealloc.o xmalloc.o hash.o hex-value.o \ +atof-generic.o append.o messages.o expr.o app.o \ +frags.o input-file.o input-scrub.o output-file.o \ +subsegs.o symbols.o version.o \ +flonum-const.o flonum-copy.o flonum-mult.o strstr.o bignum-copy.o \ +obstack.o +#gdb.o gdb-file.o gdb-symbols.o gdb-blocks.o gdb-lines.o + +a: $(DEFAULT_GAS) + @rm -f a + @ln $(DEFAULT_GAS) a + +# I860 GAS ------------------------------------------------------------------ +u = i860.o atof-ieee.o write-i860.o read-i860.o + +U = i860.c i860.h i860-opcode.h + +i860.o: i860.c i860.h i860-opcode.h as.h frags.h struc-symbol.h +i860.o: flonum.h expr.h hash.h md.h write.h read.h symbols.h + $(CC) -c $(CFLAGS) -DI860 i860.c + +atof-ieee.o: flonum.h + +write-i860.o: write.c i860.h + $(CC) -c -DI860 $(CFLAGS) write.c + mv write.o write-i860.o + +read-i860.o: read.c i860.h + $(CC) -c -DI860 $(CFLAGS) read.c + mv read.o read-i860.o + +a860: $a $u + $(CC) -o a860 $(LDFLAGS) $a $u $(LOADLIBES) + +# SPARC GAS ------------------------------------------------------------------ +v = sparc.o atof-ieee.o write-sparc.o read-sparc.o + +V = sparc.c sparc.h sparc-opcode.h + +atof-ieee.o: flonum.h +sparc.o: sparc.c sparc.h sparc-opcode.h as.h frags.h struc-symbol.h +sparc.o: flonum.h expr.h hash.h md.h write.h read.h symbols.h + $(CC) -c $(CFLAGS) -DSPARC sparc.c + +write-sparc.o: write.c + $(CC) -c -DSPARC $(CFLAGS) write.c + mv write.o write-sparc.o + +read-sparc.o: read.c + $(CC) -c -DSPARC $(CFLAGS) read.c + mv read.o read-sparc.o + +asparc: $a $v + $(CC) -o asparc $(LDFLAGS) $a $v $(LOADLIBES) + +# NS32K GAS ------------------------------------------------------------------ +w = ns32k.o atof-ieee.o write-ns32k.o read-ns32k.o + +W = ns32k.c ns32k-opcode.h + +atof-ieee.o: flonum.h +ns32k.o: as.h frags.h struc-symbol.h flonum.h expr.h md.h hash.h +ns32k.o: write.h symbols.h ns32k-opcode.h ns32k.c + $(CC) $(CFLAGS) $(OPTIONS) -c ns32k.c + +write-ns32k.o: write.c + $(CC) -c -DNS32K $(CFLAGS) write.c + mv write.o write-ns32k.o + +read-ns32k.o: + $(CC) -c -DNS32K $(CFLAGS) read.c + mv read.o read-ns32k.o + +a32k: $a $w + $(CC) -o a32k $(LDFLAGS) $a $w $(LOADLIBES) + +# 80386 GAS ------------------------------------------------------------------ +x = i386.o atof-ieee.o write.o read.o + +X = i386.c i386.h i386-opcode.h + +i386.o: i386.c as.h read.h flonum.h frags.h struc-symbol.h expr.h +i386.o: symbols.h hash.h md.h i386.h i386-opcode.h + $(CC) $(CFLAGS) $(OPTIONS) -c i386.c + +atof-ieee.o: flonum.h + +a386: $a $x + $(CC) -o a386 $(LDFLAGS) $a $x $(LOADLIBES) + +# 68020 GAS ------------------------------------------------------------------ +y = m68k.o atof-ieee.o write.o read.o + +Y = m68k.c atof-ieee.c m68k-opcode.h m-hpux.h m-sun3.h m-generic.h + +atof-ieee.o: flonum.h + +m68k.o: m68k.c a.out.gnu.h as.h expr.h flonum.h frags.h hash.h +m68k.o: m68k-opcode.h m68k.h md.h obstack.h struc-symbol.h + $(CC) $(CFLAGS) $(OPTIONS) -c m68k.c + +a68: $a $y + $(CC) -o a68 $(LDFLAGS) $a $y $(LOADLIBES) + +# VAX GAS -------------------------------------------------------------------- +z = vax.o atof-vax.o write.o read.o + +Z = vax.c atof-vax.c vax-opcode.h vax-inst.h \ + make-gas.com objrecdef.h vms.c vms-dbg.c README-vms-dbg + +vax.o: vax.c a.out.gnu.h as.h expr.h flonum.h frags.h md.h obstack.h +vax.o: read.h struc-symbol.h symbols.h vax-inst.h vax-opcode.h +atof-vax.o: as.h flonum.h read.h + +avax: $a $z + $(CC) -o avax $(LDFLAGS) $a $z $(LOADLIBES) + +# global files --------------------------------------------------------------- + +as.o: as.c + $(CC) $(CFLAGS) $(OPTIONS) -c as.c + +messages.o: messages.c + $(CC) $(CFLAGS) $(OPTIONS) -c messages.c + +hash.o: hash.c + $(CC) $(CFLAGS) -Derror=as_fatal -c hash.c + +xmalloc.o: xmalloc.c + $(CC) $(CFLAGS) -Derror=as_fatal -c xmalloc.c + +xrealloc.o: xrealloc.c + $(CC) $(CFLAGS) -Derror=as_fatal -c xrealloc.c + +A =\ +as.c xrealloc.c xmalloc.c hash.c hex-value.c \ +atof-generic.c append.c messages.c expr.c bignum-copy.c \ +frags.c input-file.c input-scrub.c output-file.c read.c \ +subsegs.c symbols.c write.c strstr.c \ +flonum-const.c flonum-copy.c flonum-mult.c app.c version.c \ +obstack.c \ +#gdb.c gdb-file.c gdb-symbols.c gdb-blocks.c \ +#gdb-lines.c + +H = \ +a.out.gnu.h as.h bignum.h expr.h flonum.h \ +frags.h hash.h input-file.h md.h \ +obstack.h read.h struc-symbol.h subsegs.h \ +symbols.h write.h + +dist: COPYING README ChangeLog $A $H $Z $Y $X $W $V $U Makefile + echo gas-`sed -n -e '/ version /s/[^0-9.]*\([0-9.]*\).*/\1/p' < version.c` > .fname + mkdir `cat .fname` + + ln COPYING README ChangeLog $A $H $Z $Y $X $W $V $U Makefile `cat .fname` + tar cvhZf `cat .fname`.tar.Z `cat .fname` + -rm -r `cat .fname` + -rm .fname + +clean: + rm -f a avax a68 a386 a32k asparc $a $v $w $x $y $z a core gmon.out bugs a.out + +install: a + cp a $(BINDIR)/gas + + +# General .o-->.h dependencies + +app.o: as.h +as.o: a.out.gnu.h as.h read.h struc-symbol.h write.h +atof-generic.o: flonum.h +bignum-copy.o: bignum.h +expr.o: a.out.gnu.h as.h expr.h flonum.h obstack.h read.h struc-symbol.h +expr.o: symbols.h +flonum-const.o: flonum.h +flonum-copy.o: flonum.h +flonum-mult.o: flonum.h +flonum-normal.o:flonum.h +flonum-print.o: flonum.h +frags.o: a.out.gnu.h as.h frags.h obstack.h struc-symbol.h subsegs.h +#gdb.o: as.h +#gdb-blocks.o: as.h +#gdb-lines.o: as.h frags.h obstack.h +#gdb-symbols.o: a.out.gnu.h as.h struc-symbol.h +hash.o: hash.h +input-file.o: input-file.h +input-scrub.o: as.h input-file.h read.h +messages.o: as.h +obstack.o: obstack.h +read.o: a.out.gnu.h as.h expr.h flonum.h frags.h hash.h md.h obstack.h +read.o: read.h struc-symbol.h symbols.h +subsegs.o: a.out.gnu.h as.h frags.h obstack.h struc-symbol.h subsegs.h write.h +symbols.o: a.out.gnu.h as.h frags.h hash.h obstack.h struc-symbol.h symbols.h +write.o: a.out.gnu.h as.h md.h obstack.h struc-symbol.h subsegs.h +write.o: symbols.h write.h + +flonum.h: bignum.h + diff --git a/gnu/usr.bin/as/NOTES b/gnu/usr.bin/as/NOTES new file mode 100644 index 0000000..b3f3f92 --- /dev/null +++ b/gnu/usr.bin/as/NOTES @@ -0,0 +1,35 @@ +gdb debugging of assembly sources: + write a function linestab() that generates a .stabd symbol + independently of the input + write a function filestab() to generate a .stabs symbol + we need to take especial care with #line directives + since we want to handle locore, and locore is passed thru cpp + this could be tough + outline of a solution: + cpp sends us lines of the form + # logical-line "logical-file" trash + these lines are interpreted ahead of the gas preprocess pass + in the starting state, the logical filename is the same + as the real filename (in case there're no #lines) + the initial logical line number is 1 + every time we're ready to process a new instruction line, + if the source file has changed, + emit a .stabs for the logical file + emit a .stabd for the logical line + bump the logical line number + can gas eat multiple actual lines in one insn? + +i386 nits: + jmp *$foo produces a short relative branch + string quotes in comments + Bill says gas eats text across newlines to find matches + works fine for me + I think it's most likely due to cpp + make / no longer be a comment char + it's now like the VAX: # is the only comment char + incorrectly assembles lcall, int3, into, bsr/f instructions + constant expressions fail if more than a few terms + gives (low+2)*3+4*5 as an example + works fine for me + cpp seems to think $ is a valid literal + use -$ in /usr/bin/cpp diff --git a/gnu/usr.bin/as/README.gnu b/gnu/usr.bin/as/README.gnu new file mode 100644 index 0000000..46f135fc --- /dev/null +++ b/gnu/usr.bin/as/README.gnu @@ -0,0 +1,133 @@ +This is the beta-test version of the GNU assembler. (Probably +around Version 1.35, but check version.c which gets updated more +often than this readme.) + +The assembler has been modified to support a feature that is +potentially useful when assembling compiler output, but which may +confuse assembly language programmers. If assembler encounters a +.word pseudo-op of the form symbol1-symbol2 (the difference of two +symbols), and the difference of those two symbols will not fit in 16 +bits, the assembler will create a branch around a long jump to +symbol1, and insert this into the output directly before the next +label: The .word will (instead of containing garbage, or giving an +error message) contain (the address of the long jump)-symbol2. This +allows the assembler to assemble jump tables that jump to locations +very far away into code that works properly. If the next label is +more than 32K away from the .word, you lose (silently) RMS claims +this will never happen. If the -k option is given, you will get a +warning message when this happens. + +These files are currently set up to allow you to compile all of the +versions of the assembler (68020, VAX, ns32k, and i386) on the same +machine. To compile the 68020 version, type 'make a68'. To compile +the VAX version, type 'make avax'. To compile the ns32k version, +type 'make a32k'. To compile the Intel 80386 version, type 'make +a386'. The Makefile contains instructions on how to make one of the +assemblers compile as the default. + +Before you can compile the 68020 version of the assembler, you must +make m68k.h be a link to m-sun3.h , m-hpux.h or m-generic.h . If +you are on a SUN-3 (or other machine that uses a magic number of +(2 << 16) | OMAGIC type 'ln -s m-sun3.h m68k.h' else if you are on a +machine running HP-UX, type 'ln m-hpux.h m689k.h' else type +'ln -s m-generic.h m68k.h' If your machine does not support symbolic +links, omit the '-s'. + +See the instructions in the Makefile for compiling gas for the Sequent +Symmetry (dynix 3.0.12 + others?) or for the HP 9000/300 + +If your machine does not have both varargs.h and vfprintf(), but does have +_doprnt() add -DNO_VARARGS to the CFLAGS line in the makefile. If your +machine has neither vfprintf() or _doprnt(), you will have to change +messages.c in order to get readable error messages from the assembler. + + + REPORTING BUGS IN GAS + +Bugs in gas should be reported to bug-gnu-utils@prep.ai.mit.edu If you can't +get through to prep, try hack@gnu.ai.mit.edu or hack@media-lab.media.mit.edu + +If you report a bug in GAS, please remember to include: + +A description of exactly what went wrong. + +The type of machine GAS was running on (VAX, 68020, etc), + +The Operating System GAS was running under. + +The options given to GAS. + +The actual input file that caused the problem. + +It is silly to report a bug in GAS without including an input file for +GAS. Don't ask us to generate the file just because you made it from +files you think we have access to. + +1. You might be mistaken. +2. It might take us a lot of time to install things to regenerate that file. +3. We might get a different file from the one you got, and might not see any +bug. + +To save us these delays and uncertainties, always send the input file +for the program that failed. + +If the input file is very large, and you are on the internet, you may +want to make it avaliable for anonymous FTP instead of mailing it. If you +do, include instructions for FTP'ing it in your bug report. + +------------------------------ README.APOLLO --------------------------------- + +The changes required to get the GNU C compiler running on +Apollo 68K platforms are available via anonymous ftp from +labrea.stanford.edu (36.8.0.47) in the form of a compressed +tar file named "/pub/gnu/apollo-gcc-1.37.tar.Z". +The size of the file is 84145 bytes. + +To build GCC for the Apollo you'll need the virgin FSF +distributions of bison-1.03, gas-1.34, and gcc-1.37. They +are also on labrea.stanford.edu as well as prep.ai.mit.edu. +My changes are to enable gas to produce Apollo COFF object +files and allow gcc to parse some of the syntax extensions +which appear in Apollo C header files. Note that the +COFF encapsulation technique cannot be used on the Apollo. + +The tar file should be unpacked in the directory containing +the gas-1.34 and gcc-1.37 directories; a few files will be overlaid, +and an APOLLO-GCC-README file will appear in the top directory. +This file contains detailed instructions on how to proceed. + +These changes will only work for SR10.1 or later systems, using +the 6.6 or later version of the Apollo C compiler. + +If you do not have ftp access, I can mail you the changes in the +form of diffs; they are approximately 40K in length. If you request +them, be sure to give me a voice phone number so I can contact you +in case I can't send you mail; I've had several requests in the +past from people I can't contact. + +By the way, I'm working on getting the GNU C++ compiler running; +there are a couple problems to solve. I hope to be able to announce +the Apollo version shortly after the 1.37 version is released. + +John Vasta Hewlett-Packard Apollo Systems Division +vasta@apollo.hp.com M.S. CHA-01-LT +(508) 256-6600 x6362 300 Apollo Drive, Chelmsford, MA 01824 +UUCP: {decwrl!decvax, mit-eddie, attunix}!apollo!vasta + +------------------------------------ + +You might refer others who are interested in a similar thing. + +Kevin Buchs buchs@mayo.edu + + +------------------------------ README.COFF ----------------------------------- + +If you have a COFF system, you may wish to aquire + + UUCP: osu-cis!~/gnu/coff/gnu-coff.tar.Z + or + FTP: tut.cis.ohio-state.edu:/pub/gnu/coff/gnu-coff.tar.Z + +These contain patches for gas that will make it produce COFF output. +I have never seen these patches, so I don't know how well they work. diff --git a/gnu/usr.bin/as/app.c b/gnu/usr.bin/as/app.c new file mode 100644 index 0000000..a0ec8a2 --- /dev/null +++ b/gnu/usr.bin/as/app.c @@ -0,0 +1,392 @@ +/* This is the Assembler Pre-Processor + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* App, the assembler pre-processor. This pre-processor strips out excess + spaces, turns single-quoted characters into a decimal constant, and turns + # <number> <filename> <garbage> into a .line <number>;.file <filename> pair. + This needs better error-handling. + */ +#include <stdio.h> +#ifdef USG +#define bzero(s,n) memset(s,0,n) +#endif +#if !defined(__STDC__) && !defined(const) +#define const /* Nothing */ +#endif + +static char lex [256]; +static const char symbol_chars[] = + "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +extern const char comment_chars[]; +extern const char line_comment_chars[]; + +#define LEX_IS_SYMBOL_COMPONENT (1) +#define LEX_IS_WHITESPACE (2) +#define LEX_IS_LINE_SEPERATOR (4) +#define LEX_IS_COMMENT_START (8) /* JF added these two */ +#define LEX_IS_LINE_COMMENT_START (16) +#define IS_SYMBOL_COMPONENT(c) (lex [c] & LEX_IS_SYMBOL_COMPONENT) +#define IS_WHITESPACE(c) (lex [c] & LEX_IS_WHITESPACE) +#define IS_LINE_SEPERATOR(c) (lex [c] & LEX_IS_LINE_SEPERATOR) +#define IS_COMMENT(c) (lex [c] & LEX_IS_COMMENT_START) +#define IS_LINE_COMMENT(c) (lex [c] & LEX_IS_LINE_COMMENT_START) + +void +do_scrub_begin() +{ + const char *p; + + bzero (lex, sizeof(lex)); /* Trust NOBODY! */ + lex [' '] |= LEX_IS_WHITESPACE; + lex ['\t'] |= LEX_IS_WHITESPACE; + for (p =symbol_chars;*p;++p) + lex [*p] |= LEX_IS_SYMBOL_COMPONENT; + lex ['\n'] |= LEX_IS_LINE_SEPERATOR; +#ifdef DONTDEF + lex [':'] |= LEX_IS_LINE_SEPERATOR; +#endif + lex [';'] |= LEX_IS_LINE_SEPERATOR; + for (p=comment_chars;*p;p++) + lex[*p] |= LEX_IS_COMMENT_START; + for (p=line_comment_chars;*p;p++) + lex[*p] |= LEX_IS_LINE_COMMENT_START; +} + +FILE *scrub_file; + +int +scrub_from_file() +{ + return getc(scrub_file); +} + +void +scrub_to_file(ch) +int ch; +{ + ungetc(ch,scrub_file); +} + +char *scrub_string; +char *scrub_last_string; + +int +scrub_from_string() +{ + return scrub_string == scrub_last_string ? EOF : *scrub_string++; +} + +void +scrub_to_string(ch) +int ch; +{ + *--scrub_string=ch; +} + +int +do_scrub_next_char(get,unget) +int (*get)(); +void (*unget)(); +/* FILE *fp; */ +{ + /* State 0: beginning of normal line + 1: After first whitespace on normal line (flush more white) + 2: After first non-white on normal line (keep 1white) + 3: after second white on normal line (flush white) + 4: after putting out a .line, put out digits + 5: parsing a string, then go to old-state + 6: putting out \ escape in a "d string. + 7: After putting out a .file, put out string. + 8: After putting out a .file string, flush until newline. + -1: output string in out_string and go to the state in old_state + -2: flush text until a '*' '/' is seen, then go to state old_state + */ + + static state; + static old_state; + static char *out_string; + static char out_buf[20]; + static add_newlines; + int ch; + + if(state==-1) { + ch= *out_string++; + if(*out_string==0) { + state=old_state; + old_state=3; + } + return ch; + } + if(state==-2) { + for(;;) { + do ch=(*get)(); + while(ch!=EOF && ch!='\n' && ch!='*'); + if(ch=='\n' || ch==EOF) + return ch; + ch=(*get)(); + if(ch==EOF || ch=='/') + break; + (*unget)(ch); + } + state=old_state; + return ' '; + } + if(state==4) { + ch=(*get)(); + if(ch==EOF || (ch>='0' && ch<='9')) + return ch; + else { + while(ch!=EOF && IS_WHITESPACE(ch)) + ch=(*get)(); + if(ch=='"') { + (*unget)(ch); + out_string="; .file "; + old_state=7; + state= -1; + return *out_string++; + } else { + while(ch!=EOF && ch!='\n') + ch=(*get)(); + return ch; + } + } + } + if(state==5) { + ch=(*get)(); + if(ch=='"') { + state=old_state; + return '"'; + } else if(ch=='\\') { + state=6; + return ch; + } else if(ch==EOF) { + as_warn("End of file in string: inserted '\"'"); + state=old_state; + (*unget)('\n'); + return '"'; + } else { + return ch; + } + } + if(state==6) { + state=5; + ch=(*get)(); + switch(ch) { + /* This is neet. Turn "string + more string" into "string\n more string" + */ + case '\n': + (*unget)('n'); + add_newlines++; + return '\\'; + + case '"': + case '\\': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + break; + default: + as_warn("Unknown escape '\\%c' in string: Ignored",ch); + break; + + case EOF: + as_warn("End of file in string: '\"' inserted"); + return '"'; + } + return ch; + } + + if(state==7) { + ch=(*get)(); + state=5; + old_state=8; + return ch; + } + + if(state==8) { + do ch= (*get)(); + while(ch!='\n'); + state=0; + return ch; + } + + flushchar: + ch=(*get)(); + switch(ch) { + case ' ': + case '\t': + do ch=(*get)(); + while(ch!=EOF && IS_WHITESPACE(ch)); + if(ch==EOF) + return ch; + if(IS_COMMENT(ch) || (state==0 && IS_LINE_COMMENT(ch)) || ch=='/' || IS_LINE_SEPERATOR(ch)) { + (*unget)(ch); + goto flushchar; + } + (*unget)(ch); + if(state==0 || state==2) { + state++; + return ' '; + } else goto flushchar; + + case '/': + ch=(*get)(); + if(ch=='*') { + for(;;) { + do { + ch=(*get)(); + if(ch=='\n') + add_newlines++; + } while(ch!=EOF && ch!='*'); + ch=(*get)(); + if(ch==EOF || ch=='/') + break; + (*unget)(ch); + } + if(ch==EOF) + as_warn("End of file in '/' '*' string: */ inserted"); + + (*unget)(' '); + goto flushchar; + } else { + if(IS_COMMENT('/') || (state==0 && IS_LINE_COMMENT('/'))) { + (*unget)(ch); + ch='/'; + goto deal_misc; + } + if(ch!=EOF) + (*unget)(ch); + return '/'; + } + break; + + case '"': + old_state=state; + state=5; + return '"'; + break; + + case '\'': + ch=(*get)(); + if(ch==EOF) { + as_warn("End-of-file after a ': \000 inserted"); + ch=0; + } + sprintf(out_buf,"(%d)",ch&0xff); + old_state=state; + state= -1; + out_string=out_buf; + return *out_string++; + + case ':': + if(state!=3) + state=0; + return ch; + + case '\n': + if(add_newlines) { + --add_newlines; + (*unget)(ch); + } + case ';': + state=0; + return ch; + + default: + deal_misc: + if(state==0 && IS_LINE_COMMENT(ch)) { + do ch=(*get)(); + while(ch!=EOF && IS_WHITESPACE(ch)); + if(ch==EOF) { + as_warn("EOF in comment: Newline inserted"); + return '\n'; + } + if(ch<'0' || ch>'9') { + while(ch!=EOF && ch!='\n') + ch=(*get)(); + if(ch==EOF) + as_warn("EOF in Comment: Newline inserted"); + state=0; + return '\n'; + } + (*unget)(ch); + old_state=4; + state= -1; + out_string=".line "; + return *out_string++; + + } else if(IS_COMMENT(ch)) { + do ch=(*get)(); + while(ch!=EOF && ch!='\n'); + if(ch==EOF) + as_warn("EOF in comment: Newline inserted"); + state=0; + return '\n'; + + } else if(state==0) { + state=2; + return ch; + } else if(state==1) { + state=2; + return ch; + } else { + return ch; + + } + case EOF: + if(state==0) + return ch; + as_warn("End-of-File not at end of a line"); + } + return -1; +} + +#ifdef TEST + +char comment_chars[] = "|"; +char line_comment_chars[] = "#"; + +main() +{ + int ch; + + app_begin(); + while((ch=do_scrub_next_char(stdin))!=EOF) + putc(ch,stdout); +} + +as_warn(str) +char *str; +{ + fputs(str,stderr); + putc('\n',stderr); +} +#endif diff --git a/gnu/usr.bin/as/append.c b/gnu/usr.bin/as/append.c new file mode 100644 index 0000000..d51a27f --- /dev/null +++ b/gnu/usr.bin/as/append.c @@ -0,0 +1,37 @@ +/* Append a string ontp another string + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* JF: This is silly. Why not stuff this in some other file? */ +#ifdef USG +#define bcopy(from,to,n) memcpy(to,from,n) +#endif + +void +append (charPP, fromP, length) +char **charPP; +char *fromP; +unsigned long length; +{ + if (length) { /* Don't trust bcopy() of 0 chars. */ + bcopy (fromP, * charPP,(int) length); + *charPP += length; + } +} + +/* end: append.c */ diff --git a/gnu/usr.bin/as/as.1 b/gnu/usr.bin/as/as.1 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/gnu/usr.bin/as/as.1 diff --git a/gnu/usr.bin/as/as.1aout b/gnu/usr.bin/as/as.1aout new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/gnu/usr.bin/as/as.1aout diff --git a/gnu/usr.bin/as/as.c b/gnu/usr.bin/as/as.c new file mode 100644 index 0000000..db85525 --- /dev/null +++ b/gnu/usr.bin/as/as.c @@ -0,0 +1,324 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + */ + +#ifndef lint +static char sccsid[] = "@(#)as.c 6.3 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* as.c - GAS main program. + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Main program for AS; a 32-bit assembler of GNU. + * Understands command arguments. + * Has a few routines that don't fit in other modules because they + * are shared. + * + * + * bugs + * + * : initialisers + * Since no-one else says they will support them in future: I + * don't support them now. + * + */ + +#ifdef _POSIX_SOURCE +#include <sys/types.h> /* For pid_t in signal.h */ +#endif +#include <signal.h> + +#define COMMON +#include "as.h" +#include "struc-symbol.h" +#include "write.h" + /* Warning! This may have some slightly strange side effects + if you try to compile two or more assemblers in the same + directory! + */ + +#ifndef SIGTY +#define SIGTY int +#endif + +SIGTY got_sig(); + +#ifdef DONTDEF +static char * gdb_symbol_file_name; +long int gdb_begin(); +#endif + +char *myname; /* argv[0] */ +extern char version_string[]; + +main(argc,argv) +int argc; +char **argv; +{ + int work_argc; /* variable copy of argc */ + char **work_argv; /* variable copy of argv */ + char *arg; /* an arg to program */ + char a; /* an arg flag (after -) */ + static const int sig[] = { SIGHUP, SIGINT, SIGPIPE, SIGTERM, 0}; + + extern int bad_error; /* Did we hit a bad error ? */ + + char *stralloc(); /* Make a (safe) copy of a string. */ + void symbol_begin(); + void read_begin(); + void write_object_file(); + + for(a=0;sig[a]!=0;a++) + if(signal(sig[a], SIG_IGN) != SIG_IGN) + signal(sig[a], got_sig); + + myname=argv[0]; + bzero (flagseen, sizeof(flagseen)); /* aint seen nothing yet */ + out_file_name = "a.out"; /* default .o file */ + symbol_begin(); /* symbols.c */ + subsegs_begin(); /* subsegs.c */ + read_begin(); /* read.c */ + md_begin(); /* MACHINE.c */ + input_scrub_begin(); /* input_scrub.c */ +#ifdef DONTDEF + gdb_symbol_file_name = 0; +#endif + /* + * Parse arguments, but we are only interested in flags. + * When we find a flag, we process it then make it's argv[] NULL. + * This helps any future argv[] scanners avoid what we processed. + * Since it is easy to do here we interpret the special arg "-" + * to mean "use stdin" and we set that argv[] pointing to "". + * After we have munged argv[], the only things left are source file + * name(s) and ""(s) denoting stdin. These file names are used + * (perhaps more than once) later. + */ + work_argc = argc-1; /* don't count argv[0] */ + work_argv = argv+1; /* skip argv[0] */ + for (;work_argc--;work_argv++) { + arg = * work_argv; /* work_argv points to this argument */ + + if (*arg!='-') /* Filename. We need it later. */ + continue; /* Keep scanning args looking for flags. */ + if (arg[1] == '-' && arg[2] == 0) { + /* "--" as an argument means read STDIN */ + /* on this scan, we don't want to think about filenames */ + * work_argv = ""; /* Code that means 'use stdin'. */ + continue; + } + /* This better be a switch. */ + arg ++; /* -> letter. */ + + while (a = * arg) {/* scan all the 1-char flags */ + arg ++; /* arg -> after letter. */ + a &= 0x7F; /* ascii only please */ + if (flagseen[a]) + as_warn("%s: Flag option -%c has already been seen!",myname,a); + flagseen[a] = TRUE; + switch (a) { + case 'f': + break; /* -f means fast - no need for "app" preprocessor. */ + + case 'D': + /* DEBUG is implemented: it debugs different */ + /* things to other people's assemblers. */ + break; + +#ifdef DONTDEF + case 'G': /* GNU AS switch: include gdbsyms. */ + if (*arg) /* Rest of argument is file-name. */ + gdb_symbol_file_name = stralloc (arg); + else if (work_argc) { /* Next argument is file-name. */ + work_argc --; + * work_argv = NULL; /* Not a source file-name. */ + gdb_symbol_file_name = * ++ work_argv; + } else + as_warn( "%s: I expected a filename after -G",myname); + arg = ""; /* Finished with this arg. */ + break; +#endif + +#ifndef WORKING_DOT_WORD + case 'k': + break; +#endif + + case 'L': /* -L means keep L* symbols */ + break; + + case 'o': + if (*arg) /* Rest of argument is object file-name. */ + out_file_name = stralloc (arg); + else if (work_argc) { /* Want next arg for a file-name. */ + * work_argv = NULL; /* This is not a file-name. */ + work_argc--; + out_file_name = * ++ work_argv; + } else + as_warn("%s: I expected a filename after -o. \"%s\" assumed.",myname,out_file_name); + arg = ""; /* Finished with this arg. */ + break; + + case 'R': + /* -R means put data into text segment */ + break; + + case 'v': +#ifdef VMS + { + extern char *compiler_version_string; + compiler_version_string = arg; + } +#else /* not VMS */ + fprintf(stderr,version_string); + if(*arg && strcmp(arg,"ersion")) + as_warn("Unknown -v option ignored"); +#endif + while(*arg) arg++; /* Skip the rest */ + break; + + case 'W': + /* -W means don't warn about things */ + break; + + case 'g': + /* + * -g asks gas to produce gdb/dbx line number + * and file name stabs so that an assembly + * file can be handled by a source debugger. + */ + break; + + default: + --arg; + if(md_parse_option(&arg,&work_argc,&work_argv)==0) + as_warn("%s: I don't understand '%c' flag!",myname,a); + if(arg && *arg) + arg++; + break; + } + } + /* + * We have just processed a "-..." arg, which was not a + * file-name. Smash it so the + * things that look for filenames won't ever see it. + * + * Whatever work_argv points to, it has already been used + * as part of a flag, so DON'T re-use it as a filename. + */ + *work_argv = NULL; /* NULL means 'not a file-name' */ + } +#ifdef DONTDEF + if (gdb_begin(gdb_symbol_file_name) == 0) + flagseen ['G'] = 0; /* Don't do any gdbsym stuff. */ +#endif + /* Here with flags set up in flagseen[]. */ + perform_an_assembly_pass(argc,argv); /* Assemble it. */ + if (seen_at_least_1_file() && !bad_error) + write_object_file();/* relax() addresses then emit object file */ + input_scrub_end(); + md_end(); /* MACHINE.c */ +#ifndef VMS + exit(bad_error); /* WIN */ +#else /* VMS */ + exit(!bad_error); /* WIN */ +#endif /* VMS */ +} + + +/* perform_an_assembly_pass() + * + * Here to attempt 1 pass over each input file. + * We scan argv[*] looking for filenames or exactly "" which is + * shorthand for stdin. Any argv that is NULL is not a file-name. + * We set need_pass_2 TRUE if, after this, we still have unresolved + * expressions of the form (unknown value)+-(unknown value). + * + * Note the un*x semantics: there is only 1 logical input file, but it + * may be a catenation of many 'physical' input files. + */ +perform_an_assembly_pass (argc, argv) +int argc; +char ** argv; +{ + char * buffer; /* Where each bufferful of lines will start. */ + void read_a_source_file(); + int saw_a_file = 0; + + text_fix_root = NULL; + data_fix_root = NULL; + need_pass_2 = FALSE; + + argv++; /* skip argv[0] */ + argc--; /* skip argv[0] */ + while (argc--) { + if (*argv) { /* Is it a file-name argument? */ + /* argv -> "" if stdin desired, else -> filename */ + if (buffer = input_scrub_new_file (*argv) ) { + saw_a_file++; + read_a_source_file(buffer); + } + } + argv++; /* completed that argv */ + } + if(!saw_a_file) + if(buffer = input_scrub_new_file("") ) + read_a_source_file(buffer); +} + +/* + * stralloc() + * + * Allocate memory for a new copy of a string. Copy the string. + * Return the address of the new string. Die if there is any error. + */ + +char * +stralloc (str) +char * str; +{ + register char * retval; + register long int len; + + len = strlen (str) + 1; + retval = xmalloc (len); + (void)strcpy (retval, str); + return (retval); +} + +lose() +{ + as_fatal( "%s: 2nd pass not implemented - get your code from random(3)",myname ); +} + +SIGTY +got_sig(sig) +int sig; +{ + static here_before = 0; + + as_bad("Interrupted by signal %d",sig); + if(here_before++) + exit(1); +} + +/* end: as.c */ diff --git a/gnu/usr.bin/as/as.h b/gnu/usr.bin/as/as.h new file mode 100644 index 0000000..8de4052 --- /dev/null +++ b/gnu/usr.bin/as/as.h @@ -0,0 +1,292 @@ +/* as.h - global header file + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef asH +#define asH /* Don't declare things twice. */ + +#if !defined(__STDC__) && !defined(const) +#define const /* ignore */ +#endif + +#ifdef USG +#define index strchr +#define bzero(s,n) memset((s),0,(n)) +#define bcopy(from,to,n) memcpy((to),(from),(n)) +#define setbuffer(a,b,c) +#endif + +/* + * CAPITALISED names are #defined. + * "lowercaseH" is #defined if "lowercase.h" has been #include-d. + * "lowercaseT" is a typedef of "lowercase" objects. + * "lowercaseP" is type "pointer to object of type 'lowercase'". + * "lowercaseS" is typedef struct ... lowercaseS. + * + * #define SUSPECT when debugging. + * #define DUMP to include data-structure dumpers. + * #define COMMON as "extern" for all modules except one, where you #define + * COMMON as "". + * If TEST is #defined, then we are testing a module: #define COMMON as "". + */ + + + +/* These #defines are for parameters of entire assembler. */ + +/* #define SUSPECT JF remove for speed testing */ +/* #define DUMP */ +#define NDEBUG /* JF disable asserts */ +/* These #includes are for type definitions etc. */ + +/* #include "style.h" */ +#include <stdio.h> +#include <assert.h> +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free xfree + +/* These defines are potentially useful */ +#define FALSE (0) +#define TRUE (!FALSE) +#define ASSERT assert +#define BAD_CASE(value) \ +{ \ + as_fatal ("Case value %d unexpected at line %d of file \"%s\"\n", \ + value, __LINE__, __FILE__); \ +} + + + + +/* These are assembler-wide concepts */ + + +#ifndef COMMON +#ifdef TEST +#define COMMON /* declare our COMMONs storage here. */ +#else +#define COMMON extern /* our commons live elswhere */ +#endif +#endif + /* COMMON now defined */ + +#ifdef SUSPECT +#define register /* no registers: helps debugging */ +#define know(p) ASSERT(p) /* know() is less ugly than #ifdef SUSPECT/ */ + /* assert()/#endif. */ +#else +#define know(p) /* know() checks are no-op.ed */ +#endif /* #ifdef SUSPECT */ + + +char *xmalloc(); /* keep C compilers happy */ +char *xrealloc(); /* " */ +void free(); /* " */ +#define xfree free + +/* input_scrub.c */ + +/* + * Supplies sanitised buffers to read.c. + * Also understands printing line-number part of error messages. + */ + + /* Line number things. */ +int seen_at_least_1_file(); +void bump_line_counters(); +void new_logical_line(); +void as_where(); +void as_perror(); +void as_howmuch(); + /* Sanitising things. */ +void input_scrub_begin(); +void input_scrub_end(); +char *input_scrub_new_file(); +char *input_scrub_next_buffer(); + +/* subsegs.c Sub-segments. Also, segment(=expression type)s.*/ + +/* + * This table describes the use of segments as EXPRESSION types. + * + * X_seg X_add_symbol X_subtract_symbol X_add_number + * SEG_NONE no (legal) expression + * SEG_PASS1 no (defined) " + * SEG_BIG * > 32 bits const. + * SEG_ABSOLUTE 0 + * SEG_DATA * 0 + * SEG_TEXT * 0 + * SEG_BSS * 0 + * SEG_UNKNOWN * 0 + * SEG_DIFFERENCE 0 * 0 + * + * The blank fields MUST be 0, and are nugatory. + * The '0' fields MAY be 0. The '*' fields MAY NOT be 0. + * + * SEG_BIG: X_add_number is < 0 if the result is in + * generic_floating_point_number. The value is -'c' where c is the + * character that introduced the constant. e.g. "0f6.9" will have -'f' + * as a X_add_number value. + * X_add_number > 0 is a count of how many littlenums it took to + * represent a bignum. + * SEG_DIFFERENCE: + * If segments of both symbols are known, they are the same segment. + * X_add_symbol != X_sub_symbol (then we just cancel them, => SEG_ABSOLUTE). + */ + +typedef enum +{ + SEG_ABSOLUTE, + SEG_TEXT, + SEG_DATA, + SEG_BSS, + SEG_UNKNOWN, + SEG_NONE, /* Mythical Segment: NO expression seen. */ + SEG_PASS1, /* Mythical Segment: Need another pass. */ + SEG_GOOF, /* Only happens if AS has a logic error. */ + /* Invented so we don't crash printing */ + /* error message involving weird segment. */ + SEG_BIG, /* Bigger than 32 bits constant. */ + SEG_DIFFERENCE /* Mythical Segment: absolute difference. */ +} segT; +#define SEG_MAXIMUM_ORDINAL (SEG_DIFFERENCE) + +typedef unsigned char subsegT; + +COMMON subsegT now_subseg; + /* What subseg we are accreting now? */ + + +COMMON segT now_seg; + /* Segment our instructions emit to. */ + /* Only OK values are SEG_TEXT or SEG_DATA. */ + + +extern char *const seg_name[]; +extern const int seg_N_TYPE[]; +extern const segT N_TYPE_seg[]; +void subsegs_begin(); +void subseg_change(); +void subseg_new(); + +/* relax() */ + +typedef enum +{ + rs_fill, /* Variable chars to be repeated fr_offset */ + /* times. Fr_symbol unused. */ + /* Used with fr_offset == 0 for a constant */ + /* length frag. */ + + rs_align, /* Align: Fr_offset: power of 2. */ + /* 1 variable char: fill character. */ + rs_org, /* Org: Fr_offset, fr_symbol: address. */ + /* 1 variable char: fill character. */ + + rs_machine_dependent, +#ifndef WORKING_DOT_WORD + rs_broken_word, /* JF: gunpoint */ +#endif +} +relax_stateT; + +/* typedef unsigned char relax_substateT; */ +/* JF this is more likely to leave the end of a struct frag on an align + boundry. Be very careful with this. */ +typedef unsigned long int relax_substateT; + +typedef unsigned long int relax_addressT;/* Enough bits for address. */ + /* Still an integer type. */ + + +/* frags.c */ + +/* + * A code fragment (frag) is some known number of chars, followed by some + * unknown number of chars. Typically the unknown number of chars is an + * instruction address whose size is yet unknown. We always know the greatest + * possible size the unknown number of chars may become, and reserve that + * much room at the end of the frag. + * Once created, frags do not change address during assembly. + * We chain the frags in (a) forward-linked list(s). The object-file address + * of the 1st char of a frag is generally not known until after relax(). + * Many things at assembly time describe an address by {object-file-address + * of a particular frag}+offset. + + BUG: it may be smarter to have a single pointer off to various different +notes for different frag kinds. See how code pans out. + + + */ +struct frag /* a code fragment */ +{ + long unsigned int fr_address; /* Object file address. */ + struct frag *fr_next; /* Chain forward; ascending address order. */ + /* Rooted in frch_root. */ + + long int fr_fix; /* (Fixed) number of chars we know we have. */ + /* May be 0. */ + long int fr_var; /* (Variable) number of chars after above. */ + /* May be 0. */ + struct symbol *fr_symbol; /* For variable-length tail. */ + long int fr_offset; /* For variable-length tail. */ + char *fr_opcode; /*->opcode low addr byte,for relax()ation*/ + relax_stateT fr_type; /* What state is my tail in? */ + relax_substateT fr_subtype; + /* These are needed only on the NS32K machines */ + char fr_pcrel_adjust; + char fr_bsr; + char fr_literal [1]; /* Chars begin here. */ + /* One day we will compile fr_literal[0]. */ +}; +#define SIZEOF_STRUCT_FRAG \ + ((int)zero_address_frag.fr_literal-(int)&zero_address_frag) + /* We want to say fr_literal[0] above. */ + +typedef struct frag fragS; + +COMMON fragS * frag_now; /* -> current frag we are building. */ + /* This frag is incomplete. */ + /* It is, however, included in frchain_now. */ + /* Frag_now->fr_fix is bogus. Use: */ +/* Virtual frag_now->fr_fix==obstack_next_free(&frags)-frag_now->fr_literal.*/ + +COMMON fragS zero_address_frag; /* For foreign-segment symbol fixups. */ +COMMON fragS bss_address_frag; /* For local common (N_BSS segment) fixups. */ + +void frag_new(); +char * frag_more(); +char * frag_var(); +void frag_wane(); +void frag_align(); + + +/* main program "as.c" (command arguments etc) */ + +COMMON char +flagseen[128]; /* ['x'] TRUE if "-x" seen. */ + +COMMON char * +out_file_name; /* name of emitted object file */ + +COMMON int need_pass_2; /* TRUE if we need a second pass. */ + + +#endif /* #ifdef asH */ + +/* end: as.h */ diff --git a/gnu/usr.bin/as/atof-generic.c b/gnu/usr.bin/as/atof-generic.c new file mode 100644 index 0000000..4975410 --- /dev/null +++ b/gnu/usr.bin/as/atof-generic.c @@ -0,0 +1,526 @@ +/* atof_generic.c - turn a string of digits into a Flonum + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <ctype.h> +#include "flonum.h" +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#ifdef sparc +#include <alloca.h> +#endif +#endif + +#ifdef USG +#define bzero(s,n) memset(s,0,n) +#define index strchr +#endif + +#define FALSE (0) +#define TRUE (1) + +char *index(); + +/***********************************************************************\ +* * +* Given a string of decimal digits , with optional decimal * +* mark and optional decimal exponent (place value) of the * +* lowest_order decimal digit: produce a floating point * +* number. The number is 'generic' floating point: our * +* caller will encode it for a specific machine architecture. * +* * +* Assumptions * +* uses base (radix) 2 * +* this machine uses 2's complement binary integers * +* target flonums use " " " " * +* target flonums exponents fit in a long int * +* * +\***********************************************************************/ + +/* + + Syntax: + +<flonum> ::= <optional-sign> <decimal-number> <optional-exponent> +<optional-sign> ::= '+' | '-' | {empty} +<decimal-number> ::= <integer> + | <integer> <radix-character> + | <integer> <radix-character> <integer> + | <radix-character> <integer> +<optional-exponent> ::= {empty} | <exponent-character> <optional-sign> <integer> +<integer> ::= <digit> | <digit> <integer> +<digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' +<exponent-character> ::= {one character from "string_of_decimal_exponent_marks"} +<radix-character> ::= {one character from "string_of_decimal_marks"} + +*/ + +int /* 0 if OK */ + +atof_generic ( + address_of_string_pointer, /* return pointer to just AFTER number we read. */ + string_of_decimal_marks, /* At most one per number. */ + string_of_decimal_exponent_marks, + address_of_generic_floating_point_number) + + char * * address_of_string_pointer; + const char * string_of_decimal_marks; + const char * string_of_decimal_exponent_marks; + FLONUM_TYPE * address_of_generic_floating_point_number; + +{ + + int return_value; /* 0 means OK. */ + char * first_digit; + /* char * last_digit; JF unused */ + int number_of_digits_before_decimal; + int number_of_digits_after_decimal; + long int decimal_exponent; + int number_of_digits_available; + char digits_sign_char; + + { + /* + * Scan the input string, abstracting (1)digits (2)decimal mark (3) exponent. + * It would be simpler to modify the string, but we don't; just to be nice + * to caller. + * We need to know how many digits we have, so we can allocate space for + * the digits' value. + */ + + char * p; + char c; + int seen_significant_digit; + + first_digit = * address_of_string_pointer; + c= *first_digit; + if (c=='-' || c=='+') + { + digits_sign_char = c; + first_digit ++; + } + else + digits_sign_char = '+'; + + if( (first_digit[0]=='n' || first_digit[0]=='N') + && (first_digit[1]=='a' || first_digit[1]=='A') + && (first_digit[2]=='n' || first_digit[2]=='N')) { + address_of_generic_floating_point_number->sign=0; + address_of_generic_floating_point_number->exponent=0; + address_of_generic_floating_point_number->leader=address_of_generic_floating_point_number->low; + (*address_of_string_pointer)=first_digit+3; + return 0; + } + if( (first_digit[0]=='i' || first_digit[0]=='I') + && (first_digit[1]=='n' || first_digit[1]=='N') + && (first_digit[2]=='f' || first_digit[2]=='F')) { + address_of_generic_floating_point_number->sign= digits_sign_char=='+' ? 'P' : 'N'; + address_of_generic_floating_point_number->exponent=0; + address_of_generic_floating_point_number->leader=address_of_generic_floating_point_number->low; + if( (first_digit[3]=='i' || first_digit[3]=='I') + && (first_digit[4]=='n' || first_digit[4]=='N') + && (first_digit[5]=='i' || first_digit[5]=='I') + && (first_digit[6]=='t' || first_digit[6]=='T') + && (first_digit[7]=='y' || first_digit[7]=='Y')) + (*address_of_string_pointer)=first_digit+8; + else + (*address_of_string_pointer)=first_digit+3; + return 0; + } + + number_of_digits_before_decimal = 0; + number_of_digits_after_decimal = 0; + decimal_exponent = 0; + seen_significant_digit = FALSE; + for (p = first_digit; + (c = * p) + && (!c || ! index (string_of_decimal_marks, c) ) + && (!c || ! index (string_of_decimal_exponent_marks, c) ); + p ++) + { + if (isdigit(c)) + { + if (seen_significant_digit || c > '0') + { + number_of_digits_before_decimal ++; + seen_significant_digit = TRUE; + } + else + { + first_digit++; + } + } + else + { + break; /* p -> char after pre-decimal digits. */ + } + } /* For each digit before decimal mark. */ + if (c && index (string_of_decimal_marks, c)) + { + for (p ++; + (c = * p) + && (!c || ! index (string_of_decimal_exponent_marks, c) ); + p ++) + { + if (isdigit(c)) + { + number_of_digits_after_decimal ++; /* This may be retracted below. */ + if (/* seen_significant_digit || */ c > '0') + { + seen_significant_digit = TRUE; + } + } + else + { + if ( ! seen_significant_digit) + { + number_of_digits_after_decimal = 0; + } + break; + } + } /* For each digit after decimal mark. */ + } + while(number_of_digits_after_decimal && first_digit[number_of_digits_before_decimal+number_of_digits_after_decimal]=='0') + --number_of_digits_after_decimal; +/* last_digit = p; JF unused */ + + if (c && index (string_of_decimal_exponent_marks, c) ) + { + char digits_exponent_sign_char; + + c = * ++ p; + if (c && index ("+-",c)) + { + digits_exponent_sign_char = c; + c = * ++ p; + } + else + { + digits_exponent_sign_char = '+'; + } + for (; + (c); + c = * ++ p) + { + if (isdigit(c)) + { + decimal_exponent = decimal_exponent * 10 + c - '0'; + /* + * BUG! If we overflow here, we lose! + */ + } + else + { + break; + } + } + if (digits_exponent_sign_char == '-') + { + decimal_exponent = - decimal_exponent; + } + } + * address_of_string_pointer = p; + } + + number_of_digits_available = + number_of_digits_before_decimal + + number_of_digits_after_decimal; + return_value = 0; + if (number_of_digits_available == 0) + { + address_of_generic_floating_point_number -> exponent = 0; /* Not strictly necessary */ + address_of_generic_floating_point_number -> leader + = -1 + address_of_generic_floating_point_number -> low; + address_of_generic_floating_point_number -> sign = digits_sign_char; + /* We have just concocted (+/-)0.0E0 */ + } + else + { + LITTLENUM_TYPE * digits_binary_low; + int precision; + int maximum_useful_digits; + int number_of_digits_to_use; + int more_than_enough_bits_for_digits; + int more_than_enough_littlenums_for_digits; + int size_of_digits_in_littlenums; + int size_of_digits_in_chars; + FLONUM_TYPE power_of_10_flonum; + FLONUM_TYPE digits_flonum; + + + precision = (address_of_generic_floating_point_number -> high + - address_of_generic_floating_point_number -> low + + 1 + ); /* Number of destination littlenums. */ + /* Includes guard bits (two littlenums worth) */ + maximum_useful_digits = ( ((double) (precision - 2)) + * ((double) (LITTLENUM_NUMBER_OF_BITS)) + / (LOG_TO_BASE_2_OF_10) + ) + + 2; /* 2 :: guard digits. */ + if (number_of_digits_available > maximum_useful_digits) + { + number_of_digits_to_use = maximum_useful_digits; + } + else + { + number_of_digits_to_use = number_of_digits_available; + } + decimal_exponent += number_of_digits_before_decimal - number_of_digits_to_use; + + more_than_enough_bits_for_digits + = ((((double)number_of_digits_to_use) * LOG_TO_BASE_2_OF_10) + 1); + more_than_enough_littlenums_for_digits + = ( more_than_enough_bits_for_digits + / LITTLENUM_NUMBER_OF_BITS + ) + + 2; + + /* + * Compute (digits) part. In "12.34E56" this is the "1234" part. + * Arithmetic is exact here. If no digits are supplied then + * this part is a 0 valued binary integer. + * Allocate room to build up the binary number as littlenums. + * We want this memory to disappear when we leave this function. + * Assume no alignment problems => (room for n objects) == + * n * (room for 1 object). + */ + + size_of_digits_in_littlenums = more_than_enough_littlenums_for_digits; + size_of_digits_in_chars = size_of_digits_in_littlenums + * sizeof( LITTLENUM_TYPE ); + digits_binary_low = (LITTLENUM_TYPE *) + alloca (size_of_digits_in_chars); + bzero ((char *)digits_binary_low, size_of_digits_in_chars); + + /* Digits_binary_low[] is allocated and zeroed. */ + + { + /* + * Parse the decimal digits as if * digits_low was in the units position. + * Emit a binary number into digits_binary_low[]. + * + * Use a large-precision version of: + * (((1st-digit) * 10 + 2nd-digit) * 10 + 3rd-digit ...) * 10 + last-digit + */ + + char * p; + char c; + int count; /* Number of useful digits left to scan. */ + + for (p = first_digit, count = number_of_digits_to_use; + count; + p ++, -- count) + { + c = * p; + if (isdigit(c)) + { + /* + * Multiply by 10. Assume can never overflow. + * Add this digit to digits_binary_low[]. + */ + + long int carry; + LITTLENUM_TYPE * littlenum_pointer; + LITTLENUM_TYPE * littlenum_limit; + + littlenum_limit + = digits_binary_low + + more_than_enough_littlenums_for_digits + - 1; + carry = c - '0'; /* char -> binary */ + for (littlenum_pointer = digits_binary_low; + littlenum_pointer <= littlenum_limit; + littlenum_pointer ++) + { + long int work; + + work = carry + 10 * (long)(*littlenum_pointer); + * littlenum_pointer = work & LITTLENUM_MASK; + carry = work >> LITTLENUM_NUMBER_OF_BITS; + } + if (carry != 0) + { + /* + * We have a GROSS internal error. + * This should never happen. + */ + abort(); /* RMS prefers abort() to any message. */ + } + } + else + { + ++ count; /* '.' doesn't alter digits used count. */ + } /* if valid digit */ + } /* for each digit */ + } + + /* + * Digits_binary_low[] properly encodes the value of the digits. + * Forget about any high-order littlenums that are 0. + */ + while (digits_binary_low [size_of_digits_in_littlenums - 1] == 0 + && size_of_digits_in_littlenums >= 2) + size_of_digits_in_littlenums --; + + digits_flonum . low = digits_binary_low; + digits_flonum . high = digits_binary_low + size_of_digits_in_littlenums - 1; + digits_flonum . leader = digits_flonum . high; + digits_flonum . exponent = 0; + /* + * The value of digits_flonum . sign should not be important. + * We have already decided the output's sign. + * We trust that the sign won't influence the other parts of the number! + * So we give it a value for these reasons: + * (1) courtesy to humans reading/debugging + * these numbers so they don't get excited about strange values + * (2) in future there may be more meaning attached to sign, + * and what was + * harmless noise may become disruptive, ill-conditioned (or worse) + * input. + */ + digits_flonum . sign = '+'; + + { + /* + * Compute the mantssa (& exponent) of the power of 10. + * If sucessful, then multiply the power of 10 by the digits + * giving return_binary_mantissa and return_binary_exponent. + */ + + LITTLENUM_TYPE *power_binary_low; + int decimal_exponent_is_negative; + /* This refers to the "-56" in "12.34E-56". */ + /* FALSE: decimal_exponent is positive (or 0) */ + /* TRUE: decimal_exponent is negative */ + FLONUM_TYPE temporary_flonum; + LITTLENUM_TYPE *temporary_binary_low; + int size_of_power_in_littlenums; + int size_of_power_in_chars; + + size_of_power_in_littlenums = precision; +/* Precision has a built-in fudge factor so we get a few guard bits. */ + + + decimal_exponent_is_negative = decimal_exponent < 0; + if (decimal_exponent_is_negative) + { + decimal_exponent = - decimal_exponent; + } + /* From now on: the decimal exponent is > 0. Its sign is seperate. */ + + size_of_power_in_chars + = size_of_power_in_littlenums + * sizeof( LITTLENUM_TYPE ) + 2; + power_binary_low = (LITTLENUM_TYPE *) alloca ( size_of_power_in_chars ); + temporary_binary_low = (LITTLENUM_TYPE *) alloca ( size_of_power_in_chars ); + bzero ((char *)power_binary_low, size_of_power_in_chars); + * power_binary_low = 1; + power_of_10_flonum . exponent = 0; + power_of_10_flonum . low = power_binary_low; + power_of_10_flonum . leader = power_binary_low; + power_of_10_flonum . high = power_binary_low + size_of_power_in_littlenums - 1; + power_of_10_flonum . sign = '+'; + temporary_flonum . low = temporary_binary_low; + temporary_flonum . high = temporary_binary_low + size_of_power_in_littlenums - 1; + /* + * (power) == 1. + * Space for temporary_flonum allocated. + */ + + /* + * ... + * + * WHILE more bits + * DO find next bit (with place value) + * multiply into power mantissa + * OD + */ + { + int place_number_limit; + /* Any 10^(2^n) whose "n" exceeds this */ + /* value will fall off the end of */ + /* flonum_XXXX_powers_of_ten[]. */ + int place_number; + const FLONUM_TYPE * multiplicand; /* -> 10^(2^n) */ + + place_number_limit = table_size_of_flonum_powers_of_ten; + multiplicand + = ( decimal_exponent_is_negative + ? flonum_negative_powers_of_ten + : flonum_positive_powers_of_ten); + for (place_number = 1; /* Place value of this bit of exponent. */ + decimal_exponent; /* Quit when no more 1 bits in exponent. */ + decimal_exponent >>= 1 + , place_number ++) + { + if (decimal_exponent & 1) + { + if (place_number > place_number_limit) + { + /* + * The decimal exponent has a magnitude so great that + * our tables can't help us fragment it. Although this + * routine is in error because it can't imagine a + * number that big, signal an error as if it is the + * user's fault for presenting such a big number. + */ + return_value = ERROR_EXPONENT_OVERFLOW; + /* + * quit out of loop gracefully + */ + decimal_exponent = 0; + } + else + { +#ifdef TRACE +printf("before multiply, place_number = %d., power_of_10_flonum:\n", place_number); +flonum_print( & power_of_10_flonum ); +(void)putchar('\n'); +#endif + flonum_multip (multiplicand + place_number, & power_of_10_flonum, & temporary_flonum); + flonum_copy (& temporary_flonum, & power_of_10_flonum); + } /* If this bit of decimal_exponent was computable.*/ + } /* If this bit of decimal_exponent was set. */ + } /* For each bit of binary representation of exponent */ +#ifdef TRACE +printf( " after computing power_of_10_flonum: " ); +flonum_print( & power_of_10_flonum ); +(void)putchar('\n'); +#endif + } + + } + + /* + * power_of_10_flonum is power of ten in binary (mantissa) , (exponent). + * It may be the number 1, in which case we don't NEED to multiply. + * + * Multiply (decimal digits) by power_of_10_flonum. + */ + + flonum_multip (& power_of_10_flonum, & digits_flonum, address_of_generic_floating_point_number); + /* Assert sign of the number we made is '+'. */ + address_of_generic_floating_point_number -> sign = digits_sign_char; + + } /* If we had any significant digits. */ + return (return_value); +} /* atof_generic () */ + +/* end: atof_generic.c */ diff --git a/gnu/usr.bin/as/bignum-copy.c b/gnu/usr.bin/as/bignum-copy.c new file mode 100644 index 0000000..2640121 --- /dev/null +++ b/gnu/usr.bin/as/bignum-copy.c @@ -0,0 +1,75 @@ +/* bignum_copy.c - copy a bignum + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "bignum.h" + +#ifdef USG +#define bzero(s,n) memset(s,0,n) +#define bcopy(from,to,n) memcpy(to,from,n) +#endif + +/* + * bignum_copy () + * + * Copy a bignum from in to out. + * If the output is shorter than the input, copy lower-order littlenums. + * Return 0 or the number of significant littlenums dropped. + * Assumes littlenum arrays are densely packed: no unused chars between + * the littlenums. Uses bcopy() to move littlenums, and wants to + * know length (in chars) of the input bignum. + */ + +/* void */ +int +bignum_copy (in, in_length, out, out_length) + register LITTLENUM_TYPE * in; + register int in_length; /* in sizeof(littlenum)s */ + register LITTLENUM_TYPE * out; + register int out_length; /* in sizeof(littlenum)s */ +{ + register int significant_littlenums_dropped; + + if (out_length < in_length) + { + register LITTLENUM_TYPE * p; /* -> most significant (non-zero) input littlenum. */ + + bcopy ((char *)in, (char *)out, out_length << LITTLENUM_SHIFT); + for (p = in + in_length - 1; p >= in; -- p) + { + if (* p) break; + } + significant_littlenums_dropped = p - in - in_length + 1; + if (significant_littlenums_dropped < 0) + { + significant_littlenums_dropped = 0; + } + } + else + { + bcopy ((char *)in, (char *)out, in_length << LITTLENUM_SHIFT); + if (out_length > in_length) + { + bzero ((char *)(out + out_length), (out_length - in_length) << LITTLENUM_SHIFT); + } + significant_littlenums_dropped = 0; + } + return (significant_littlenums_dropped); +} + +/* end: bignum_copy.c */ diff --git a/gnu/usr.bin/as/bignum.h b/gnu/usr.bin/as/bignum.h new file mode 100644 index 0000000..dbc95a3 --- /dev/null +++ b/gnu/usr.bin/as/bignum.h @@ -0,0 +1,48 @@ +/* bignum.h-arbitrary precision integers + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/***********************************************************************\ +* * +* Arbitrary-precision integer arithmetic. * +* For speed, we work in groups of bits, even though this * +* complicates algorithms. * +* Each group of bits is called a 'littlenum'. * +* A bunch of littlenums representing a (possibly large) * +* integer is called a 'bignum'. * +* Bignums are >= 0. * +* * +\***********************************************************************/ + +#define LITTLENUM_NUMBER_OF_BITS (16) +#define LITTLENUM_RADIX (1 << LITTLENUM_NUMBER_OF_BITS) +#define LITTLENUM_MASK (0xFFFF) +#define LITTLENUM_SHIFT (1) +#define CHARS_PER_LITTLENUM (1 << LITTLENUM_SHIFT) +#ifndef BITS_PER_CHAR +#define BITS_PER_CHAR (8) +#endif + +typedef unsigned short int LITTLENUM_TYPE; + + +/* JF truncated this to get around a problem with GCC */ +#define LOG_TO_BASE_2_OF_10 (3.3219280948873623478703194294893901758651 ) + /* WARNING: I haven't checked that the trailing digits are correct! */ + +/* end: bignum.h */ diff --git a/gnu/usr.bin/as/config/Makefile.i386 b/gnu/usr.bin/as/config/Makefile.i386 new file mode 100644 index 0000000..945246b --- /dev/null +++ b/gnu/usr.bin/as/config/Makefile.i386 @@ -0,0 +1,4 @@ +# @(#)Makefile.i386 6.1 (Berkeley) 3/3/91 + +CFLAGS+= -DNON_BROKEN_WORDS +SRCS+= i386.c atof-ieee.c diff --git a/gnu/usr.bin/as/config/a.out.gnu.h b/gnu/usr.bin/as/config/a.out.gnu.h new file mode 100644 index 0000000..71b09a0 --- /dev/null +++ b/gnu/usr.bin/as/config/a.out.gnu.h @@ -0,0 +1,261 @@ +#ifndef __A_OUT_GNU_H__ +#define __A_OUT_GNU_H__ + +#define __GNU_EXEC_MACROS__ + +#ifndef __STRUCT_EXEC_OVERRIDE__ + +struct exec +{ + unsigned long a_info; /* Use macros N_MAGIC, etc for access */ + unsigned a_text; /* length of text, in bytes */ + unsigned a_data; /* length of data, in bytes */ + unsigned a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned a_syms; /* length of symbol table data in file, in bytes */ + unsigned a_entry; /* start address */ + unsigned a_trsize; /* length of relocation info for text, in bytes */ + unsigned a_drsize; /* length of relocation info for data, in bytes */ +}; + +#endif /* __STRUCT_EXEC_OVERRIDE__ */ + +/* these go in the N_MACHTYPE field */ +enum machine_type { +#if defined (M_OLDSUN2) + M__OLDSUN2 = M_OLDSUN2, +#else + M_OLDSUN2 = 0, +#endif +#if defined (M_68010) + M__68010 = M_68010, +#else + M_68010 = 1, +#endif +#if defined (M_68020) + M__68020 = M_68020, +#else + M_68020 = 2, +#endif +#if defined (M_SPARC) + M__SPARC = M_SPARC, +#else + M_SPARC = 3, +#endif + /* skip a bunch so we don't run into any of sun's numbers */ + M_386 = 100, +}; + +#if !defined (N_MAGIC) +#define N_MAGIC(exec) ((exec).a_info & 0xffff) +#endif +#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff)) +#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff) +#define N_SET_INFO(exec, magic, type, flags) \ + ((exec).a_info = ((magic) & 0xffff) \ + | (((int)(type) & 0xff) << 16) \ + | (((flags) & 0xff) << 24)) +#define N_SET_MAGIC(exec, magic) \ + ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff))) + +#define N_SET_MACHTYPE(exec, machtype) \ + ((exec).a_info = \ + ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16)) + +#define N_SET_FLAGS(exec, flags) \ + ((exec).a_info = \ + ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) + +/* Code indicating object file or impure executable. */ +#define OMAGIC 0407 +/* Code indicating pure executable. */ +#define NMAGIC 0410 +/* Code indicating demand-paged executable. */ +#define ZMAGIC 0413 + +#if !defined (N_BADMAG) +#define N_BADMAG(x) \ + (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) +#endif + +#define _N_BADMAG(x) \ + (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) + +#define _N_HDROFF(x) (1024 - sizeof (struct exec)) + +#if !defined (N_TXTOFF) +#define N_TXTOFF(x) \ + (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec)) +#endif + +#if !defined (N_DATOFF) +#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) +#endif + +#if !defined (N_TRELOFF) +#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data) +#endif + +#if !defined (N_DRELOFF) +#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize) +#endif + +#if !defined (N_SYMOFF) +#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize) +#endif + +#if !defined (N_STROFF) +#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms) +#endif + +/* Address of text segment in memory after it is loaded. */ +#if !defined (N_TXTADDR) +#define N_TXTADDR(x) 0 +#endif + +/* Address of data segment in memory after it is loaded. + Note that it is up to you to define SEGMENT_SIZE + on machines not listed here. */ +#if defined(vax) || defined(hp300) || defined(pyr) +#define SEGMENT_SIZE page_size +#endif +#ifdef sony +#define SEGMENT_SIZE 0x2000 +#endif /* Sony. */ +#ifdef is68k +#define SEGMENT_SIZE 0x20000 +#endif +#if defined(m68k) && defined(PORTAR) +#define PAGE_SIZE 0x400 +#define SEGMENT_SIZE PAGE_SIZE +#endif + +#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1)) + +#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) + +#ifndef N_DATADDR +#define N_DATADDR(x) \ + (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ + : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) +#endif + +/* Address of bss segment in memory after it is loaded. */ +#if !defined (N_BSSADDR) +#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) +#endif + +#if !defined (N_NLIST_DECLARED) +struct nlist { + union { + char *n_name; + struct nlist *n_next; + long n_strx; + } n_un; + unsigned char n_type; + char n_other; + short n_desc; + unsigned long n_value; +}; +#endif /* no N_NLIST_DECLARED. */ + +#if !defined (N_UNDF) +#define N_UNDF 0 +#endif +#if !defined (N_ABS) +#define N_ABS 2 +#endif +#if !defined (N_TEXT) +#define N_TEXT 4 +#endif +#if !defined (N_DATA) +#define N_DATA 6 +#endif +#if !defined (N_BSS) +#define N_BSS 8 +#endif +#if !defined (N_FN) +#define N_FN 15 +#endif + +#if !defined (N_EXT) +#define N_EXT 1 +#endif +#if !defined (N_TYPE) +#define N_TYPE 036 +#endif +#if !defined (N_STAB) +#define N_STAB 0340 +#endif + +/* The following type indicates the definition of a symbol as being + an indirect reference to another symbol. The other symbol + appears as an undefined reference, immediately following this symbol. + + Indirection is asymmetrical. The other symbol's value will be used + to satisfy requests for the indirect symbol, but not vice versa. + If the other symbol does not have a definition, libraries will + be searched to find a definition. */ +#define N_INDR 0xa + +/* The following symbols refer to set elements. + All the N_SET[ATDB] symbols with the same name form one set. + Space is allocated for the set in the text section, and each set + element's value is stored into one word of the space. + The first word of the space is the length of the set (number of elements). + + The address of the set is made into an N_SETV symbol + whose name is the same as the name of the set. + This symbol acts like a N_DATA global symbol + in that it can satisfy undefined external references. */ + +/* These appear as input to LD, in a .o file. */ +#define N_SETA 0x14 /* Absolute set element symbol */ +#define N_SETT 0x16 /* Text set element symbol */ +#define N_SETD 0x18 /* Data set element symbol */ +#define N_SETB 0x1A /* Bss set element symbol */ + +/* This is output from LD. */ +#define N_SETV 0x1C /* Pointer to set vector in data area. */ + +#if !defined (N_RELOCATION_INFO_DECLARED) +/* This structure describes a single relocation to be performed. + The text-relocation section of the file is a vector of these structures, + all of which apply to the text section. + Likewise, the data-relocation section applies to the data section. */ + +struct relocation_info +{ + /* Address (within segment) to be relocated. */ + int r_address; + /* The meaning of r_symbolnum depends on r_extern. */ + unsigned int r_symbolnum:24; + /* Nonzero means value is a pc-relative offset + and it should be relocated for changes in its own address + as well as for changes in the symbol or section specified. */ + unsigned int r_pcrel:1; + /* Length (as exponent of 2) of the field to be relocated. + Thus, a value of 2 indicates 1<<2 bytes. */ + unsigned int r_length:2; + /* 1 => relocate with value of symbol. + r_symbolnum is the index of the symbol + in file's the symbol table. + 0 => relocate with the address of a segment. + r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS + (the N_EXT bit may be set also, but signifies nothing). */ + unsigned int r_extern:1; + /* Four bits that aren't used, but when writing an object file + it is desirable to clear them. */ +#ifdef NS32K + unsigned r_bsr:1; + unsigned r_disp:1; + unsigned r_pad:2; +#else + unsigned int r_pad:4; +#endif +}; +#endif /* no N_RELOCATION_INFO_DECLARED. */ + + +#endif /* __A_OUT_GNU_H__ */ diff --git a/gnu/usr.bin/as/config/atof-ieee.c b/gnu/usr.bin/as/config/atof-ieee.c new file mode 100644 index 0000000..6ff45c8 --- /dev/null +++ b/gnu/usr.bin/as/config/atof-ieee.c @@ -0,0 +1,505 @@ +/* atof_ieee.c - turn a Flonum into an IEEE floating point number + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "flonum.h" +#ifdef USG +#define bzero(s,n) memset(s,0,n) +#define bcopy(from,to,n) memcpy((to),(from),(n)) +#endif + +extern FLONUM_TYPE generic_floating_point_number; /* Flonums returned here. */ +#define NULL (0) + +extern char EXP_CHARS[]; + /* Precision in LittleNums. */ +#define MAX_PRECISION (6) +#define F_PRECISION (2) +#define D_PRECISION (4) +#define X_PRECISION (6) +#define P_PRECISION (6) + + /* Length in LittleNums of guard bits. */ +#define GUARD (2) + +static unsigned long int mask [] = { + 0x00000000, + 0x00000001, + 0x00000003, + 0x00000007, + 0x0000000f, + 0x0000001f, + 0x0000003f, + 0x0000007f, + 0x000000ff, + 0x000001ff, + 0x000003ff, + 0x000007ff, + 0x00000fff, + 0x00001fff, + 0x00003fff, + 0x00007fff, + 0x0000ffff, + 0x0001ffff, + 0x0003ffff, + 0x0007ffff, + 0x000fffff, + 0x001fffff, + 0x003fffff, + 0x007fffff, + 0x00ffffff, + 0x01ffffff, + 0x03ffffff, + 0x07ffffff, + 0x0fffffff, + 0x1fffffff, + 0x3fffffff, + 0x7fffffff, + 0xffffffff + }; + +static int bits_left_in_littlenum; +static int littlenums_left; +static LITTLENUM_TYPE * littlenum_pointer; + +static int +next_bits (number_of_bits) + int number_of_bits; +{ + int return_value; + + if(!littlenums_left) + return 0; + if (number_of_bits >= bits_left_in_littlenum) + { + return_value = mask [bits_left_in_littlenum] & *littlenum_pointer; + number_of_bits -= bits_left_in_littlenum; + return_value <<= number_of_bits; + if(--littlenums_left) { + bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits; + littlenum_pointer --; + return_value |= (*littlenum_pointer>>bits_left_in_littlenum) & mask[number_of_bits]; + } + } + else + { + bits_left_in_littlenum -= number_of_bits; + return_value = mask [number_of_bits] & (*littlenum_pointer>>bits_left_in_littlenum); + } + return (return_value); +} + +/* Num had better be less than LITTLENUM_NUMBER_OF_BITS */ +static int +unget_bits(num) +{ + if(!littlenums_left) { + ++littlenum_pointer; + ++littlenums_left; + bits_left_in_littlenum=num; + } else if(bits_left_in_littlenum+num>LITTLENUM_NUMBER_OF_BITS) { + bits_left_in_littlenum= num-(LITTLENUM_NUMBER_OF_BITS-bits_left_in_littlenum); + ++littlenum_pointer; + ++littlenums_left; + } else + bits_left_in_littlenum+=num; +} + +static void +make_invalid_floating_point_number (words) + LITTLENUM_TYPE * words; +{ + as_warn("cannot create floating-point number"); + words[0]= ((unsigned)-1)>>1; /* Zero the leftmost bit */ + words[1]= -1; + words[2]= -1; + words[3]= -1; + words[4]= -1; + words[5]= -1; +} + +/***********************************************************************\ +* Warning: this returns 16-bit LITTLENUMs. It is up to the caller * +* to figure out any alignment problems and to conspire for the * +* bytes/word to be emitted in the right order. Bigendians beware! * +* * +\***********************************************************************/ + +/* Note that atof-ieee always has X and P precisions enabled. it is up + to md_atof to filter them out if the target machine does not support + them. */ + +char * /* Return pointer past text consumed. */ +atof_ieee (str, what_kind, words) + char * str; /* Text to convert to binary. */ + char what_kind; /* 'd', 'f', 'g', 'h' */ + LITTLENUM_TYPE * words; /* Build the binary here. */ +{ + static LITTLENUM_TYPE bits [MAX_PRECISION + MAX_PRECISION + GUARD]; + /* Extra bits for zeroed low-order bits. */ + /* The 1st MAX_PRECISION are zeroed, */ + /* the last contain flonum bits. */ + char * return_value; + int precision; /* Number of 16-bit words in the format. */ + long int exponent_bits; + + return_value = str; + generic_floating_point_number.low = bits + MAX_PRECISION; + generic_floating_point_number.high = NULL; + generic_floating_point_number.leader = NULL; + generic_floating_point_number.exponent = NULL; + generic_floating_point_number.sign = '\0'; + + /* Use more LittleNums than seems */ + /* necessary: the highest flonum may have */ + /* 15 leading 0 bits, so could be useless. */ + + bzero (bits, sizeof(LITTLENUM_TYPE) * MAX_PRECISION); + + switch(what_kind) { + case 'f': + case 'F': + case 's': + case 'S': + precision = F_PRECISION; + exponent_bits = 8; + break; + + case 'd': + case 'D': + case 'r': + case 'R': + precision = D_PRECISION; + exponent_bits = 11; + break; + + case 'x': + case 'X': + case 'e': + case 'E': + precision = X_PRECISION; + exponent_bits = 15; + break; + + case 'p': + case 'P': + + precision = P_PRECISION; + exponent_bits= -1; + break; + + default: + make_invalid_floating_point_number (words); + return NULL; + } + + generic_floating_point_number.high = generic_floating_point_number.low + precision - 1 + GUARD; + + if (atof_generic (& return_value, ".", EXP_CHARS, & generic_floating_point_number)) { + /* as_warn("Error converting floating point number (Exponent overflow?)"); */ + make_invalid_floating_point_number (words); + return NULL; + } + gen_to_words(words, precision, exponent_bits); + return return_value; +} + +/* Turn generic_floating_point_number into a real float/double/extended */ +gen_to_words(words,precision,exponent_bits) +LITTLENUM_TYPE *words; +long int exponent_bits; +int precision; +{ + int return_value=0; + + long int exponent_1; + long int exponent_2; + long int exponent_3; + long int exponent_4; + int exponent_skippage; + LITTLENUM_TYPE word1; + LITTLENUM_TYPE * lp; + + if (generic_floating_point_number.low > generic_floating_point_number.leader) { + /* 0.0e0 seen. */ + if(generic_floating_point_number.sign=='+') + words[0]=0x0000; + else + words[0]=0x8000; + bzero (&words[1], sizeof(LITTLENUM_TYPE) * (precision-1)); + return return_value; + } + + /* NaN: Do the right thing */ + if(generic_floating_point_number.sign==0) { + if(precision==F_PRECISION) { + words[0]=0x7fff; + words[1]=0xffff; + } else { + words[0]=0x7fff; + words[1]=0xffff; + words[2]=0xffff; + words[3]=0xffff; + } + return return_value; + } else if(generic_floating_point_number.sign=='P') { + /* +INF: Do the right thing */ + if(precision==F_PRECISION) { + words[0]=0x7f80; + words[1]=0; + } else { + words[0]=0x7ff0; + words[1]=0; + words[2]=0; + words[3]=0; + } + return return_value; + } else if(generic_floating_point_number.sign=='N') { + /* Negative INF */ + if(precision==F_PRECISION) { + words[0]=0xff80; + words[1]=0x0; + } else { + words[0]=0xfff0; + words[1]=0x0; + words[2]=0x0; + words[3]=0x0; + } + return return_value; + } + /* + * The floating point formats we support have: + * Bit 15 is sign bit. + * Bits 14:n are excess-whatever exponent. + * Bits n-1:0 (if any) are most significant bits of fraction. + * Bits 15:0 of the next word(s) are the next most significant bits. + * + * So we need: number of bits of exponent, number of bits of + * mantissa. + */ + bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS; + littlenum_pointer = generic_floating_point_number.leader; + littlenums_left = 1+generic_floating_point_number.leader - generic_floating_point_number.low; + /* Seek (and forget) 1st significant bit */ + for (exponent_skippage = 0;! next_bits(1); exponent_skippage ++) + ; + exponent_1 = generic_floating_point_number.exponent + generic_floating_point_number.leader + 1 - + generic_floating_point_number.low; + /* Radix LITTLENUM_RADIX, point just higher than generic_floating_point_number.leader. */ + exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS; + /* Radix 2. */ + exponent_3 = exponent_2 - exponent_skippage; + /* Forget leading zeros, forget 1st bit. */ + exponent_4 = exponent_3 + ((1 << (exponent_bits - 1)) - 2); + /* Offset exponent. */ + + lp = words; + + /* Word 1. Sign, exponent and perhaps high bits. */ + word1 = (generic_floating_point_number.sign == '+') ? 0 : (1<<(LITTLENUM_NUMBER_OF_BITS-1)); + + /* Assume 2's complement integers. */ + if(exponent_4<1 && exponent_4>=-62) { + int prec_bits; + int num_bits; + + unget_bits(1); + num_bits= -exponent_4; + prec_bits=LITTLENUM_NUMBER_OF_BITS*precision-(exponent_bits+1+num_bits); + if(precision==X_PRECISION && exponent_bits==15) + prec_bits-=LITTLENUM_NUMBER_OF_BITS+1; + + if(num_bits>=LITTLENUM_NUMBER_OF_BITS-exponent_bits) { + /* Bigger than one littlenum */ + num_bits-=(LITTLENUM_NUMBER_OF_BITS-1)-exponent_bits; + *lp++=word1; + if(num_bits+exponent_bits+1>=precision*LITTLENUM_NUMBER_OF_BITS) { + /* Exponent overflow */ + make_invalid_floating_point_number(words); + return return_value; + } + if(precision==X_PRECISION && exponent_bits==15) { + *lp++=0; + *lp++=0; + num_bits-=LITTLENUM_NUMBER_OF_BITS-1; + } + while(num_bits>=LITTLENUM_NUMBER_OF_BITS) { + num_bits-=LITTLENUM_NUMBER_OF_BITS; + *lp++=0; + } + if(num_bits) + *lp++=next_bits(LITTLENUM_NUMBER_OF_BITS-(num_bits)); + } else { + if(precision==X_PRECISION && exponent_bits==15) { + *lp++=word1; + *lp++=0; + if(num_bits==LITTLENUM_NUMBER_OF_BITS) { + *lp++=0; + *lp++=next_bits(LITTLENUM_NUMBER_OF_BITS-1); + } else if(num_bits==LITTLENUM_NUMBER_OF_BITS-1) + *lp++=0; + else + *lp++=next_bits(LITTLENUM_NUMBER_OF_BITS-1-num_bits); + num_bits=0; + } else { + word1|= next_bits ((LITTLENUM_NUMBER_OF_BITS-1) - (exponent_bits+num_bits)); + *lp++=word1; + } + } + while(lp<words+precision) + *lp++=next_bits(LITTLENUM_NUMBER_OF_BITS); + + /* Round the mantissa up, but don't change the number */ + if(next_bits(1)) { + --lp; + if(prec_bits>LITTLENUM_NUMBER_OF_BITS) { + int n = 0; + int tmp_bits; + + n=0; + tmp_bits=prec_bits; + while(tmp_bits>LITTLENUM_NUMBER_OF_BITS) { + if(lp[n]!=(LITTLENUM_TYPE)-1) + break; + --n; + tmp_bits-=LITTLENUM_NUMBER_OF_BITS; + } + if(tmp_bits>LITTLENUM_NUMBER_OF_BITS || (lp[n]&mask[tmp_bits])!=mask[tmp_bits]) { + unsigned long int carry; + + for (carry = 1; carry && (lp >= words); lp --) { + carry = * lp + carry; + * lp = carry; + carry >>= LITTLENUM_NUMBER_OF_BITS; + } + } + } else if((*lp&mask[prec_bits])!=mask[prec_bits]) + lp++; + } + + return return_value; + } else if (exponent_4 & ~ mask [exponent_bits]) { + /* + * Exponent overflow. Lose immediately. + */ + + /* + * We leave return_value alone: admit we read the + * number, but return a floating exception + * because we can't encode the number. + */ + make_invalid_floating_point_number (words); + return return_value; + } else { + word1 |= (exponent_4 << ((LITTLENUM_NUMBER_OF_BITS-1) - exponent_bits)) + | next_bits ((LITTLENUM_NUMBER_OF_BITS-1) - exponent_bits); + } + + * lp ++ = word1; + + /* X_PRECISION is special: it has 16 bits of zero in the middle, + followed by a 1 bit. */ + if(exponent_bits==15 && precision==X_PRECISION) { + *lp++=0; + *lp++= 1<<(LITTLENUM_NUMBER_OF_BITS)|next_bits(LITTLENUM_NUMBER_OF_BITS-1); + } + + /* The rest of the words are just mantissa bits. */ + while(lp < words + precision) + *lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS); + + if (next_bits (1)) { + unsigned long int carry; + /* + * Since the NEXT bit is a 1, round UP the mantissa. + * The cunning design of these hidden-1 floats permits + * us to let the mantissa overflow into the exponent, and + * it 'does the right thing'. However, we lose if the + * highest-order bit of the lowest-order word flips. + * Is that clear? + */ + + +/* #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2) + Please allow at least 1 more bit in carry than is in a LITTLENUM. + We need that extra bit to hold a carry during a LITTLENUM carry + propagation. Another extra bit (kept 0) will assure us that we + don't get a sticky sign bit after shifting right, and that + permits us to propagate the carry without any masking of bits. +#endif */ + for (carry = 1, lp --; carry && (lp >= words); lp --) { + carry = * lp + carry; + * lp = carry; + carry >>= LITTLENUM_NUMBER_OF_BITS; + } + if ( (word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1)) ) { + /* We leave return_value alone: admit we read the + * number, but return a floating exception + * because we can't encode the number. + */ + *words&= ~ (1 << (LITTLENUM_NUMBER_OF_BITS - 1)); + /* make_invalid_floating_point_number (words); */ + /* return return_value; */ + } + } + return (return_value); +} + +/* This routine is a real kludge. Someone really should do it better, but + I'm too lazy, and I don't understand this stuff all too well anyway + (JF) + */ +void +int_to_gen(x) +long x; +{ + char buf[20]; + char *bufp; + + sprintf(buf,"%ld",x); + bufp= &buf[0]; + if(atof_generic(&bufp,".", EXP_CHARS, &generic_floating_point_number)) + as_warn("Error converting number to floating point (Exponent overflow?)"); +} + +#ifdef TEST +char * +print_gen(gen) +FLONUM_TYPE *gen; +{ + FLONUM_TYPE f; + LITTLENUM_TYPE arr[10]; + double dv; + float fv; + static char sbuf[40]; + + if(gen) { + f=generic_floating_point_number; + generic_floating_point_number= *gen; + } + gen_to_words(&arr[0],4,11); + bcopy(&arr[0],&dv,sizeof(double)); + sprintf(sbuf,"%x %x %x %x %.14G ",arr[0],arr[1],arr[2],arr[3],dv); + gen_to_words(&arr[0],2,8); + bcopy(&arr[0],&fv,sizeof(float)); + sprintf(sbuf+strlen(sbuf),"%x %x %.12g\n",arr[0],arr[1],fv); + if(gen) + generic_floating_point_number=f; + return sbuf; +} +#endif diff --git a/gnu/usr.bin/as/config/i386-opcode.h b/gnu/usr.bin/as/config/i386-opcode.h new file mode 100644 index 0000000..35c86c3 --- /dev/null +++ b/gnu/usr.bin/as/config/i386-opcode.h @@ -0,0 +1,806 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * + * @(#)i386-opcode.h 6.3 (Berkeley) 5/8/91 + */ + +/* i386-opcode.h -- Intel 80386 opcode table + Copyright (C) 1989, Free Software Foundation. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +template i386_optab[] = { + +#define _ None +/* move instructions */ +{ "mov", 2, 0xa0, _, DW|NoModrm, Disp32, Acc, 0 }, +{ "mov", 2, 0x88, _, DW|Modrm, Reg, Reg|Mem, 0 }, +{ "mov", 2, 0xb0, _, ShortFormW, Imm, Reg, 0 }, +{ "mov", 2, 0xc6, _, W|Modrm, Imm, Reg|Mem, 0 }, +{ "mov", 2, 0x8c, _, D|Modrm, SReg3|SReg2, Reg16|Mem16, 0 }, +/* move to/from control debug registers */ +{ "mov", 2, 0x0f20, _, D|Modrm, Control, Reg32, 0}, +{ "mov", 2, 0x0f21, _, D|Modrm, Debug, Reg32, 0}, +{ "mov", 2, 0x0f24, _, D|Modrm, Test, Reg32, 0}, + +/* move with sign extend */ +/* "movsbl" & "movsbw" must not be unified into "movsb" to avoid + conflict with the "movs" string move instruction. Thus, + {"movsb", 2, 0x0fbe, _, ReverseRegRegmem|Modrm, Reg8|Mem, Reg16|Reg32, 0}, + is not kosher; we must seperate the two instructions. */ +{"movsbl", 2, 0x0fbe, _, ReverseRegRegmem|Modrm, Reg8|Mem, Reg32, 0}, +{"movsbw", 2, 0x660fbe, _, ReverseRegRegmem|Modrm, Reg8|Mem, Reg16, 0}, +{"movswl", 2, 0x0fbf, _, ReverseRegRegmem|Modrm, Reg16|Mem, Reg32, 0}, + +/* move with zero extend */ +{"movzb", 2, 0x0fb6, _, ReverseRegRegmem|Modrm, Reg8|Mem, Reg16|Reg32, 0}, +{"movzwl", 2, 0x0fb7, _, ReverseRegRegmem|Modrm, Reg16|Mem, Reg32, 0}, + +/* push instructions */ +{"push", 1, 0x50, _, ShortForm, WordReg,0,0 }, +{"push", 1, 0xff, 0x6, Modrm, WordReg|WordMem, 0, 0 }, +{"push", 1, 0x6a, _, NoModrm, Imm8S, 0, 0}, +{"push", 1, 0x68, _, NoModrm, Imm32, 0, 0}, +{"push", 1, 0x06, _, Seg2ShortForm, SReg2,0,0 }, +{"push", 1, 0x0fa0, _, Seg3ShortForm, SReg3,0,0 }, +/* push all */ +{"pusha", 0, 0x60, _, NoModrm, 0, 0, 0 }, + +/* pop instructions */ +{"pop", 1, 0x58, _, ShortForm, WordReg,0,0 }, +{"pop", 1, 0x8f, 0x0, Modrm, WordReg|WordMem, 0, 0 }, +#define POP_SEG_SHORT 0x7 +{"pop", 1, 0x07, _, Seg2ShortForm, SReg2,0,0 }, +{"pop", 1, 0x0fa1, _, Seg3ShortForm, SReg3,0,0 }, +/* pop all */ +{"popa", 0, 0x61, _, NoModrm, 0, 0, 0 }, + +/* xchg exchange instructions + xchg commutes: we allow both operand orders */ +{"xchg", 2, 0x90, _, ShortForm, WordReg, Acc, 0 }, +{"xchg", 2, 0x90, _, ShortForm, Acc, WordReg, 0 }, +{"xchg", 2, 0x86, _, W|Modrm, Reg, Reg|Mem, 0 }, +{"xchg", 2, 0x86, _, W|Modrm, Reg|Mem, Reg, 0 }, + +/* in/out from ports */ +{"in", 2, 0xe4, _, W|NoModrm, Imm8, Acc, 0 }, +{"in", 2, 0xec, _, W|NoModrm, InOutPortReg, Acc, 0 }, +{"out", 2, 0xe6, _, W|NoModrm, Acc, Imm8, 0 }, +{"out", 2, 0xee, _, W|NoModrm, Acc, InOutPortReg, 0 }, + +/* load effective address */ +{"lea", 2, 0x8d, _, Modrm, WordMem, WordReg, 0 }, + +/* load segment registers from memory */ +{"lds", 2, 0xc5, _, Modrm, Mem, Reg32, 0}, +{"les", 2, 0xc4, _, Modrm, Mem, Reg32, 0}, +{"lfs", 2, 0x0fb4, _, Modrm, Mem, Reg32, 0}, +{"lgs", 2, 0x0fb5, _, Modrm, Mem, Reg32, 0}, +{"lss", 2, 0x0fb2, _, Modrm, Mem, Reg32, 0}, + +/* flags register instructions */ +{"clc", 0, 0xf8, _, NoModrm, 0, 0, 0}, +{"cld", 0, 0xfc, _, NoModrm, 0, 0, 0}, +{"cli", 0, 0xfa, _, NoModrm, 0, 0, 0}, +{"clts", 0, 0x0f06, _, NoModrm, 0, 0, 0}, +{"cmc", 0, 0xf5, _, NoModrm, 0, 0, 0}, +{"lahf", 0, 0x9f, _, NoModrm, 0, 0, 0}, +{"sahf", 0, 0x9e, _, NoModrm, 0, 0, 0}, +{"pushf", 0, 0x9c, _, NoModrm, 0, 0, 0}, +{"popf", 0, 0x9d, _, NoModrm, 0, 0, 0}, +{"stc", 0, 0xf9, _, NoModrm, 0, 0, 0}, +{"std", 0, 0xfd, _, NoModrm, 0, 0, 0}, +{"sti", 0, 0xfb, _, NoModrm, 0, 0, 0}, + +{"add", 2, 0x0, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"add", 2, 0x83, 0, Modrm, Imm8S, WordReg|WordMem, 0}, +{"add", 2, 0x4, _, W|NoModrm, Imm, Acc, 0}, +{"add", 2, 0x80, 0, W|Modrm, Imm, Reg|Mem, 0}, + +{"inc", 1, 0x40, _, ShortForm, WordReg, 0, 0}, +{"inc", 1, 0xfe, 0, W|Modrm, Reg|Mem, 0, 0}, + +{"sub", 2, 0x28, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"sub", 2, 0x83, 5, Modrm, Imm8S, WordReg|WordMem, 0}, +{"sub", 2, 0x2c, _, W|NoModrm, Imm, Acc, 0}, +{"sub", 2, 0x80, 5, W|Modrm, Imm, Reg|Mem, 0}, + +{"dec", 1, 0x48, _, ShortForm, WordReg, 0, 0}, +{"dec", 1, 0xfe, 1, W|Modrm, Reg|Mem, 0, 0}, + +{"sbb", 2, 0x18, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"sbb", 2, 0x83, 3, Modrm, Imm8S, WordReg|WordMem, 0}, +{"sbb", 2, 0x1c, _, W|NoModrm, Imm, Acc, 0}, +{"sbb", 2, 0x80, 3, W|Modrm, Imm, Reg|Mem, 0}, + +{"cmp", 2, 0x38, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"cmp", 2, 0x83, 7, Modrm, Imm8S, WordReg|WordMem, 0}, +{"cmp", 2, 0x3c, _, W|NoModrm, Imm, Acc, 0}, +{"cmp", 2, 0x80, 7, W|Modrm, Imm, Reg|Mem, 0}, + +{"test", 2, 0x84, _, W|Modrm, Reg|Mem, Reg, 0}, +{"test", 2, 0x84, _, W|Modrm, Reg, Reg|Mem, 0}, +{"test", 2, 0xa8, _, W|NoModrm, Imm, Acc, 0}, +{"test", 2, 0xf6, 0, W|Modrm, Imm, Reg|Mem, 0}, + +{"and", 2, 0x20, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"and", 2, 0x83, 4, Modrm, Imm8S, WordReg|WordMem, 0}, +{"and", 2, 0x24, _, W|NoModrm, Imm, Acc, 0}, +{"and", 2, 0x80, 4, W|Modrm, Imm, Reg|Mem, 0}, + +{"or", 2, 0x08, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"or", 2, 0x83, 1, Modrm, Imm8S, WordReg|WordMem, 0}, +{"or", 2, 0x0c, _, W|NoModrm, Imm, Acc, 0}, +{"or", 2, 0x80, 1, W|Modrm, Imm, Reg|Mem, 0}, + +{"xor", 2, 0x30, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"xor", 2, 0x83, 6, Modrm, Imm8S, WordReg|WordMem, 0}, +{"xor", 2, 0x34, _, W|NoModrm, Imm, Acc, 0}, +{"xor", 2, 0x80, 6, W|Modrm, Imm, Reg|Mem, 0}, + +{"adc", 2, 0x10, _, DW|Modrm, Reg, Reg|Mem, 0}, +{"adc", 2, 0x83, 2, Modrm, Imm8S, WordReg|WordMem, 0}, +{"adc", 2, 0x14, _, W|NoModrm, Imm, Acc, 0}, +{"adc", 2, 0x80, 2, W|Modrm, Imm, Reg|Mem, 0}, + +{"neg", 1, 0xf6, 3, W|Modrm, Reg|Mem, 0, 0}, +{"not", 1, 0xf6, 2, W|Modrm, Reg|Mem, 0, 0}, + +{"aaa", 0, 0x37, _, NoModrm, 0, 0, 0}, +{"aas", 0, 0x3f, _, NoModrm, 0, 0, 0}, +{"daa", 0, 0x27, _, NoModrm, 0, 0, 0}, +{"das", 0, 0x2f, _, NoModrm, 0, 0, 0}, +{"aad", 0, 0xd50a, _, NoModrm, 0, 0, 0}, +{"aam", 0, 0xd40a, _, NoModrm, 0, 0, 0}, + +/* conversion insns */ +/* conversion: intel naming */ +{"cbw", 0, 0x6698, _, NoModrm, 0, 0, 0}, +{"cwd", 0, 0x6699, _, NoModrm, 0, 0, 0}, +{"cwde", 0, 0x98, _, NoModrm, 0, 0, 0}, +{"cdq", 0, 0x99, _, NoModrm, 0, 0, 0}, +/* att naming */ +{"cbtw", 0, 0x6698, _, NoModrm, 0, 0, 0}, +{"cwtl", 0, 0x98, _, NoModrm, 0, 0, 0}, +{"cwtd", 0, 0x6699, _, NoModrm, 0, 0, 0}, +{"cltd", 0, 0x99, _, NoModrm, 0, 0, 0}, + +/* Warning! the mul/imul (opcode 0xf6) must only have 1 operand! They are + expanding 64-bit multiplies, and *cannot* be selected to accomplish + 'imul %ebx, %eax' (opcode 0x0faf must be used in this case) + These multiplies can only be selected with single opearnd forms. */ +{"mul", 1, 0xf6, 4, W|Modrm, Reg|Mem, 0, 0}, +{"imul", 1, 0xf6, 5, W|Modrm, Reg|Mem, 0, 0}, + + + + +/* imulKludge here is needed to reverse the i.rm.reg & i.rm.regmem fields. + These instructions are exceptions: 'imul $2, %eax, %ecx' would put + '%eax' in the reg field and '%ecx' in the regmem field if we did not + switch them. */ +{"imul", 2, 0x0faf, _, Modrm|ReverseRegRegmem, WordReg|Mem, WordReg, 0}, +{"imul", 3, 0x6b, _, Modrm|ReverseRegRegmem, Imm8S, WordReg|Mem, WordReg}, +{"imul", 3, 0x69, _, Modrm|ReverseRegRegmem, Imm16|Imm32, WordReg|Mem, WordReg}, +/* + imul with 2 operands mimicks imul with 3 by puting register both + in i.rm.reg & i.rm.regmem fields +*/ +{"imul", 2, 0x6b, _, Modrm|imulKludge, Imm8S, WordReg, 0}, +{"imul", 2, 0x69, _, Modrm|imulKludge, Imm16|Imm32, WordReg, 0}, +{"div", 1, 0xf6, 6, W|Modrm, Reg|Mem, 0, 0}, +{"div", 2, 0xf6, 6, W|Modrm, Reg|Mem, Acc, 0}, +{"idiv", 1, 0xf6, 7, W|Modrm, Reg|Mem, 0, 0}, +{"idiv", 2, 0xf6, 7, W|Modrm, Reg|Mem, Acc, 0}, + +{"rol", 2, 0xd0, 0, W|Modrm, Imm1, Reg|Mem, 0}, +{"rol", 2, 0xc0, 0, W|Modrm, Imm8, Reg|Mem, 0}, +{"rol", 2, 0xd2, 0, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"rol", 1, 0xd0, 0, W|Modrm, Reg|Mem, 0, 0}, + +{"ror", 2, 0xd0, 1, W|Modrm, Imm1, Reg|Mem, 0}, +{"ror", 2, 0xc0, 1, W|Modrm, Imm8, Reg|Mem, 0}, +{"ror", 2, 0xd2, 1, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"ror", 1, 0xd0, 1, W|Modrm, Reg|Mem, 0, 0}, + +{"rcl", 2, 0xd0, 2, W|Modrm, Imm1, Reg|Mem, 0}, +{"rcl", 2, 0xc0, 2, W|Modrm, Imm8, Reg|Mem, 0}, +{"rcl", 2, 0xd2, 2, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"rcl", 1, 0xd0, 2, W|Modrm, Reg|Mem, 0, 0}, + +{"rcr", 2, 0xd0, 3, W|Modrm, Imm1, Reg|Mem, 0}, +{"rcr", 2, 0xc0, 3, W|Modrm, Imm8, Reg|Mem, 0}, +{"rcr", 2, 0xd2, 3, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"rcr", 1, 0xd0, 3, W|Modrm, Reg|Mem, 0, 0}, + +{"sal", 2, 0xd0, 4, W|Modrm, Imm1, Reg|Mem, 0}, +{"sal", 2, 0xc0, 4, W|Modrm, Imm8, Reg|Mem, 0}, +{"sal", 2, 0xd2, 4, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"sal", 1, 0xd0, 4, W|Modrm, Reg|Mem, 0, 0}, +{"shl", 2, 0xd0, 4, W|Modrm, Imm1, Reg|Mem, 0}, +{"shl", 2, 0xc0, 4, W|Modrm, Imm8, Reg|Mem, 0}, +{"shl", 2, 0xd2, 4, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"shl", 1, 0xd0, 4, W|Modrm, Reg|Mem, 0, 0}, + +{"shld", 3, 0x0fa4, _, Modrm, Imm8, WordReg, WordReg|Mem}, +{"shld", 3, 0x0fa5, _, Modrm, ShiftCount, WordReg, WordReg|Mem}, + +{"shr", 2, 0xd0, 5, W|Modrm, Imm1, Reg|Mem, 0}, +{"shr", 2, 0xc0, 5, W|Modrm, Imm8, Reg|Mem, 0}, +{"shr", 2, 0xd2, 5, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"shr", 1, 0xd0, 5, W|Modrm, Reg|Mem, 0, 0}, + +{"shrd", 3, 0x0fac, _, Modrm, Imm8, WordReg, WordReg|Mem}, +{"shrd", 3, 0x0fad, _, Modrm, ShiftCount, WordReg, WordReg|Mem}, + +{"sar", 2, 0xd0, 7, W|Modrm, Imm1, Reg|Mem, 0}, +{"sar", 2, 0xc0, 7, W|Modrm, Imm8, Reg|Mem, 0}, +{"sar", 2, 0xd2, 7, W|Modrm, ShiftCount, Reg|Mem, 0}, +{"sar", 1, 0xd0, 7, W|Modrm, Reg|Mem, 0, 0}, + +/* control transfer instructions */ +#define CALL_PC_RELATIVE 0xe8 +{"call", 1, 0xe8, _, JumpDword, Disp32, 0, 0}, +{"call", 1, 0xff, 2, Modrm, Reg|Mem|JumpAbsolute, 0, 0}, +#define CALL_FAR_IMMEDIATE 0x9a +{"lcall", 2, 0x9a, _, JumpInterSegment, Imm16, Imm32, 0}, +{"lcall", 1, 0xff, 3, Modrm, Mem, 0, 0}, + +#define JUMP_PC_RELATIVE 0xeb +{"jmp", 1, 0xeb, _, Jump, Disp, 0, 0}, +{"jmp", 1, 0xff, 4, Modrm, Reg32|Mem|JumpAbsolute, 0, 0}, +#define JUMP_FAR_IMMEDIATE 0xea +{"ljmp", 2, 0xea, _, JumpInterSegment, Imm16, Imm32, 0}, +{"ljmp", 1, 0xff, 5, Modrm, Mem, 0, 0}, + +{"ret", 0, 0xc3, _, NoModrm, 0, 0, 0}, +{"ret", 1, 0xc2, _, NoModrm, Imm16, 0, 0}, +{"lret", 0, 0xcb, _, NoModrm, 0, 0, 0}, +{"lret", 1, 0xca, _, NoModrm, Imm16, 0, 0}, +{"enter", 2, 0xc8, _, NoModrm, Imm16, Imm8, 0}, +{"leave", 0, 0xc9, _, NoModrm, 0, 0, 0}, + +/* conditional jumps */ +{"jo", 1, 0x70, _, Jump, Disp, 0, 0}, + +{"jno", 1, 0x71, _, Jump, Disp, 0, 0}, + +{"jb", 1, 0x72, _, Jump, Disp, 0, 0}, +{"jc", 1, 0x72, _, Jump, Disp, 0, 0}, +{"jnae", 1, 0x72, _, Jump, Disp, 0, 0}, + +{"jnb", 1, 0x73, _, Jump, Disp, 0, 0}, +{"jnc", 1, 0x73, _, Jump, Disp, 0, 0}, +{"jae", 1, 0x73, _, Jump, Disp, 0, 0}, + +{"je", 1, 0x74, _, Jump, Disp, 0, 0}, +{"jz", 1, 0x74, _, Jump, Disp, 0, 0}, + +{"jne", 1, 0x75, _, Jump, Disp, 0, 0}, +{"jnz", 1, 0x75, _, Jump, Disp, 0, 0}, + +{"jbe", 1, 0x76, _, Jump, Disp, 0, 0}, +{"jna", 1, 0x76, _, Jump, Disp, 0, 0}, + +{"jnbe", 1, 0x77, _, Jump, Disp, 0, 0}, +{"ja", 1, 0x77, _, Jump, Disp, 0, 0}, + +{"js", 1, 0x78, _, Jump, Disp, 0, 0}, + +{"jns", 1, 0x79, _, Jump, Disp, 0, 0}, + +{"jp", 1, 0x7a, _, Jump, Disp, 0, 0}, +{"jpe", 1, 0x7a, _, Jump, Disp, 0, 0}, + +{"jnp", 1, 0x7b, _, Jump, Disp, 0, 0}, +{"jpo", 1, 0x7b, _, Jump, Disp, 0, 0}, + +{"jl", 1, 0x7c, _, Jump, Disp, 0, 0}, +{"jnge", 1, 0x7c, _, Jump, Disp, 0, 0}, + +{"jnl", 1, 0x7d, _, Jump, Disp, 0, 0}, +{"jge", 1, 0x7d, _, Jump, Disp, 0, 0}, + +{"jle", 1, 0x7e, _, Jump, Disp, 0, 0}, +{"jng", 1, 0x7e, _, Jump, Disp, 0, 0}, + +{"jnle", 1, 0x7f, _, Jump, Disp, 0, 0}, +{"jg", 1, 0x7f, _, Jump, Disp, 0, 0}, + +/* these turn into pseudo operations when disp is larger than 8 bits */ +#define IS_JUMP_ON_CX_ZERO(o) \ + (o == 0x67e3) +#define IS_JUMP_ON_ECX_ZERO(o) \ + (o == 0xe3) + +{"jcxz", 1, 0x67e3, _, JumpByte, Disp, 0, 0}, +{"jecxz", 1, 0xe3, _, JumpByte, Disp, 0, 0}, + +#define IS_LOOP_ECX_TIMES(o) \ + (o == 0xe2 || o == 0xe1 || o == 0xe0) + +{"loop", 1, 0xe2, _, JumpByte, Disp, 0, 0}, + +{"loopz", 1, 0xe1, _, JumpByte, Disp, 0, 0}, +{"loope", 1, 0xe1, _, JumpByte, Disp, 0, 0}, + +{"loopnz", 1, 0xe0, _, JumpByte, Disp, 0, 0}, +{"loopne", 1, 0xe0, _, JumpByte, Disp, 0, 0}, + +/* set byte on flag instructions */ +{"seto", 1, 0x0f90, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setno", 1, 0x0f91, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setb", 1, 0x0f92, 0, Modrm, Reg8|Mem, 0, 0}, +{"setnae", 1, 0x0f92, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setnb", 1, 0x0f93, 0, Modrm, Reg8|Mem, 0, 0}, +{"setae", 1, 0x0f93, 0, Modrm, Reg8|Mem, 0, 0}, + +{"sete", 1, 0x0f94, 0, Modrm, Reg8|Mem, 0, 0}, +{"setz", 1, 0x0f94, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setne", 1, 0x0f95, 0, Modrm, Reg8|Mem, 0, 0}, +{"setnz", 1, 0x0f95, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setbe", 1, 0x0f96, 0, Modrm, Reg8|Mem, 0, 0}, +{"setna", 1, 0x0f96, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setnbe", 1, 0x0f97, 0, Modrm, Reg8|Mem, 0, 0}, +{"seta", 1, 0x0f97, 0, Modrm, Reg8|Mem, 0, 0}, + +{"sets", 1, 0x0f98, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setns", 1, 0x0f99, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setp", 1, 0x0f9a, 0, Modrm, Reg8|Mem, 0, 0}, +{"setpe", 1, 0x0f9a, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setnp", 1, 0x0f9b, 0, Modrm, Reg8|Mem, 0, 0}, +{"setpo", 1, 0x0f9b, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setl", 1, 0x0f9c, 0, Modrm, Reg8|Mem, 0, 0}, +{"setnge", 1, 0x0f9c, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setnl", 1, 0x0f9d, 0, Modrm, Reg8|Mem, 0, 0}, +{"setge", 1, 0x0f9d, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setle", 1, 0x0f9e, 0, Modrm, Reg8|Mem, 0, 0}, +{"setng", 1, 0x0f9e, 0, Modrm, Reg8|Mem, 0, 0}, + +{"setnle", 1, 0x0f9f, 0, Modrm, Reg8|Mem, 0, 0}, +{"setg", 1, 0x0f9f, 0, Modrm, Reg8|Mem, 0, 0}, + +#define IS_STRING_INSTRUCTION(o) \ + ((o) == 0xa6 || (o) == 0x6c || (o) == 0x6e || (o) == 0x6e || \ + (o) == 0xac || (o) == 0xa4 || (o) == 0xae || (o) == 0xaa || \ + (o) == 0xd7) + +/* string manipulation */ +{"cmps", 0, 0xa6, _, W|NoModrm, 0, 0, 0}, +{"ins", 0, 0x6c, _, W|NoModrm, 0, 0, 0}, +{"outs", 0, 0x6e, _, W|NoModrm, 0, 0, 0}, +{"lods", 0, 0xac, _, W|NoModrm, 0, 0, 0}, +{"movs", 0, 0xa4, _, W|NoModrm, 0, 0, 0}, +{"scas", 0, 0xae, _, W|NoModrm, 0, 0, 0}, +{"stos", 0, 0xaa, _, W|NoModrm, 0, 0, 0}, +{"xlat", 0, 0xd7, _, NoModrm, 0, 0, 0}, + +/* bit manipulation */ +{"bsf", 2, 0x0fbc, _, Modrm|ReverseRegRegmem, Reg|Mem, Reg, 0}, +{"bsr", 2, 0x0fbd, _, Modrm|ReverseRegRegmem, Reg|Mem, Reg, 0}, +{"bt", 2, 0x0fa3, _, Modrm, Reg, Reg|Mem, 0}, +{"bt", 2, 0x0fba, 4, Modrm, Imm8, Reg|Mem, 0}, +{"btc", 2, 0x0fbb, _, Modrm, Reg, Reg|Mem, 0}, +{"btc", 2, 0x0fba, 7, Modrm, Imm8, Reg|Mem, 0}, +{"btr", 2, 0x0fb3, _, Modrm, Reg, Reg|Mem, 0}, +{"btr", 2, 0x0fba, 6, Modrm, Imm8, Reg|Mem, 0}, +{"bts", 2, 0x0fab, _, Modrm, Reg, Reg|Mem, 0}, +{"bts", 2, 0x0fba, 5, Modrm, Imm8, Reg|Mem, 0}, + +/* interrupts & op. sys insns */ +/* See i386.c for conversion of 'int $3' into the special int 3 insn. */ +#define INT_OPCODE 0xcd +#define INT3_OPCODE 0xcc +{"int", 1, 0xcd, _, NoModrm, Imm8, 0, 0}, +{"int3", 0, 0xcc, _, NoModrm, 0, 0, 0}, +{"into", 0, 0xce, _, NoModrm, 0, 0, 0}, +{"iret", 0, 0xcf, _, NoModrm, 0, 0, 0}, + +{"boundl", 2, 0x62, _, Modrm, Reg32, Mem, 0}, +{"boundw", 2, 0x6662, _, Modrm, Reg16, Mem, 0}, + +{"hlt", 0, 0xf4, _, NoModrm, 0, 0, 0}, +{"wait", 0, 0x9b, _, NoModrm, 0, 0, 0}, +/* nop is actually 'xchgl %eax, %eax' */ +{"nop", 0, 0x90, _, NoModrm, 0, 0, 0}, + +/* protection control */ +{"arpl", 2, 0x63, _, Modrm, Reg16, Reg16|Mem, 0}, +{"lar", 2, 0x0f02, _, Modrm|ReverseRegRegmem, WordReg|Mem, WordReg, 0}, +{"lgdt", 1, 0x0f01, 2, Modrm, Mem, 0, 0}, +{"lidt", 1, 0x0f01, 3, Modrm, Mem, 0, 0}, +{"lldt", 1, 0x0f00, 2, Modrm, WordReg|Mem, 0, 0}, +{"lmsw", 1, 0x0f01, 6, Modrm, WordReg|Mem, 0, 0}, +{"lsl", 2, 0x0f03, _, Modrm|ReverseRegRegmem, WordReg|Mem, WordReg, 0}, +{"ltr", 1, 0x0f00, 3, Modrm, WordReg|Mem, 0, 0}, + +{"sgdt", 1, 0x0f01, 0, Modrm, Mem, 0, 0}, +{"sidt", 1, 0x0f01, 1, Modrm, Mem, 0, 0}, +{"sldt", 1, 0x0f00, 0, Modrm, WordReg|Mem, 0, 0}, +{"smsw", 1, 0x0f01, 4, Modrm, WordReg|Mem, 0, 0}, +{"str", 1, 0x0f00, 1, Modrm, Reg16|Mem, 0, 0}, + +{"verr", 1, 0x0f00, 4, Modrm, WordReg|Mem, 0, 0}, +{"verw", 1, 0x0f00, 5, Modrm, WordReg|Mem, 0, 0}, + +/* floating point instructions */ + +/* load */ +{"fld", 1, 0xd9c0, _, ShortForm, FloatReg, 0, 0}, /* register */ +{"flds", 1, 0xd9, 0, Modrm, Mem, 0, 0}, /* %st0 <-- mem float */ +{"fildl", 1, 0xdb, 0, Modrm, Mem, 0, 0}, /* %st0 <-- mem word */ +{"fldl", 1, 0xdd, 0, Modrm, Mem, 0, 0}, /* %st0 <-- mem double */ +{"fldl", 1, 0xd9c0, _, ShortForm, FloatReg, 0, 0}, /* register */ +{"filds", 1, 0xdf, 0, Modrm, Mem, 0, 0}, /* %st0 <-- mem dword */ +{"fildq", 1, 0xdf, 5, Modrm, Mem, 0, 0}, /* %st0 <-- mem qword */ +{"fldt", 1, 0xdb, 5, Modrm, Mem, 0, 0}, /* %st0 <-- mem efloat */ +{"fbld", 1, 0xdf, 4, Modrm, Mem, 0, 0}, /* %st0 <-- mem bcd */ + +/* store (no pop) */ +{"fst", 1, 0xddd0, _, ShortForm, FloatReg, 0, 0}, /* register */ +{"fsts", 1, 0xd9, 2, Modrm, Mem, 0, 0}, /* %st0 --> mem float */ +{"fistl", 1, 0xdb, 2, Modrm, Mem, 0, 0}, /* %st0 --> mem dword */ +{"fstl", 1, 0xdd, 2, Modrm, Mem, 0, 0}, /* %st0 --> mem double */ +{"fstl", 1, 0xddd0, _, ShortForm, FloatReg, 0, 0}, /* register */ +{"fists", 1, 0xdf, 2, Modrm, Mem, 0, 0}, /* %st0 --> mem word */ + +/* store (with pop) */ +{"fstp", 1, 0xddd8, _, ShortForm, FloatReg, 0, 0}, /* register */ +{"fstps", 1, 0xd9, 3, Modrm, Mem, 0, 0}, /* %st0 --> mem float */ +{"fistpl", 1, 0xdb, 3, Modrm, Mem, 0, 0}, /* %st0 --> mem word */ +{"fstpl", 1, 0xdd, 3, Modrm, Mem, 0, 0}, /* %st0 --> mem double */ +{"fstpl", 1, 0xddd8, _, ShortForm, FloatReg, 0, 0}, /* register */ +{"fistps", 1, 0xdf, 3, Modrm, Mem, 0, 0}, /* %st0 --> mem dword */ +{"fistpq", 1, 0xdf, 7, Modrm, Mem, 0, 0}, /* %st0 --> mem qword */ +{"fstpt", 1, 0xdb, 7, Modrm, Mem, 0, 0}, /* %st0 --> mem efloat */ +{"fbstp", 1, 0xdf, 6, Modrm, Mem, 0, 0}, /* %st0 --> mem bcd */ + +/* exchange %st<n> with %st0 */ +{"fxch", 1, 0xd9c8, _, ShortForm, FloatReg, 0, 0}, + +/* comparison (without pop) */ +{"fcom", 1, 0xd8d0, _, ShortForm, FloatReg, 0, 0}, +{"fcoms", 1, 0xd8, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem float */ +{"ficoml", 1, 0xda, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem word */ +{"fcoml", 1, 0xdc, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem double */ +{"fcoml", 1, 0xd8d0, _, ShortForm, FloatReg, 0, 0}, +{"ficoms", 1, 0xde, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem dword */ + +/* comparison (with pop) */ +{"fcomp", 1, 0xd8d8, _, ShortForm, FloatReg, 0, 0}, +{"fcomps", 1, 0xd8, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem float */ +{"ficompl", 1, 0xda, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem word */ +{"fcompl", 1, 0xdc, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem double */ +{"fcompl", 1, 0xd8d8, _, ShortForm, FloatReg, 0, 0}, +{"ficomps", 1, 0xde, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem dword */ +{"fcompp", 0, 0xded9, _, NoModrm, 0, 0, 0}, /* compare %st0, %st1 & pop twice */ + +/* unordered comparison (with pop) */ +{"fucom", 1, 0xdde0, _, ShortForm, FloatReg, 0, 0}, +{"fucomp", 1, 0xdde8, _, ShortForm, FloatReg, 0, 0}, +{"fucompp", 0, 0xdae9, _, NoModrm, 0, 0, 0}, /* ucompare %st0, %st1 & pop twice */ + +{"ftst", 0, 0xd9e4, _, NoModrm, 0, 0, 0}, /* test %st0 */ +{"fxam", 0, 0xd9e5, _, NoModrm, 0, 0, 0}, /* examine %st0 */ + +/* load constants into %st0 */ +{"fld1", 0, 0xd9e8, _, NoModrm, 0, 0, 0}, /* %st0 <-- 1.0 */ +{"fldl2t", 0, 0xd9e9, _, NoModrm, 0, 0, 0}, /* %st0 <-- log2(10) */ +{"fldl2e", 0, 0xd9ea, _, NoModrm, 0, 0, 0}, /* %st0 <-- log2(e) */ +{"fldpi", 0, 0xd9eb, _, NoModrm, 0, 0, 0}, /* %st0 <-- pi */ +{"fldlg2", 0, 0xd9ec, _, NoModrm, 0, 0, 0}, /* %st0 <-- log10(2) */ +{"fldln2", 0, 0xd9ed, _, NoModrm, 0, 0, 0}, /* %st0 <-- ln(2) */ +{"fldz", 0, 0xd9ee, _, NoModrm, 0, 0, 0}, /* %st0 <-- 0.0 */ + +/* arithmetic */ + +/* add */ +{"fadd", 1, 0xd8c0, _, ShortForm, FloatReg, 0, 0}, +{"fadd", 2, 0xd8c0, _, ShortForm|FloatD, FloatReg, FloatAcc, 0}, +{"fadd", 0, 0xdcc1, _, NoModrm, 0, 0, 0}, /* alias for fadd %st, %st(1) */ +{"faddp", 1, 0xdac0, _, ShortForm, FloatReg, 0, 0}, +{"faddp", 2, 0xdac0, _, ShortForm|FloatD, FloatReg, FloatAcc, 0}, +{"faddp", 0, 0xdec1, _, NoModrm, 0, 0, 0}, /* alias for faddp %st, %st(1) */ +{"fadds", 1, 0xd8, 0, Modrm, Mem, 0, 0}, +{"fiaddl", 1, 0xda, 0, Modrm, Mem, 0, 0}, +{"faddl", 1, 0xdc, 0, Modrm, Mem, 0, 0}, +{"fiadds", 1, 0xde, 0, Modrm, Mem, 0, 0}, + +/* sub */ +/* Note: intel has decided that certain of these operations are reversed + in assembler syntax. */ +{"fsub", 1, 0xd8e0, _, ShortForm, FloatReg, 0, 0}, +{"fsub", 2, 0xd8e0, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fsub", 2, 0xdce8, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fsub", 2, 0xdce0, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fsub", 0, 0xdce1, _, NoModrm, 0, 0, 0}, +{"fsubp", 1, 0xdae0, _, ShortForm, FloatReg, 0, 0}, +{"fsubp", 2, 0xdae0, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fsubp", 2, 0xdee8, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fsubp", 2, 0xdee0, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fsubp", 0, 0xdee1, _, NoModrm, 0, 0, 0}, +{"fsubs", 1, 0xd8, 4, Modrm, Mem, 0, 0}, +{"fisubl", 1, 0xda, 4, Modrm, Mem, 0, 0}, +{"fsubl", 1, 0xdc, 4, Modrm, Mem, 0, 0}, +{"fisubs", 1, 0xde, 4, Modrm, Mem, 0, 0}, + +/* sub reverse */ +{"fsubr", 1, 0xd8e8, _, ShortForm, FloatReg, 0, 0}, +{"fsubr", 2, 0xd8e8, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fsubr", 2, 0xdce0, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fsubr", 2, 0xdce8, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fsubr", 0, 0xdce9, _, NoModrm, 0, 0, 0}, +{"fsubrp", 1, 0xdae8, _, ShortForm, FloatReg, 0, 0}, +{"fsubrp", 2, 0xdae8, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fsubrp", 2, 0xdee0, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fsubrp", 2, 0xdee8, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fsubrp", 0, 0xdee9, _, NoModrm, 0, 0, 0}, +{"fsubrs", 1, 0xd8, 5, Modrm, Mem, 0, 0}, +{"fisubrl", 1, 0xda, 5, Modrm, Mem, 0, 0}, +{"fsubrl", 1, 0xdc, 5, Modrm, Mem, 0, 0}, +{"fisubrs", 1, 0xde, 5, Modrm, Mem, 0, 0}, + +/* mul */ +{"fmul", 1, 0xd8c8, _, ShortForm, FloatReg, 0, 0}, +{"fmul", 2, 0xd8c8, _, ShortForm|FloatD, FloatReg, FloatAcc, 0}, +{"fmul", 0, 0xdcc9, _, NoModrm, 0, 0, 0}, +{"fmulp", 1, 0xdac8, _, ShortForm, FloatReg, 0, 0}, +{"fmulp", 2, 0xdac8, _, ShortForm|FloatD, FloatReg, FloatAcc, 0}, +{"fmulp", 0, 0xdec9, _, NoModrm, 0, 0, 0}, +{"fmuls", 1, 0xd8, 1, Modrm, Mem, 0, 0}, +{"fimull", 1, 0xda, 1, Modrm, Mem, 0, 0}, +{"fmull", 1, 0xdc, 1, Modrm, Mem, 0, 0}, +{"fimuls", 1, 0xde, 1, Modrm, Mem, 0, 0}, + +/* div */ +/* Note: intel has decided that certain of these operations are reversed + in assembler syntax. */ +{"fdiv", 1, 0xd8f0, _, ShortForm, FloatReg, 0, 0}, +{"fdiv", 2, 0xd8f0, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fdiv", 2, 0xdcf8, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fdiv", 2, 0xdcf0, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fdiv", 0, 0xdcf1, _, NoModrm, 0, 0, 0}, +{"fdivp", 1, 0xdaf0, _, ShortForm, FloatReg, 0, 0}, +{"fdivp", 2, 0xdaf0, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fdivp", 2, 0xdef8, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fdivp", 2, 0xdef0, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fdivp", 0, 0xdef1, _, NoModrm, 0, 0, 0}, +{"fdivs", 1, 0xd8, 6, Modrm, Mem, 0, 0}, +{"fidivl", 1, 0xda, 6, Modrm, Mem, 0, 0}, +{"fdivl", 1, 0xdc, 6, Modrm, Mem, 0, 0}, +{"fidivs", 1, 0xde, 6, Modrm, Mem, 0, 0}, + +/* div reverse */ +{"fdivr", 1, 0xd8f8, _, ShortForm, FloatReg, 0, 0}, +{"fdivr", 2, 0xd8f8, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fdivr", 2, 0xdcf0, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fdivr", 2, 0xdcf8, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fdivr", 0, 0xdcf9, _, NoModrm, 0, 0, 0}, +{"fdivrp", 1, 0xdaf8, _, ShortForm, FloatReg, 0, 0}, +{"fdivrp", 2, 0xdaf8, _, ShortForm, FloatReg, FloatAcc, 0}, +#ifdef NON_BROKEN_OPCODES +{"fdivrp", 2, 0xdef0, _, ShortForm, FloatAcc, FloatReg, 0}, +#else +{"fdivrp", 2, 0xdef8, _, ShortForm, FloatAcc, FloatReg, 0}, +#endif +{"fdivrp", 0, 0xdef9, _, NoModrm, 0, 0, 0}, +{"fdivrs", 1, 0xd8, 7, Modrm, Mem, 0, 0}, +{"fidivrl", 1, 0xda, 7, Modrm, Mem, 0, 0}, +{"fdivrl", 1, 0xdc, 7, Modrm, Mem, 0, 0}, +{"fidivrs", 1, 0xde, 7, Modrm, Mem, 0, 0}, + +{"f2xm1", 0, 0xd9f0, _, NoModrm, 0, 0, 0}, +{"fyl2x", 0, 0xd9f1, _, NoModrm, 0, 0, 0}, +{"fptan", 0, 0xd9f2, _, NoModrm, 0, 0, 0}, +{"fpatan", 0, 0xd9f3, _, NoModrm, 0, 0, 0}, +{"fxtract", 0, 0xd9f4, _, NoModrm, 0, 0, 0}, +{"fprem1", 0, 0xd9f5, _, NoModrm, 0, 0, 0}, +{"fdecstp", 0, 0xd9f6, _, NoModrm, 0, 0, 0}, +{"fincstp", 0, 0xd9f7, _, NoModrm, 0, 0, 0}, +{"fprem", 0, 0xd9f8, _, NoModrm, 0, 0, 0}, +{"fyl2xp1", 0, 0xd9f9, _, NoModrm, 0, 0, 0}, +{"fsqrt", 0, 0xd9fa, _, NoModrm, 0, 0, 0}, +{"fsincos", 0, 0xd9fb, _, NoModrm, 0, 0, 0}, +{"frndint", 0, 0xd9fc, _, NoModrm, 0, 0, 0}, +{"fscale", 0, 0xd9fd, _, NoModrm, 0, 0, 0}, +{"fsin", 0, 0xd9fe, _, NoModrm, 0, 0, 0}, +{"fcos", 0, 0xd9ff, _, NoModrm, 0, 0, 0}, + +{"fchs", 0, 0xd9e0, _, NoModrm, 0, 0, 0}, +{"fabs", 0, 0xd9e1, _, NoModrm, 0, 0, 0}, + +/* processor control */ +{"fninit", 0, 0xdbe3, _, NoModrm, 0, 0, 0}, +{"finit", 0, 0xdbe3, _, NoModrm, 0, 0, 0}, +{"fldcw", 1, 0xd9, 5, Modrm, Mem, 0, 0}, +{"fnstcw", 1, 0xd9, 7, Modrm, Mem, 0, 0}, +{"fstcw", 1, 0xd9, 7, Modrm, Mem, 0, 0}, +{"fnstsw", 1, 0xdfe0, _, NoModrm, Acc, 0, 0}, +{"fnstsw", 1, 0xdd, 7, Modrm, Mem, 0, 0}, +{"fnstsw", 0, 0xdfe0, _, NoModrm, 0, 0, 0}, +{"fstsw", 1, 0xdfe0, _, NoModrm, Acc, 0, 0}, +{"fstsw", 1, 0xdd, 7, Modrm, Mem, 0, 0}, +{"fstsw", 0, 0xdfe0, _, NoModrm, 0, 0, 0}, +{"fnclex", 0, 0xdbe2, _, NoModrm, 0, 0, 0}, +{"fclex", 0, 0xdbe2, _, NoModrm, 0, 0, 0}, +/* + We ignore the short format (287) versions of fstenv/fldenv & fsave/frstor + instructions; i'm not sure how to add them or how they are different. + My 386/387 book offers no details about this. +*/ +{"fnstenv", 1, 0xd9, 6, Modrm, Mem, 0, 0}, +{"fstenv", 1, 0xd9, 6, Modrm, Mem, 0, 0}, +{"fldenv", 1, 0xd9, 4, Modrm, Mem, 0, 0}, +{"fnsave", 1, 0xdd, 6, Modrm, Mem, 0, 0}, +{"fsave", 1, 0xdd, 6, Modrm, Mem, 0, 0}, +{"frstor", 1, 0xdd, 4, Modrm, Mem, 0, 0}, + +{"ffree", 1, 0xddc0, _, ShortForm, FloatReg, 0, 0}, +{"fnop", 0, 0xd9d0, _, NoModrm, 0, 0, 0}, +{"fwait", 0, 0x9b, _, NoModrm, 0, 0, 0}, + +/* + opcode prefixes; we allow them as seperate insns too + (see prefix table below) +*/ +{"aword", 0, 0x67, _, NoModrm, 0, 0, 0}, +{"word", 0, 0x66, _, NoModrm, 0, 0, 0}, +{"lock", 0, 0xf0, _, NoModrm, 0, 0, 0}, +{"cs", 0, 0x2e, _, NoModrm, 0, 0, 0}, +{"ds", 0, 0x3e, _, NoModrm, 0, 0, 0}, +{"es", 0, 0x26, _, NoModrm, 0, 0, 0}, +{"fs", 0, 0x64, _, NoModrm, 0, 0, 0}, +{"gs", 0, 0x65, _, NoModrm, 0, 0, 0}, +{"ss", 0, 0x36, _, NoModrm, 0, 0, 0}, +{"rep", 0, 0xf3, _, NoModrm, 0, 0, 0}, +{"repe", 0, 0xf3, _, NoModrm, 0, 0, 0}, +{ "repne", 0, 0xf2, _, NoModrm, 0, 0, 0}, + +{"", 0, 0, 0, 0, 0, 0, 0} /* sentinal */ +}; +#undef _ + +template *i386_optab_end + = i386_optab + sizeof (i386_optab)/sizeof(i386_optab[0]); + +/* 386 register table */ + +reg_entry i386_regtab[] = { + /* 8 bit regs */ + {"al", Reg8|Acc, 0}, {"cl", Reg8|ShiftCount, 1}, {"dl", Reg8, 2}, + {"bl", Reg8, 3}, + {"ah", Reg8, 4}, {"ch", Reg8, 5}, {"dh", Reg8, 6}, {"bh", Reg8, 7}, + /* 16 bit regs */ + {"ax", Reg16|Acc, 0}, {"cx", Reg16, 1}, {"dx", Reg16|InOutPortReg, 2}, {"bx", Reg16, 3}, + {"sp", Reg16, 4}, {"bp", Reg16, 5}, {"si", Reg16, 6}, {"di", Reg16, 7}, + /* 32 bit regs */ + {"eax", Reg32|Acc, 0}, {"ecx", Reg32, 1}, {"edx", Reg32, 2}, {"ebx", Reg32, 3}, + {"esp", Reg32, 4}, {"ebp", Reg32, 5}, {"esi", Reg32, 6}, {"edi", Reg32, 7}, + /* segment registers */ + {"es", SReg2, 0}, {"cs", SReg2, 1}, {"ss", SReg2, 2}, + {"ds", SReg2, 3}, {"fs", SReg3, 4}, {"gs", SReg3, 5}, + /* control registers */ + {"cr0", Control, 0}, {"cr2", Control, 2}, {"cr3", Control, 3}, + /* debug registers */ + {"db0", Debug, 0}, {"db1", Debug, 1}, {"db2", Debug, 2}, + {"db3", Debug, 3}, {"db6", Debug, 6}, {"db7", Debug, 7}, + /* test registers */ + {"tr6", Test, 6}, {"tr7", Test, 7}, + /* float registers */ + {"st(0)", FloatReg|FloatAcc, 0}, + {"st", FloatReg|FloatAcc, 0}, + {"st(1)", FloatReg, 1}, {"st(2)", FloatReg, 2}, + {"st(3)", FloatReg, 3}, {"st(4)", FloatReg, 4}, {"st(5)", FloatReg, 5}, + {"st(6)", FloatReg, 6}, {"st(7)", FloatReg, 7} +}; + +#define MAX_REG_NAME_SIZE 8 /* for parsing register names from input */ + +reg_entry *i386_regtab_end + = i386_regtab + sizeof(i386_regtab)/sizeof(i386_regtab[0]); + +/* segment stuff */ +seg_entry cs = { "cs", 0x2e }; +seg_entry ds = { "ds", 0x3e }; +seg_entry ss = { "ss", 0x36 }; +seg_entry es = { "es", 0x26 }; +seg_entry fs = { "fs", 0x64 }; +seg_entry gs = { "gs", 0x65 }; +seg_entry null = { "", 0x0 }; + +/* + This table is used to store the default segment register implied by all + possible memory addressing modes. + It is indexed by the mode & modrm entries of the modrm byte as follows: + index = (mode<<3) | modrm; +*/ +seg_entry *one_byte_segment_defaults[] = { + /* mode 0 */ + &ds, &ds, &ds, &ds, &null, &ds, &ds, &ds, + /* mode 1 */ + &ds, &ds, &ds, &ds, &null, &ss, &ds, &ds, + /* mode 2 */ + &ds, &ds, &ds, &ds, &null, &ss, &ds, &ds, + /* mode 3 --- not a memory reference; never referenced */ +}; + +seg_entry *two_byte_segment_defaults[] = { + /* mode 0 */ + &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds, + /* mode 1 */ + &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds, + /* mode 2 */ + &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds, + /* mode 3 --- not a memory reference; never referenced */ +}; + +prefix_entry i386_prefixtab[] = { + { "addr16", 0x67 }, /* address size prefix ==> 16bit addressing + * (How is this useful?) */ +#define WORD_PREFIX_OPCODE 0x66 + { "data16", 0x66 }, /* operand size prefix */ + { "lock", 0xf0 }, /* bus lock prefix */ + { "wait", 0x9b }, /* wait for coprocessor */ + { "cs", 0x2e }, { "ds", 0x3e }, /* segment overrides ... */ + { "es", 0x26 }, { "fs", 0x64 }, + { "gs", 0x65 }, { "ss", 0x36 }, +/* REPE & REPNE used to detect rep/repne with a non-string instruction */ +#define REPNE 0xf2 +#define REPE 0xf3 + { "rep", 0xf3 }, { "repe", 0xf3 }, /* repeat string instructions */ + { "repne", 0xf2 } +}; + +prefix_entry *i386_prefixtab_end + = i386_prefixtab + sizeof(i386_prefixtab)/sizeof(i386_prefixtab[0]); + diff --git a/gnu/usr.bin/as/config/i386.c b/gnu/usr.bin/as/config/i386.c new file mode 100644 index 0000000..2281acd --- /dev/null +++ b/gnu/usr.bin/as/config/i386.c @@ -0,0 +1,1946 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + */ + +#ifndef lint +static char sccsid[] = "@(#)i386.c 6.4 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* i386.c -- Assemble code for the Intel 80386 + Copyright (C) 1989, Free Software Foundation. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + Intel 80386 machine specific gas. + Written by Eliot Dresselhaus (eliot@mgm.mit.edu). + Bugs & suggestions are completely welcome. This is free software. + Please help us make it better. +*/ + +#include <stdio.h> +#include <varargs.h> +#include <ctype.h> + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +extern char *alloca(); +#endif +#ifdef USG +#define index strchr +#endif + +#include "as.h" +#include "read.h" +#include "flonum.h" +#include "obstack.h" +#include "frags.h" +#include "struc-symbol.h" +#include "expr.h" +#include "symbols.h" +#include "hash.h" +#include "md.h" +#include "i386.h" +#include "i386-opcode.h" + +long omagic = OMAGIC; +char FLT_CHARS[] = "fFdDxX"; +char EXP_CHARS[] = "eE"; +char line_comment_chars[] = "#"; +char comment_chars[] = "#"; + +/* tables for lexical analysis */ +static char opcode_chars[256]; +static char register_chars[256]; +static char operand_chars[256]; +static char space_chars[256]; +static char identifier_chars[256]; +static char digit_chars[256]; + +/* lexical macros */ +#define is_opcode_char(x) (opcode_chars[(unsigned char) x]) +#define is_operand_char(x) (operand_chars[(unsigned char) x]) +#define is_register_char(x) (register_chars[(unsigned char) x]) +#define is_space_char(x) (space_chars[(unsigned char) x]) +#define is_identifier_char(x) (identifier_chars[(unsigned char) x]) +#define is_digit_char(x) (digit_chars[(unsigned char) x]) + +/* put here all non-digit non-letter charcters that may occur in an operand */ +static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:"; + +static char *ordinal_names[] = { "first", "second", "third" }; /* for printfs */ + +/* md_assemble() always leaves the strings it's passed unaltered. To + effect this we maintain a stack of saved characters that we've smashed + with '\0's (indicating end of strings for various sub-fields of the + assembler instruction). */ +static char save_stack[32]; +static char *save_stack_p; /* stack pointer */ +#define END_STRING_AND_SAVE(s) *save_stack_p++ = *s; *s = '\0' +#define RESTORE_END_STRING(s) *s = *--save_stack_p + +/* The instruction we're assembling. */ +static i386_insn i; + +/* Per instruction expressionS buffers: 2 displacements & 2 immediate max. */ +static expressionS disp_expressions[2], im_expressions[2]; + +/* pointers to ebp & esp entries in reg_hash hash table */ +static reg_entry *ebp, *esp; + +static int this_operand; /* current operand we are working on */ + +/* +Interface to relax_segment. +There are 2 relax states for 386 jump insns: one for conditional & one +for unconditional jumps. This is because the these two types of jumps +add different sizes to frags when we're figuring out what sort of jump +to choose to reach a given label. */ + +/* types */ +#define COND_JUMP 1 /* conditional jump */ +#define UNCOND_JUMP 2 /* unconditional jump */ +/* sizes */ +#define BYTE 0 +#define WORD 1 +#define DWORD 2 +#define UNKNOWN_SIZE 3 + +#define ENCODE_RELAX_STATE(type,size) ((type<<2) | (size)) +#define SIZE_FROM_RELAX_STATE(s) \ + ( (((s) & 0x3) == BYTE ? 1 : (((s) & 0x3) == WORD ? 2 : 4)) ) + +const relax_typeS md_relax_table[] = { +/* + The fields are: + 1) most positive reach of this state, + 2) most negative reach of this state, + 3) how many bytes this mode will add to the size of the current frag + 4) which index into the table to try if we can't fit into this one. +*/ + {1, 1, 0, 0}, + {1, 1, 0, 0}, + {1, 1, 0, 0}, + {1, 1, 0, 0}, + + /* For now we don't use word displacement jumps: they may be + untrustworthy. */ + {127+1, -128+1, 0, ENCODE_RELAX_STATE(COND_JUMP,DWORD) }, + /* word conditionals add 3 bytes to frag: + 2 opcode prefix; 1 displacement bytes */ + {32767+2, -32768+2, 3, ENCODE_RELAX_STATE(COND_JUMP,DWORD) }, + /* dword conditionals adds 4 bytes to frag: + 1 opcode prefix; 3 displacement bytes */ + {0, 0, 4, 0}, + {1, 1, 0, 0}, + + {127+1, -128+1, 0, ENCODE_RELAX_STATE(UNCOND_JUMP,DWORD) }, + /* word jmp adds 2 bytes to frag: + 1 opcode prefix; 1 displacement bytes */ + {32767+2, -32768+2, 2, ENCODE_RELAX_STATE(UNCOND_JUMP,DWORD) }, + /* dword jmp adds 3 bytes to frag: + 0 opcode prefix; 3 displacement bytes */ + {0, 0, 3, 0}, + {1, 1, 0, 0}, + +}; + +void float_cons (), cons (); + +/* Ignore certain directives generated by gcc. This probably should + not be here. */ +void dummy () +{ + while (*input_line_pointer && *input_line_pointer != '\n') + input_line_pointer++; +} + +const pseudo_typeS md_pseudo_table[] = { + { "ffloat", float_cons, 'f' }, + { "dfloat", float_cons, 'd' }, + { "tfloat", float_cons, 'x' }, + { "value", cons, 2 }, + { "ident", dummy, 0 }, /* ignore these directives */ + { "def", dummy, 0 }, + { "optim", dummy, 0 }, /* For sun386i cc */ + { "version", dummy, 0 }, + { "ln", dummy, 0 }, + { 0, 0, 0 } +}; + +/* for interface with expression () */ +extern char * input_line_pointer; +char * index (); + +char * output_invalid (); +reg_entry * parse_register (); + +/* obstack for constructing various things in md_begin */ +struct obstack o; + +/* hash table for opcode lookup */ +static struct hash_control *op_hash = (struct hash_control *) 0; +/* hash table for register lookup */ +static struct hash_control *reg_hash = (struct hash_control *) 0; +/* hash table for prefix lookup */ +static struct hash_control *prefix_hash = (struct hash_control *) 0; + + +void md_begin () +{ + char * hash_err; + + obstack_begin (&o,4096); + + /* initialize op_hash hash table */ + op_hash = hash_new(); /* xmalloc handles error */ + + { + register template *optab; + register templates *core_optab; + char *prev_name; + + optab = i386_optab; /* setup for loop */ + prev_name = optab->name; + obstack_grow (&o, optab, sizeof(template)); + core_optab = (templates *) xmalloc (sizeof (templates)); + + for (optab++; optab < i386_optab_end; optab++) { + if (! strcmp (optab->name, prev_name)) { + /* same name as before --> append to current template list */ + obstack_grow (&o, optab, sizeof(template)); + } else { + /* different name --> ship out current template list; + add to hash table; & begin anew */ + /* Note: end must be set before start! since obstack_next_free changes + upon opstack_finish */ + core_optab->end = (template *) obstack_next_free(&o); + core_optab->start = (template *) obstack_finish(&o); + hash_err = hash_insert (op_hash, prev_name, (char *) core_optab); + if (hash_err && *hash_err) { + hash_error: + as_fatal("Internal Error: Can't hash %s: %s",prev_name, hash_err); + } + prev_name = optab->name; + core_optab = (templates *) xmalloc (sizeof(templates)); + obstack_grow (&o, optab, sizeof(template)); + } + } + } + + /* initialize reg_hash hash table */ + reg_hash = hash_new(); + { + register reg_entry *regtab; + + for (regtab = i386_regtab; regtab < i386_regtab_end; regtab++) { + hash_err = hash_insert (reg_hash, regtab->reg_name, regtab); + if (hash_err && *hash_err) goto hash_error; + } + } + + esp = (reg_entry *) hash_find (reg_hash, "esp"); + ebp = (reg_entry *) hash_find (reg_hash, "ebp"); + + /* initialize reg_hash hash table */ + prefix_hash = hash_new(); + { + register prefix_entry *prefixtab; + + for (prefixtab = i386_prefixtab; + prefixtab < i386_prefixtab_end; prefixtab++) { + hash_err = hash_insert (prefix_hash, prefixtab->prefix_name, prefixtab); + if (hash_err && *hash_err) goto hash_error; + } + } + + /* fill in lexical tables: opcode_chars, operand_chars, space_chars */ + { + register unsigned int c; + + bzero (opcode_chars, sizeof(opcode_chars)); + bzero (operand_chars, sizeof(operand_chars)); + bzero (space_chars, sizeof(space_chars)); + bzero (identifier_chars, sizeof(identifier_chars)); + bzero (digit_chars, sizeof(digit_chars)); + + for (c = 0; c < 256; c++) { + if (islower(c) || isdigit(c)) { + opcode_chars[c] = c; + register_chars[c] = c; + } else if (isupper(c)) { + opcode_chars[c] = tolower(c); + register_chars[c] = opcode_chars[c]; + } else if (c == PREFIX_SEPERATOR) { + opcode_chars[c] = c; + } else if (c == ')' || c == '(') { + register_chars[c] = c; + } + + if (isupper(c) || islower(c) || isdigit(c)) + operand_chars[c] = c; + else if (c && index(operand_special_chars, c)) + operand_chars[c] = c; + + if (isdigit(c) || c == '-') digit_chars[c] = c; + + if (isalpha(c) || c == '_' || c == '.' || isdigit(c)) + identifier_chars[c] = c; + + if (c == ' ' || c == '\t') space_chars[c] = c; + } + } +} + +void md_end() {} /* not much to do here. */ + + +#ifdef DEBUG386 + +/* debugging routines for md_assemble */ +static void pi (), pte (), pt (), pe (), ps (); + +static void pi (line, x) + char * line; + i386_insn *x; +{ + register template *p; + int i; + + fprintf (stdout, "%s: template ", line); + pte (&x->tm); + fprintf (stdout, " modrm: mode %x reg %x reg/mem %x", + x->rm.mode, x->rm.reg, x->rm.regmem); + fprintf (stdout, " base %x index %x scale %x\n", + x->bi.base, x->bi.index, x->bi.scale); + for (i = 0; i < x->operands; i++) { + fprintf (stdout, " #%d: ", i+1); + pt (x->types[i]); + fprintf (stdout, "\n"); + if (x->types[i] & Reg) fprintf (stdout, "%s\n", x->regs[i]->reg_name); + if (x->types[i] & Imm) pe (x->imms[i]); + if (x->types[i] & (Disp|Abs)) pe (x->disps[i]); + } +} + +static void pte (t) + template *t; +{ + int i; + fprintf (stdout, " %d operands ", t->operands); + fprintf (stdout, "opcode %x ", + t->base_opcode); + if (t->extension_opcode != None) + fprintf (stdout, "ext %x ", t->extension_opcode); + if (t->opcode_modifier&D) + fprintf (stdout, "D"); + if (t->opcode_modifier&W) + fprintf (stdout, "W"); + fprintf (stdout, "\n"); + for (i = 0; i < t->operands; i++) { + fprintf (stdout, " #%d type ", i+1); + pt (t->operand_types[i]); + fprintf (stdout, "\n"); + } +} + +char *seg_names[] = { +"SEG_ABSOLUTE", "SEG_TEXT", "SEG_DATA", "SEG_BSS", "SEG_UNKNOWN", +"SEG_NONE", "SEG_PASS1", "SEG_GOOF", "SEG_BIG", "SEG_DIFFERENCE" }; + +static void pe (e) + expressionS *e; +{ + fprintf (stdout, " segment %s\n", seg_names[(int) e->X_seg]); + fprintf (stdout, " add_number %d (%x)\n", + e->X_add_number, e->X_add_number); + if (e->X_add_symbol) { + fprintf (stdout, " add_symbol "); + ps (e->X_add_symbol); + fprintf (stdout, "\n"); + } + if (e->X_subtract_symbol) { + fprintf (stdout, " sub_symbol "); + ps (e->X_subtract_symbol); + fprintf (stdout, "\n"); + } +} + +#define SYMBOL_TYPE(t) \ + (((t&N_TYPE) == N_UNDF) ? "UNDEFINED" : \ + (((t&N_TYPE) == N_ABS) ? "ABSOLUTE" : \ + (((t&N_TYPE) == N_TEXT) ? "TEXT" : \ + (((t&N_TYPE) == N_DATA) ? "DATA" : \ + (((t&N_TYPE) == N_BSS) ? "BSS" : "Bad n_type!"))))) + +static void ps (s) + symbolS *s; +{ + fprintf (stdout, "%s type %s%s", + s->sy_nlist.n_un.n_name, + (s->sy_nlist.n_type&N_EXT) ? "EXTERNAL " : "", + SYMBOL_TYPE (s->sy_nlist.n_type)); +} + +struct type_name { + uint mask; + char *tname; +} type_names[] = { + { Reg8, "r8" }, { Reg16, "r16" }, { Reg32, "r32" }, { Imm8, "i8" }, + { Imm8S, "i8s" }, + { Imm16, "i16" }, { Imm32, "i32" }, { Mem8, "Mem8"}, { Mem16, "Mem16"}, + { Mem32, "Mem32"}, { BaseIndex, "BaseIndex" }, + { Abs8, "Abs8" }, { Abs16, "Abs16" }, { Abs32, "Abs32" }, + { Disp8, "d8" }, { Disp16, "d16" }, + { Disp32, "d32" }, { SReg2, "SReg2" }, { SReg3, "SReg3" }, { Acc, "Acc" }, + { InOutPortReg, "InOutPortReg" }, { ShiftCount, "ShiftCount" }, + { Imm1, "i1" }, { Control, "control reg" }, {Test, "test reg"}, + { FloatReg, "FReg"}, {FloatAcc, "FAcc"}, + { JumpAbsolute, "Jump Absolute"}, + { 0, "" } +}; + +static void pt (t) + uint t; +{ + register struct type_name *ty; + + if (t == Unknown) { + fprintf (stdout, "Unknown"); + } else { + for (ty = type_names; ty->mask; ty++) + if (t & ty->mask) fprintf (stdout, "%s, ", ty->tname); + } + fflush (stdout); +} + +#endif /* DEBUG386 */ + +/* + This is the guts of the machine-dependent assembler. LINE points to a + machine dependent instruction. This funciton is supposed to emit + the frags/bytes it assembles to. + */ +void md_assemble (line) + char *line; +{ + /* Holds temlate once we've found it. */ + register template * t; + + /* Possible templates for current insn */ + templates *current_templates = (templates *) 0; + + /* Initialize globals. */ + bzero (&i, sizeof(i)); + bzero (disp_expressions, sizeof(disp_expressions)); + bzero (im_expressions, sizeof(im_expressions)); + save_stack_p = save_stack; /* reset stack pointer */ + + /* Fist parse an opcode & call i386_operand for the operands. + We assume that the scrubber has arranged it so that line[0] is the valid + start of a (possibly prefixed) opcode. */ + { + register char *l = line; /* Fast place to put LINE. */ + + /* TRUE if operand is pending after ','. */ + uint expecting_operand = 0; + /* TRUE if we found a prefix only acceptable with string insns. */ + uint expecting_string_instruction = 0; + /* Non-zero if operand parens not balenced. */ + uint paren_not_balenced; + char * token_start = l; + + while (! is_space_char(*l) && *l != END_OF_INSN) { + if (! is_opcode_char(*l)) { + as_bad ("invalid character %s in opcode", output_invalid(*l)); + return; + } else if (*l != PREFIX_SEPERATOR) { + *l = opcode_chars[(unsigned char) *l]; /* fold case of opcodes */ + l++; + } else { /* this opcode's got a prefix */ + register int q; + register prefix_entry * prefix; + + if (l == token_start) { + as_bad ("expecting prefix; got nothing"); + return; + } + END_STRING_AND_SAVE (l); + prefix = (prefix_entry *) hash_find (prefix_hash, token_start); + if (! prefix) { + as_bad ("no such opcode prefix ('%s')", token_start); + return; + } + RESTORE_END_STRING (l); + /* check for repeated prefix */ + for (q = 0; q < i.prefixes; q++) + if (i.prefix[q] == prefix->prefix_code) { + as_bad ("same prefix used twice; you don't really want this!"); + return; + } + if (i.prefixes == MAX_PREFIXES) { + as_bad ("too many opcode prefixes"); + return; + } + i.prefix[i.prefixes++] = prefix->prefix_code; + if (prefix->prefix_code == REPE || prefix->prefix_code == REPNE) + expecting_string_instruction = TRUE; + /* skip past PREFIX_SEPERATOR and reset token_start */ + token_start = ++l; + } + } + END_STRING_AND_SAVE (l); + if (token_start == l) { + as_bad ("expecting opcode; got nothing"); + return; + } + + /* Lookup insn in hash; try intel & att naming conventions if appropriate; + that is: we only use the opcode suffix 'b' 'w' or 'l' if we need to. */ + current_templates = (templates *) hash_find (op_hash, token_start); + if (! current_templates) { + int last_index = strlen(token_start) - 1; + char last_char = token_start[last_index]; + switch (last_char) { + case DWORD_OPCODE_SUFFIX: + case WORD_OPCODE_SUFFIX: + case BYTE_OPCODE_SUFFIX: + token_start[last_index] = '\0'; + current_templates = (templates *) hash_find (op_hash, token_start); + token_start[last_index] = last_char; + i.suffix = last_char; + } + if (!current_templates) { + as_bad ("no such 386 instruction: `%s'", token_start); return; + } + } + RESTORE_END_STRING (l); + + /* check for rep/repne without a string instruction */ + if (expecting_string_instruction && + ! IS_STRING_INSTRUCTION (current_templates-> + start->base_opcode)) { + as_bad ("expecting string instruction after rep/repne"); + return; + } + + /* There may be operands to parse. */ + if (*l != END_OF_INSN && + /* For string instructions, we ignore any operands if given. This + kludges, for example, 'rep/movsb %ds:(%esi), %es:(%edi)' where + the operands are always going to be the same, and are not really + encoded in machine code. */ + ! IS_STRING_INSTRUCTION (current_templates-> + start->base_opcode)) { + /* parse operands */ + do { + /* skip optional white space before operand */ + while (! is_operand_char(*l) && *l != END_OF_INSN) { + if (! is_space_char(*l)) { + as_bad ("invalid character %s before %s operand", + output_invalid(*l), + ordinal_names[i.operands]); + return; + } + l++; + } + token_start = l; /* after white space */ + paren_not_balenced = 0; + while (paren_not_balenced || *l != ',') { + if (*l == END_OF_INSN) { + if (paren_not_balenced) { + as_bad ("unbalenced parenthesis in %s operand.", + ordinal_names[i.operands]); + return; + } else break; /* we are done */ + } else if (! is_operand_char(*l)) { + as_bad ("invalid character %s in %s operand", + output_invalid(*l), + ordinal_names[i.operands]); + return; + } + if (*l == '(') ++paren_not_balenced; + if (*l == ')') --paren_not_balenced; + l++; + } + if (l != token_start) { /* yes, we've read in another operand */ + uint operand_ok; + this_operand = i.operands++; + if (i.operands > MAX_OPERANDS) { + as_bad ("spurious operands; (%d operands/instruction max)", + MAX_OPERANDS); + return; + } + /* now parse operand adding info to 'i' as we go along */ + END_STRING_AND_SAVE (l); + operand_ok = i386_operand (token_start); + RESTORE_END_STRING (l); /* restore old contents */ + if (!operand_ok) return; + } else { + if (expecting_operand) { + expecting_operand_after_comma: + as_bad ("expecting operand after ','; got nothing"); + return; + } + if (*l == ',') { + as_bad ("expecting operand before ','; got nothing"); + return; + } + } + + /* now *l must be either ',' or END_OF_INSN */ + if (*l == ',') { + if (*++l == END_OF_INSN) { /* just skip it, if it's \n complain */ + goto expecting_operand_after_comma; + } + expecting_operand = TRUE; + } + } while (*l != END_OF_INSN); /* until we get end of insn */ + } + } + + /* Now we've parsed the opcode into a set of templates, and have the + operands at hand. + Next, we find a template that matches the given insn, + making sure the overlap of the given operands types is consistent + with the template operand types. */ + +#define MATCH(overlap,given_type) \ + (overlap && \ + (overlap & (JumpAbsolute|BaseIndex|Mem8)) \ + == (given_type & (JumpAbsolute|BaseIndex|Mem8))) + + /* If m0 and m1 are register matches they must be consistent + with the expected operand types t0 and t1. + That is, if both m0 & m1 are register matches + i.e. ( ((m0 & (Reg)) && (m1 & (Reg)) ) ? + then, either 1. or 2. must be true: + 1. the expected operand type register overlap is null: + (t0 & t1 & Reg) == 0 + AND + the given register overlap is null: + (m0 & m1 & Reg) == 0 + 2. the expected operand type register overlap == the given + operand type overlap: (t0 & t1 & m0 & m1 & Reg). + */ +#define CONSISTENT_REGISTER_MATCH(m0, m1, t0, t1) \ + ( ((m0 & (Reg)) && (m1 & (Reg))) ? \ + ( ((t0 & t1 & (Reg)) == 0 && (m0 & m1 & (Reg)) == 0) || \ + ((t0 & t1) & (m0 & m1) & (Reg)) \ + ) : 1) + { + register uint overlap0, overlap1; + expressionS * exp; + uint overlap2; + uint found_reverse_match; + + overlap0 = overlap1 = overlap2 = found_reverse_match = 0; + for (t = current_templates->start; + t < current_templates->end; + t++) { + + /* must have right number of operands */ + if (i.operands != t->operands) continue; + else if (!t->operands) break; /* 0 operands always matches */ + + overlap0 = i.types[0] & t->operand_types[0]; + switch (t->operands) { + case 1: + if (! MATCH (overlap0,i.types[0])) continue; + break; + case 2: case 3: + overlap1 = i.types[1] & t->operand_types[1]; + if (! MATCH (overlap0,i.types[0]) || + ! MATCH (overlap1,i.types[1]) || + ! CONSISTENT_REGISTER_MATCH(overlap0, overlap1, + t->operand_types[0], + t->operand_types[1])) { + + /* check if other direction is valid ... */ + if (! (t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS)) + continue; + + /* try reversing direction of operands */ + overlap0 = i.types[0] & t->operand_types[1]; + overlap1 = i.types[1] & t->operand_types[0]; + if (! MATCH (overlap0,i.types[0]) || + ! MATCH (overlap1,i.types[1]) || + ! CONSISTENT_REGISTER_MATCH (overlap0, overlap1, + t->operand_types[0], + t->operand_types[1])) { + /* does not match either direction */ + continue; + } + /* found a reverse match here -- slip through */ + /* found_reverse_match holds which of D or FloatD we've found */ + found_reverse_match = t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS; + } /* endif: not forward match */ + /* found either forward/reverse 2 operand match here */ + if (t->operands == 3) { + overlap2 = i.types[2] & t->operand_types[2]; + if (! MATCH (overlap2,i.types[2]) || + ! CONSISTENT_REGISTER_MATCH (overlap0, overlap2, + t->operand_types[0], + t->operand_types[2]) || + ! CONSISTENT_REGISTER_MATCH (overlap1, overlap2, + t->operand_types[1], + t->operand_types[2])) + continue; + } + /* found either forward/reverse 2 or 3 operand match here: + slip through to break */ + } + break; /* we've found a match; break out of loop */ + } /* for (t = ... */ + if (t == current_templates->end) { /* we found no match */ + as_bad ("operands given don't match any known 386 instruction"); + return; + } + + /* Copy the template we found (we may change it!). */ + bcopy (t, &i.tm, sizeof (template)); + t = &i.tm; /* alter new copy of template */ + + /* If there's no opcode suffix we try to invent one based on register + operands. */ + if (! i.suffix && i.reg_operands) { + /* We take i.suffix from the LAST register operand specified. This + assumes that the last register operands is the destination register + operand. */ + int o; + for (o = 0; o < MAX_OPERANDS; o++) + if (i.types[o] & Reg) { + i.suffix = (i.types[o] == Reg8) ? BYTE_OPCODE_SUFFIX : + (i.types[o] == Reg16) ? WORD_OPCODE_SUFFIX : + DWORD_OPCODE_SUFFIX; + } + } + + /* Make still unresolved immediate matches conform to size of immediate + given in i.suffix. Note: overlap2 cannot be an immediate! + We assume this. */ + if ((overlap0 & (Imm8|Imm8S|Imm16|Imm32)) + && overlap0 != Imm8 && overlap0 != Imm8S + && overlap0 != Imm16 && overlap0 != Imm32) { + if (! i.suffix) { + as_bad ("no opcode suffix given; can't determine immediate size"); + return; + } + overlap0 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8|Imm8S) : + (i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32)); + } + if ((overlap1 & (Imm8|Imm8S|Imm16|Imm32)) + && overlap1 != Imm8 && overlap1 != Imm8S + && overlap1 != Imm16 && overlap1 != Imm32) { + if (! i.suffix) { + as_bad ("no opcode suffix given; can't determine immediate size"); + return; + } + overlap1 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8|Imm8S) : + (i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32)); + } + + i.types[0] = overlap0; + i.types[1] = overlap1; + i.types[2] = overlap2; + + if (overlap0 & ImplicitRegister) i.reg_operands--; + if (overlap1 & ImplicitRegister) i.reg_operands--; + if (overlap2 & ImplicitRegister) i.reg_operands--; + if (overlap0 & Imm1) i.imm_operands = 0; /* kludge for shift insns */ + + if (found_reverse_match) { + uint save; + save = t->operand_types[0]; + t->operand_types[0] = t->operand_types[1]; + t->operand_types[1] = save; + } + + /* Finalize opcode. First, we change the opcode based on the operand + size given by i.suffix: we never have to change things for byte insns, + or when no opcode suffix is need to size the operands. */ + + if (! i.suffix && (t->opcode_modifier & W)) { + as_bad ("no opcode suffix given and no register operands; can't size instruction"); + return; + } + + if (i.suffix && i.suffix != BYTE_OPCODE_SUFFIX) { + /* Select between byte and word/dword operations. */ + if (t->opcode_modifier & W) + t->base_opcode |= W; + /* Now select between word & dword operations via the + operand size prefix. */ + if (i.suffix == WORD_OPCODE_SUFFIX) { + if (i.prefixes == MAX_PREFIXES) { + as_bad ("%d prefixes given and 'w' opcode suffix gives too many prefixes", + MAX_PREFIXES); + return; + } + i.prefix[i.prefixes++] = WORD_PREFIX_OPCODE; + } + } + + /* For insns with operands there are more diddles to do to the opcode. */ + if (i.operands) { + /* If we found a reverse match we must alter the opcode direction bit + found_reverse_match holds bit to set (different for int & + float insns). */ + + if (found_reverse_match) { + t->base_opcode |= found_reverse_match; + } + + /* + The imul $imm, %reg instruction is converted into + imul $imm, %reg, %reg. */ + if (t->opcode_modifier & imulKludge) { + i.regs[2] = i.regs[1]; /* Pretend we saw the 3 operand case. */ + i.reg_operands = 2; + } + + /* Certain instructions expect the destination to be in the i.rm.reg + field. This is by far the exceptional case. For these instructions, + if the source operand is a register, we must reverse the i.rm.reg + and i.rm.regmem fields. We accomplish this by faking that the + two register operands were given in the reverse order. */ + if ((t->opcode_modifier & ReverseRegRegmem) && i.reg_operands == 2) { + uint first_reg_operand = (i.types[0] & Reg) ? 0 : 1; + uint second_reg_operand = first_reg_operand + 1; + reg_entry *tmp = i.regs[first_reg_operand]; + i.regs[first_reg_operand] = i.regs[second_reg_operand]; + i.regs[second_reg_operand] = tmp; + } + + if (t->opcode_modifier & ShortForm) { + /* The register or float register operand is in operand 0 or 1. */ + uint o = (i.types[0] & (Reg|FloatReg)) ? 0 : 1; + /* Register goes in low 3 bits of opcode. */ + t->base_opcode |= i.regs[o]->reg_num; + } else if (t->opcode_modifier & ShortFormW) { + /* Short form with 0x8 width bit. Register is always dest. operand */ + t->base_opcode |= i.regs[1]->reg_num; + if (i.suffix == WORD_OPCODE_SUFFIX || + i.suffix == DWORD_OPCODE_SUFFIX) + t->base_opcode |= 0x8; + } else if (t->opcode_modifier & Seg2ShortForm) { + if (t->base_opcode == POP_SEG_SHORT && i.regs[0]->reg_num == 1) { + as_bad ("you can't 'pop cs' on the 386."); + return; + } + t->base_opcode |= (i.regs[0]->reg_num << 3); + } else if (t->opcode_modifier & Seg3ShortForm) { + /* 'push %fs' is 0x0fa0; 'pop %fs' is 0x0fa1. + 'push %gs' is 0x0fa8; 'pop %fs' is 0x0fa9. + So, only if i.regs[0]->reg_num == 5 (%gs) do we need + to change the opcode. */ + if (i.regs[0]->reg_num == 5) + t->base_opcode |= 0x08; + } else if (t->opcode_modifier & Modrm) { + /* The opcode is completed (modulo t->extension_opcode which must + be put into the modrm byte. + Now, we make the modrm & index base bytes based on all the info + we've collected. */ + + /* i.reg_operands MUST be the number of real register operands; + implicit registers do not count. */ + if (i.reg_operands == 2) { + uint source, dest; + source = (i.types[0] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 0 : 1; + dest = source + 1; + i.rm.mode = 3; + /* We must be careful to make sure that all segment/control/test/ + debug registers go into the i.rm.reg field (despite the whether + they are source or destination operands). */ + if (i.regs[dest]->reg_type & (SReg2|SReg3|Control|Debug|Test)) { + i.rm.reg = i.regs[dest]->reg_num; + i.rm.regmem = i.regs[source]->reg_num; + } else { + i.rm.reg = i.regs[source]->reg_num; + i.rm.regmem = i.regs[dest]->reg_num; + } + } else { /* if it's not 2 reg operands... */ + if (i.mem_operands) { + uint fake_zero_displacement = FALSE; + uint o = (i.types[0] & Mem) ? 0 : ((i.types[1] & Mem) ? 1 : 2); + + /* Encode memory operand into modrm byte and base index byte. */ + + if (i.base_reg == esp && ! i.index_reg) { + /* <disp>(%esp) becomes two byte modrm with no index register. */ + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + i.rm.mode = MODE_FROM_DISP_SIZE (i.types[o]); + i.bi.base = ESP_REG_NUM; + i.bi.index = NO_INDEX_REGISTER; + i.bi.scale = 0; /* Must be zero! */ + } else if (i.base_reg == ebp && !i.index_reg) { + if (! (i.types[o] & Disp)) { + /* Must fake a zero byte displacement. + There is no direct way to code '(%ebp)' directly. */ + fake_zero_displacement = TRUE; + /* fake_zero_displacement code does not set this. */ + i.types[o] |= Disp8; + } + i.rm.mode = MODE_FROM_DISP_SIZE (i.types[o]); + i.rm.regmem = EBP_REG_NUM; + } else if (! i.base_reg && (i.types[o] & BaseIndex)) { + /* There are three cases here. + Case 1: '<32bit disp>(,1)' -- indirect absolute. + (Same as cases 2 & 3 with NO index register) + Case 2: <32bit disp> (,<index>) -- no base register with disp + Case 3: (, <index>) --- no base register; + no disp (must add 32bit 0 disp). */ + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + i.rm.mode = 0; /* 32bit mode */ + i.bi.base = NO_BASE_REGISTER; + i.types[o] &= ~Disp; + i.types[o] |= Disp32; /* Must be 32bit! */ + if (i.index_reg) { /* case 2 or case 3 */ + i.bi.index = i.index_reg->reg_num; + i.bi.scale = i.log2_scale_factor; + if (i.disp_operands == 0) + fake_zero_displacement = TRUE; /* case 3 */ + } else { + i.bi.index = NO_INDEX_REGISTER; + i.bi.scale = 0; + } + } else if (i.disp_operands && !i.base_reg && !i.index_reg) { + /* Operand is just <32bit disp> */ + i.rm.regmem = EBP_REG_NUM; + i.rm.mode = 0; + i.types[o] &= ~Disp; + i.types[o] |= Disp32; + } else { + /* It's not a special case; rev'em up. */ + i.rm.regmem = i.base_reg->reg_num; + i.rm.mode = MODE_FROM_DISP_SIZE (i.types[o]); + if (i.index_reg) { + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + i.bi.base = i.base_reg->reg_num; + i.bi.index = i.index_reg->reg_num; + i.bi.scale = i.log2_scale_factor; + if (i.base_reg == ebp && i.disp_operands == 0) { /* pace */ + fake_zero_displacement = TRUE; + i.types[o] |= Disp8; + i.rm.mode = MODE_FROM_DISP_SIZE (i.types[o]); + } + } + } + if (fake_zero_displacement) { + /* Fakes a zero displacement assuming that i.types[o] holds + the correct displacement size. */ + exp = &disp_expressions[i.disp_operands++]; + i.disps[o] = exp; + exp->X_seg = SEG_ABSOLUTE; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_subtract_symbol = (symbolS *) 0; + } + + /* Select the correct segment for the memory operand. */ + if (i.seg) { + uint seg_index; + seg_entry * default_seg; + + if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING) { + seg_index = (i.rm.mode<<3) | i.bi.base; + default_seg = two_byte_segment_defaults [seg_index]; + } else { + seg_index = (i.rm.mode<<3) | i.rm.regmem; + default_seg = one_byte_segment_defaults [seg_index]; + } + /* If the specified segment is not the default, use an + opcode prefix to select it */ + if (i.seg != default_seg) { + if (i.prefixes == MAX_PREFIXES) { + as_bad ("%d prefixes given and %s segment override gives too many prefixes", + MAX_PREFIXES, i.seg->seg_name); + return; + } + i.prefix[i.prefixes++] = i.seg->seg_prefix; + } + } + } + + /* Fill in i.rm.reg or i.rm.regmem field with register operand + (if any) based on t->extension_opcode. Again, we must be careful + to make sure that segment/control/debug/test registers are coded + into the i.rm.reg field. */ + if (i.reg_operands) { + uint o = + (i.types[0] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 0 : + (i.types[1] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 1 : 2; + /* If there is an extension opcode to put here, the register number + must be put into the regmem field. */ + if (t->extension_opcode != None) + i.rm.regmem = i.regs[o]->reg_num; + else i.rm.reg = i.regs[o]->reg_num; + + /* Now, if no memory operand has set i.rm.mode = 0, 1, 2 + we must set it to 3 to indicate this is a register operand + int the regmem field */ + if (! i.mem_operands) i.rm.mode = 3; + } + + /* Fill in i.rm.reg field with extension opcode (if any). */ + if (t->extension_opcode != None) + i.rm.reg = t->extension_opcode; + } + } + } + } + + /* Handle conversion of 'int $3' --> special int3 insn. */ + if (t->base_opcode == INT_OPCODE && i.imms[0]->X_add_number == 3) { + t->base_opcode = INT3_OPCODE; + i.imm_operands = 0; + } + + /* We are ready to output the insn. */ + { + register char * p; + + /* Output jumps. */ + if (t->opcode_modifier & Jump) { + int n = i.disps[0]->X_add_number; + + switch (i.disps[0]->X_seg) { + case SEG_ABSOLUTE: + if (FITS_IN_SIGNED_BYTE (n)) { + p = frag_more (2); + p[0] = t->base_opcode; + p[1] = n; +#if 0 /* leave out 16 bit jumps - pace */ + } else if (FITS_IN_SIGNED_WORD (n)) { + p = frag_more (4); + p[0] = WORD_PREFIX_OPCODE; + p[1] = t->base_opcode; + md_number_to_chars (&p[2], n, 2); +#endif + } else { /* It's an absolute dword displacement. */ + if (t->base_opcode == JUMP_PC_RELATIVE) { /* pace */ + /* unconditional jump */ + p = frag_more (5); + p[0] = 0xe9; + md_number_to_chars (&p[1], n, 4); + } else { + /* conditional jump */ + p = frag_more (6); + p[0] = TWO_BYTE_OPCODE_ESCAPE; + p[1] = t->base_opcode + 0x10; + md_number_to_chars (&p[2], n, 4); + } + } + break; + default: + /* It's a symbol; end frag & setup for relax. + Make sure there are 6 chars left in the current frag; if not + we'll have to start a new one. */ + /* I caught it failing with obstack_room == 6, + so I changed to <= pace */ + if (obstack_room (&frags) <= 6) { + frag_wane(frag_now); + frag_new (0); + } + p = frag_more (1); + p[0] = t->base_opcode; + frag_var (rs_machine_dependent, + 6, /* 2 opcode/prefix + 4 displacement */ + 1, + ((uchar) *p == JUMP_PC_RELATIVE + ? ENCODE_RELAX_STATE (UNCOND_JUMP, BYTE) + : ENCODE_RELAX_STATE (COND_JUMP, BYTE)), + i.disps[0]->X_add_symbol, + n, p); + break; + } + } else if (t->opcode_modifier & (JumpByte|JumpDword)) { + int size = (t->opcode_modifier & JumpByte) ? 1 : 4; + int n = i.disps[0]->X_add_number; + + if (FITS_IN_UNSIGNED_BYTE(t->base_opcode)) { + FRAG_APPEND_1_CHAR (t->base_opcode); + } else { + p = frag_more (2); /* opcode can be at most two bytes */ + /* put out high byte first: can't use md_number_to_chars! */ + *p++ = (t->base_opcode >> 8) & 0xff; + *p = t->base_opcode & 0xff; + } + + p = frag_more (size); + switch (i.disps[0]->X_seg) { + case SEG_ABSOLUTE: + md_number_to_chars (p, n, size); + if (size == 1 && ! FITS_IN_SIGNED_BYTE (n)) { + as_bad ("loop/jecx only takes byte displacement; %d shortened to %d", + n, *p); + } + break; + default: + fix_new (frag_now, p - frag_now->fr_literal, size, + i.disps[0]->X_add_symbol, i.disps[0]->X_subtract_symbol, + i.disps[0]->X_add_number, 1); + break; + } + } else if (t->opcode_modifier & JumpInterSegment) { + p = frag_more (1 + 2 + 4); /* 1 opcode; 2 segment; 4 offset */ + p[0] = t->base_opcode; + if (i.imms[1]->X_seg == SEG_ABSOLUTE) + md_number_to_chars (p + 1, i.imms[1]->X_add_number, 4); + else + fix_new (frag_now, p + 1 - frag_now->fr_literal, 4, + i.imms[1]->X_add_symbol, + i.imms[1]->X_subtract_symbol, + i.imms[1]->X_add_number, 0); + if (i.imms[0]->X_seg != SEG_ABSOLUTE) + as_bad ("can't handle non absolute segment in long call/jmp"); + md_number_to_chars (p + 5, i.imms[0]->X_add_number, 2); + } else { + /* Output normal instructions here. */ + register char *q; + + /* First the prefix bytes. */ + for (q = i.prefix; q < i.prefix + i.prefixes; q++) { + p = frag_more (1); + md_number_to_chars (p, (uint) *q, 1); + } + + /* Now the opcode; be careful about word order here! */ + if (FITS_IN_UNSIGNED_BYTE(t->base_opcode)) { + FRAG_APPEND_1_CHAR (t->base_opcode); + } else if (FITS_IN_UNSIGNED_WORD(t->base_opcode)) { + p = frag_more (2); + /* put out high byte first: can't use md_number_to_chars! */ + *p++ = (t->base_opcode >> 8) & 0xff; + *p = t->base_opcode & 0xff; + } else { /* opcode is either 3 or 4 bytes */ + if (t->base_opcode & 0xff000000) { + p = frag_more (4); + *p++ = (t->base_opcode >> 24) & 0xff; + } else p = frag_more (3); + *p++ = (t->base_opcode >> 16) & 0xff; + *p++ = (t->base_opcode >> 8) & 0xff; + *p = (t->base_opcode ) & 0xff; + } + + /* Now the modrm byte and base index byte (if present). */ + if (t->opcode_modifier & Modrm) { + p = frag_more (1); + /* md_number_to_chars (p, i.rm, 1); */ + md_number_to_chars (p, (i.rm.regmem<<0 | i.rm.reg<<3 | i.rm.mode<<6), 1); + /* If i.rm.regmem == ESP (4) && i.rm.mode != Mode 3 (Register mode) + ==> need second modrm byte. */ + if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING && i.rm.mode != 3) { + p = frag_more (1); + /* md_number_to_chars (p, i.bi, 1); */ + md_number_to_chars (p,(i.bi.base<<0 | i.bi.index<<3 | i.bi.scale<<6), 1); + } + } + + if (i.disp_operands) { + register int n; + + for (n = 0; n < i.operands; n++) { + if (i.disps[n]) { + if (i.disps[n]->X_seg == SEG_ABSOLUTE) { + if (i.types[n] & (Disp8|Abs8)) { + p = frag_more (1); + md_number_to_chars (p, i.disps[n]->X_add_number, 1); + } else if (i.types[n] & (Disp16|Abs16)) { + p = frag_more (2); + md_number_to_chars (p, i.disps[n]->X_add_number, 2); + } else { /* Disp32|Abs32 */ + p = frag_more (4); + md_number_to_chars (p, i.disps[n]->X_add_number, 4); + } + } else { /* not SEG_ABSOLUTE */ + /* need a 32-bit fixup (don't support 8bit non-absolute disps) */ + p = frag_more (4); + fix_new (frag_now, p - frag_now->fr_literal, 4, + i.disps[n]->X_add_symbol, i.disps[n]->X_subtract_symbol, + i.disps[n]->X_add_number, 0); + } + } + } + } /* end displacement output */ + + /* output immediate */ + if (i.imm_operands) { + register int n; + + for (n = 0; n < i.operands; n++) { + if (i.imms[n]) { + if (i.imms[n]->X_seg == SEG_ABSOLUTE) { + if (i.types[n] & (Imm8|Imm8S)) { + p = frag_more (1); + md_number_to_chars (p, i.imms[n]->X_add_number, 1); + } else if (i.types[n] & Imm16) { + p = frag_more (2); + md_number_to_chars (p, i.imms[n]->X_add_number, 2); + } else { + p = frag_more (4); + md_number_to_chars (p, i.imms[n]->X_add_number, 4); + } + } else { /* not SEG_ABSOLUTE */ + /* need a 32-bit fixup (don't support 8bit non-absolute ims) */ + /* try to support other sizes ... */ + int size; + if (i.types[n] & (Imm8|Imm8S)) + size = 1; + else if (i.types[n] & Imm16) + size = 2; + else + size = 4; + p = frag_more (size); + fix_new (frag_now, p - frag_now->fr_literal, size, + i.imms[n]->X_add_symbol, i.imms[n]->X_subtract_symbol, + i.imms[n]->X_add_number, 0); + } + } + } + } /* end immediate output */ + } + +#ifdef DEBUG386 + if (flagseen ['D']) { + pi (line, &i); + } +#endif /* DEBUG386 */ + + } + return; +} + +/* Parse OPERAND_STRING into the i386_insn structure I. Returns non-zero + on error. */ + +int i386_operand (operand_string) + char *operand_string; +{ + register char *op_string = operand_string; + + /* Address of '\0' at end of operand_string. */ + char * end_of_operand_string = operand_string + strlen(operand_string); + + /* Start and end of displacement string expression (if found). */ + char * displacement_string_start = 0; + char * displacement_string_end; + + /* We check for an absolute prefix (differentiating, + for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */ + if (*op_string == ABSOLUTE_PREFIX) { + op_string++; + i.types[this_operand] |= JumpAbsolute; + } + + /* Check if operand is a register. */ + if (*op_string == REGISTER_PREFIX) { + register reg_entry * r; + if (! (r = parse_register (op_string))) { + as_bad ("bad register name ('%s')", op_string); + return 0; + } + /* Check for segment override, rather than segment register by + searching for ':' after %<x>s where <x> = s, c, d, e, f, g. */ + if ((r->reg_type & (SReg2|SReg3)) && op_string[3] == ':') { + switch (r->reg_num) { + case 0: + i.seg = &es; break; + case 1: + i.seg = &cs; break; + case 2: + i.seg = &ss; break; + case 3: + i.seg = &ds; break; + case 4: + i.seg = &fs; break; + case 5: + i.seg = &gs; break; + } + op_string += 4; /* skip % <x> s : */ + operand_string = op_string; /* Pretend given string starts here. */ + if (!is_digit_char(*op_string) && !is_identifier_char(*op_string) + && *op_string != '(' && *op_string != ABSOLUTE_PREFIX) { + as_bad ("bad memory operand after segment override"); + return 0; + } + /* Handle case of %es:*foo. */ + if (*op_string == ABSOLUTE_PREFIX) { + op_string++; + i.types[this_operand] |= JumpAbsolute; + } + goto do_memory_reference; + } + i.types[this_operand] |= r->reg_type; + i.regs[this_operand] = r; + i.reg_operands++; + } else if (*op_string == IMMEDIATE_PREFIX) { /* ... or an immediate */ + char * save_input_line_pointer; + register expressionS *exp; + segT exp_seg; + if (i.imm_operands == MAX_IMMEDIATE_OPERANDS) { + as_bad ("only 1 or 2 immediate operands are allowed"); + return 0; + } + exp = &im_expressions[i.imm_operands++]; + i.imms [this_operand] = exp; + save_input_line_pointer = input_line_pointer; + input_line_pointer = ++op_string; /* must advance op_string! */ + exp_seg = expression (exp); + input_line_pointer = save_input_line_pointer; + switch (exp_seg) { + case SEG_NONE: /* missing or bad expr becomes absolute 0 */ + as_bad ("missing or invalid immediate expression '%s' taken as 0", + operand_string); + exp->X_seg = SEG_ABSOLUTE; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_subtract_symbol = (symbolS *) 0; + i.types[this_operand] |= Imm; + break; + case SEG_ABSOLUTE: + i.types[this_operand] |= SMALLEST_IMM_TYPE (exp->X_add_number); + break; + case SEG_TEXT: case SEG_DATA: case SEG_BSS: case SEG_UNKNOWN: + i.types[this_operand] |= Imm32; /* this is an address ==> 32bit */ + break; + default: +seg_unimplemented: + as_bad ("Unimplemented segment type %d in parse_operand", exp_seg); + return 0; + } + /* shorten this type of this operand if the instruction wants + * fewer bits than are present in the immediate. The bit field + * code can put out 'andb $0xffffff, %al', for example. pace + * also 'movw $foo,(%eax)' + */ + switch (i.suffix) { + case WORD_OPCODE_SUFFIX: + i.types[this_operand] |= Imm16; + break; + case BYTE_OPCODE_SUFFIX: + i.types[this_operand] |= Imm16 | Imm8 | Imm8S; + break; + } + } else if (is_digit_char(*op_string) || is_identifier_char(*op_string) + || *op_string == '(') { + /* This is a memory reference of some sort. */ + register char * base_string; + uint found_base_index_form; + + do_memory_reference: + if (i.mem_operands == MAX_MEMORY_OPERANDS) { + as_bad ("more than 1 memory reference in instruction"); + return 0; + } + i.mem_operands++; + + /* Determine type of memory operand from opcode_suffix; + no opcode suffix implies general memory references. */ + switch (i.suffix) { + case BYTE_OPCODE_SUFFIX: + i.types[this_operand] |= Mem8; + break; + case WORD_OPCODE_SUFFIX: + i.types[this_operand] |= Mem16; + break; + case DWORD_OPCODE_SUFFIX: + default: + i.types[this_operand] |= Mem32; + } + + /* Check for base index form. We detect the base index form by + looking for an ')' at the end of the operand, searching + for the '(' matching it, and finding a REGISTER_PREFIX or ',' + after it. */ + base_string = end_of_operand_string - 1; + found_base_index_form = FALSE; + if (*base_string == ')') { + uint parens_balenced = 1; + /* We've already checked that the number of left & right ()'s are equal, + so this loop will not be infinite. */ + do { + base_string--; + if (*base_string == ')') parens_balenced++; + if (*base_string == '(') parens_balenced--; + } while (parens_balenced); + base_string++; /* Skip past '('. */ + if (*base_string == REGISTER_PREFIX || *base_string == ',') + found_base_index_form = TRUE; + } + + /* If we can't parse a base index register expression, we've found + a pure displacement expression. We set up displacement_string_start + and displacement_string_end for the code below. */ + if (! found_base_index_form) { + displacement_string_start = op_string; + displacement_string_end = end_of_operand_string; + } else { + char *base_reg_name, *index_reg_name, *num_string; + int num; + + i.types[this_operand] |= BaseIndex; + + /* If there is a displacement set-up for it to be parsed later. */ + if (base_string != op_string + 1) { + displacement_string_start = op_string; + displacement_string_end = base_string - 1; + } + + /* Find base register (if any). */ + if (*base_string != ',') { + base_reg_name = base_string++; + /* skip past register name & parse it */ + while (isalpha(*base_string)) base_string++; + if (base_string == base_reg_name+1) { + as_bad ("can't find base register name after '(%c'", + REGISTER_PREFIX); + return 0; + } + END_STRING_AND_SAVE (base_string); + if (! (i.base_reg = parse_register (base_reg_name))) { + as_bad ("bad base register name ('%s')", base_reg_name); + return 0; + } + RESTORE_END_STRING (base_string); + } + + /* Now check seperator; must be ',' ==> index reg + OR num ==> no index reg. just scale factor + OR ')' ==> end. (scale factor = 1) */ + if (*base_string != ',' && *base_string != ')') { + as_bad ("expecting ',' or ')' after base register in `%s'", + operand_string); + return 0; + } + + /* There may index reg here; and there may be a scale factor. */ + if (*base_string == ',' && *(base_string+1) == REGISTER_PREFIX) { + index_reg_name = ++base_string; + while (isalpha(*++base_string)); + END_STRING_AND_SAVE (base_string); + if (! (i.index_reg = parse_register(index_reg_name))) { + as_bad ("bad index register name ('%s')", index_reg_name); + return 0; + } + RESTORE_END_STRING (base_string); + } + + /* Check for scale factor. */ + if (*base_string == ',' && isdigit(*(base_string+1))) { + num_string = ++base_string; + while (is_digit_char(*base_string)) base_string++; + if (base_string == num_string) { + as_bad ("can't find a scale factor after ','"); + return 0; + } + END_STRING_AND_SAVE (base_string); + /* We've got a scale factor. */ + if (! sscanf (num_string, "%d", &num)) { + as_bad ("can't parse scale factor from '%s'", num_string); + return 0; + } + RESTORE_END_STRING (base_string); + switch (num) { /* must be 1 digit scale */ + case 1: i.log2_scale_factor = 0; break; + case 2: i.log2_scale_factor = 1; break; + case 4: i.log2_scale_factor = 2; break; + case 8: i.log2_scale_factor = 3; break; + default: + as_bad ("expecting scale factor of 1, 2, 4, 8; got %d", num); + return 0; + } + } else { + if (! i.index_reg && *base_string == ',') { + as_bad ("expecting index register or scale factor after ','; got '%c'", + *(base_string+1)); + return 0; + } + } + } + + /* If there's an expression begining the operand, parse it, + assuming displacement_string_start and displacement_string_end + are meaningful. */ + if (displacement_string_start) { + register expressionS * exp; + segT exp_seg; + char * save_input_line_pointer; + exp = &disp_expressions[i.disp_operands]; + i.disps [this_operand] = exp; + i.disp_operands++; + save_input_line_pointer = input_line_pointer; + input_line_pointer = displacement_string_start; + END_STRING_AND_SAVE (displacement_string_end); + exp_seg = expression (exp); + if(*input_line_pointer) + as_bad("Ignoring junk '%s' after expression",input_line_pointer); + RESTORE_END_STRING (displacement_string_end); + input_line_pointer = save_input_line_pointer; + switch (exp_seg) { + case SEG_NONE: + /* missing expr becomes absolute 0 */ + as_bad ("missing or invalid displacement '%s' taken as 0", + operand_string); + i.types[this_operand] |= (Disp|Abs); + exp->X_seg = SEG_ABSOLUTE; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_subtract_symbol = (symbolS *) 0; + break; + case SEG_ABSOLUTE: + i.types[this_operand] |= SMALLEST_DISP_TYPE (exp->X_add_number); + break; + case SEG_TEXT: case SEG_DATA: case SEG_BSS: + case SEG_UNKNOWN: /* must be 32 bit displacement (i.e. address) */ + i.types[this_operand] |= Disp32; + break; + default: + goto seg_unimplemented; + } + } + + /* Make sure the memory operand we've been dealt is valid. */ + if (i.base_reg && i.index_reg && + ! (i.base_reg->reg_type & i.index_reg->reg_type & Reg)) { + as_bad ("register size mismatch in (base,index,scale) expression"); + return 0; + } + if ((i.base_reg && (i.base_reg->reg_type & Reg32) == 0) || + (i.index_reg && (i.index_reg->reg_type & Reg32) == 0)) { + as_bad ("base/index register must be 32 bit register"); + return 0; + } + if (i.index_reg && i.index_reg == esp) { + as_bad ("%s may not be used as an index register", esp->reg_name); + return 0; + } + } else { /* it's not a memory operand; argh! */ + as_bad ("invalid char %s begining %s operand '%s'", + output_invalid(*op_string), ordinal_names[this_operand], + op_string); + return 0; + } + return 1; /* normal return */ +} + +/* + * md_estimate_size_before_relax() + * + * Called just before relax(). + * Any symbol that is now undefined will not become defined. + * Return the correct fr_subtype in the frag. + * Return the initial "guess for fr_var" to caller. + * The guess for fr_var is ACTUALLY the growth beyond fr_fix. + * Whatever we do to grow fr_fix or fr_var contributes to our returned value. + * Although it may not be explicit in the frag, pretend fr_var starts with a + * 0 value. + */ +int +md_estimate_size_before_relax (fragP, segment_type) + register fragS * fragP; + register int segment_type; /* N_DATA or N_TEXT. */ +{ + register uchar * opcode; + register int old_fr_fix; + + old_fr_fix = fragP -> fr_fix; + opcode = (uchar *) fragP -> fr_opcode; + /* We've already got fragP->fr_subtype right; all we have to do is check + for un-relaxable symbols. */ + if ((fragP -> fr_symbol -> sy_type & N_TYPE) != segment_type) { + /* symbol is undefined in this segment */ + switch (opcode[0]) { + case JUMP_PC_RELATIVE: /* make jmp (0xeb) a dword displacement jump */ + opcode[0] = 0xe9; /* dword disp jmp */ + fragP -> fr_fix += 4; + fix_new (fragP, old_fr_fix, 4, + fragP -> fr_symbol, + (symbolS *) 0, + fragP -> fr_offset, 1); + break; + + default: + /* This changes the byte-displacement jump 0x7N --> + the dword-displacement jump 0x0f8N */ + opcode[1] = opcode[0] + 0x10; + opcode[0] = TWO_BYTE_OPCODE_ESCAPE; /* two-byte escape */ + fragP -> fr_fix += 1 + 4; /* we've added an opcode byte */ + fix_new (fragP, old_fr_fix + 1, 4, + fragP -> fr_symbol, + (symbolS *) 0, + fragP -> fr_offset, 1); + break; + } + frag_wane (fragP); + } + return (fragP -> fr_var + fragP -> fr_fix - old_fr_fix); +} /* md_estimate_size_before_relax() */ + +/* + * md_convert_frag(); + * + * Called after relax() is finished. + * In: Address of frag. + * fr_type == rs_machine_dependent. + * fr_subtype is what the address relaxed to. + * + * Out: Any fixSs and constants are set up. + * Caller will turn frag into a ".space 0". + */ +void +md_convert_frag (fragP) + register fragS * fragP; +{ + register uchar * opcode; + uchar * where_to_put_displacement; + uint target_address, opcode_address; + uint extension; + int displacement_from_opcode_start; + + opcode = (uchar *) fragP -> fr_opcode; + + /* Address we want to reach in file space. */ + target_address = fragP->fr_symbol->sy_value + fragP->fr_offset; + + /* Address opcode resides at in file space. */ + opcode_address = fragP->fr_address + fragP->fr_fix; + + /* Displacement from opcode start to fill into instruction. */ + displacement_from_opcode_start = target_address - opcode_address; + + switch (fragP->fr_subtype) { + case ENCODE_RELAX_STATE (COND_JUMP, BYTE): + case ENCODE_RELAX_STATE (UNCOND_JUMP, BYTE): + /* don't have to change opcode */ + extension = 1; /* 1 opcode + 1 displacement */ + where_to_put_displacement = &opcode[1]; + break; + + case ENCODE_RELAX_STATE (COND_JUMP, WORD): + opcode[1] = TWO_BYTE_OPCODE_ESCAPE; + opcode[2] = opcode[0] + 0x10; + opcode[0] = WORD_PREFIX_OPCODE; + extension = 4; /* 3 opcode + 2 displacement */ + where_to_put_displacement = &opcode[3]; + break; + + case ENCODE_RELAX_STATE (UNCOND_JUMP, WORD): + opcode[1] = 0xe9; + opcode[0] = WORD_PREFIX_OPCODE; + extension = 3; /* 2 opcode + 2 displacement */ + where_to_put_displacement = &opcode[2]; + break; + + case ENCODE_RELAX_STATE (COND_JUMP, DWORD): + opcode[1] = opcode[0] + 0x10; + opcode[0] = TWO_BYTE_OPCODE_ESCAPE; + extension = 5; /* 2 opcode + 4 displacement */ + where_to_put_displacement = &opcode[2]; + break; + + case ENCODE_RELAX_STATE (UNCOND_JUMP, DWORD): + opcode[0] = 0xe9; + extension = 4; /* 1 opcode + 4 displacement */ + where_to_put_displacement = &opcode[1]; + break; + + default: + BAD_CASE(fragP -> fr_subtype); + break; + } + /* now put displacement after opcode */ + md_number_to_chars (where_to_put_displacement, + displacement_from_opcode_start - extension, + SIZE_FROM_RELAX_STATE (fragP->fr_subtype)); + fragP -> fr_fix += extension; +} + + +int md_short_jump_size = 2; /* size of byte displacement jmp */ +int md_long_jump_size = 5; /* size of dword displacement jmp */ + +void md_create_short_jump(ptr, from_addr, to_addr) + char *ptr; + long from_addr, to_addr; +{ + long offset; + + offset = to_addr - (from_addr + 2); + md_number_to_chars (ptr, (long) 0xeb, 1); /* opcode for byte-disp jump */ + md_number_to_chars (ptr + 1, offset, 1); +} + +void md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + long from_addr, to_addr; + fragS *frag; + symbolS *to_symbol; +{ + long offset; + + if (flagseen['m']) { + offset = to_addr - to_symbol->sy_value; + md_number_to_chars (ptr, 0xe9, 1); /* opcode for long jmp */ + md_number_to_chars (ptr + 1, offset, 4); + fix_new (frag, (ptr+1) - frag->fr_literal, 4, + to_symbol, (symbolS *) 0, (long int) 0, 0); + } else { + offset = to_addr - (from_addr + 5); + md_number_to_chars(ptr, (long) 0xe9, 1); + md_number_to_chars(ptr + 1, offset, 4); + } +} + +int +md_parse_option(argP,cntP,vecP) +char **argP; +int *cntP; +char ***vecP; +{ + return 1; +} + +void /* Knows about order of bytes in address. */ +md_number_to_chars (con, value, nbytes) + char con []; /* Return 'nbytes' of chars here. */ + long int value; /* The value of the bits. */ + int nbytes; /* Number of bytes in the output. */ +{ + register char * p = con; + + switch (nbytes) { + case 1: + p[0] = value & 0xff; + break; + case 2: + p[0] = value & 0xff; + p[1] = (value >> 8) & 0xff; + break; + case 4: + p[0] = value & 0xff; + p[1] = (value>>8) & 0xff; + p[2] = (value>>16) & 0xff; + p[3] = (value>>24) & 0xff; + break; + default: + BAD_CASE (nbytes); + } +} + +void /* Knows about order of bytes in address. */ +md_number_to_disp (con, value, nbytes) + char con []; /* Return 'nbytes' of chars here. */ + long int value; /* The value of the bits. */ + int nbytes; /* Number of bytes in the output. */ +{ + char * answer = alloca (nbytes); + register char * p = answer; + + switch (nbytes) { + case 1: + *p = value; + break; + case 2: + *p++ = value; + *p = (value>>8); + break; + case 4: + *p++ = value; + *p++ = (value>>8); + *p++ = (value>>16); + *p = (value>>24); + break; + default: + BAD_CASE (nbytes); + } + bcopy (answer, con, nbytes); +} + +void /* Knows about order of bytes in address. */ +md_number_to_imm (con, value, nbytes) + char con []; /* Return 'nbytes' of chars here. */ + long int value; /* The value of the bits. */ + int nbytes; /* Number of bytes in the output. */ +{ + char * answer = alloca (nbytes); + register char * p = answer; + + switch (nbytes) { + case 1: + *p = value; + break; + case 2: + *p++ = value; + *p = (value>>8); + break; + case 4: + *p++ = value; + *p++ = (value>>8); + *p++ = (value>>16); + *p = (value>>24); + break; + default: + BAD_CASE (nbytes); + } + bcopy (answer, con, nbytes); +} + +void /* Knows about order of bytes in address. */ +md_number_to_field (con, value, nbytes) + char con []; /* Return 'nbytes' of chars here. */ + long int value; /* The value of the bits. */ + int nbytes; /* Number of bytes in the output. */ +{ + char * answer = alloca (nbytes); + register char * p = answer; + + switch (nbytes) { + case 1: + *p = value; + break; + case 2: + *p++ = value; + *p = (value>>8); + break; + case 4: + *p++ = value; + *p++ = (value>>8); + *p++ = (value>>16); + *p = (value>>24); + break; + default: + BAD_CASE (nbytes); + } + bcopy (answer, con, nbytes); +} + +long int /* Knows about the byte order in a word. */ +md_chars_to_number (con, nbytes) +unsigned char con[]; /* Low order byte 1st. */ + int nbytes; /* Number of bytes in the input. */ +{ + long int retval; + for (retval=0, con+=nbytes-1; nbytes--; con--) + { + retval <<= BITS_PER_CHAR; + retval |= *con; + } + return retval; +} + +void md_ri_to_chars(ri_p, ri) + struct relocation_info *ri_p, ri; +{ + unsigned char the_bytes[8]; + + /* this is easy */ + md_number_to_chars(the_bytes, ri.r_address, sizeof(ri.r_address)); + /* now the fun stuff */ + the_bytes[6] = (ri.r_symbolnum >> 16) & 0x0ff; + the_bytes[5] = (ri.r_symbolnum >> 8) & 0x0ff; + the_bytes[4] = ri.r_symbolnum & 0x0ff; + the_bytes[7] = (((ri.r_extern << 3) & 0x08) | ((ri.r_length << 1) & 0x06) | + ((ri.r_pcrel << 0) & 0x01)) & 0x0F; + /* now put it back where you found it */ + bcopy (the_bytes, (char *)ri_p, sizeof(struct relocation_info)); +} + + +#define MAX_LITTLENUMS 6 + +/* Turn the string pointed to by litP into a floating point constant of type + type, and emit the appropriate bytes. The number of LITTLENUMS emitted + is stored in *sizeP . An error message is returned, or NULL on OK. + */ +char * +md_atof(type,litP,sizeP) + char type; + char *litP; + int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + char *atof_ieee(); + + switch(type) { + case 'f': + case 'F': + prec = 2; + break; + + case 'd': + case 'D': + prec = 4; + break; + + case 'x': + case 'X': + prec = 5; + break; + + default: + *sizeP=0; + return "Bad call to md_atof ()"; + } + t = atof_ieee (input_line_pointer,type,words); + if(t) + input_line_pointer=t; + + *sizeP = prec * sizeof(LITTLENUM_TYPE); + /* this loops outputs the LITTLENUMs in REVERSE order; in accord with + the bigendian 386 */ + for(wordP = words + prec - 1;prec--;) { + md_number_to_chars (litP, (long) (*wordP--), sizeof(LITTLENUM_TYPE)); + litP += sizeof(LITTLENUM_TYPE); + } + return ""; /* Someone should teach Dean about null pointers */ +} + +char output_invalid_buf[8]; + +char * output_invalid (c) + char c; +{ + if (isprint(c)) sprintf (output_invalid_buf, "'%c'", c); + else sprintf (output_invalid_buf, "(0x%x)", c); + return output_invalid_buf; +} + +reg_entry *parse_register (reg_string) + char *reg_string; /* reg_string starts *before* REGISTER_PREFIX */ +{ + register char *s = reg_string; + register char *p; + char reg_name_given[MAX_REG_NAME_SIZE]; + + s++; /* skip REGISTER_PREFIX */ + for (p = reg_name_given; is_register_char (*s); p++, s++) { + *p = register_chars [*s]; + if (p >= reg_name_given + MAX_REG_NAME_SIZE) + return (reg_entry *) 0; + } + *p = '\0'; + return (reg_entry *) hash_find (reg_hash, reg_name_given); +} + diff --git a/gnu/usr.bin/as/config/i386.h b/gnu/usr.bin/as/config/i386.h new file mode 100644 index 0000000..c569c1c --- /dev/null +++ b/gnu/usr.bin/as/config/i386.h @@ -0,0 +1,296 @@ +/* i386.h -- Header file for i386.c + Copyright (C) 1989, Free Software Foundation. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define MAX_OPERANDS 3 /* max operands per insn */ +#define MAX_PREFIXES 4 /* max prefixes per opcode */ +#define MAX_IMMEDIATE_OPERANDS 2 /* max immediates per insn */ +#define MAX_MEMORY_OPERANDS 2 /* max memory ref per insn + * lcall uses 2 + */ +/* we define the syntax here (modulo base,index,scale syntax) */ +#define REGISTER_PREFIX '%' +#define IMMEDIATE_PREFIX '$' +#define ABSOLUTE_PREFIX '*' +#define PREFIX_SEPERATOR '/' + +#define TWO_BYTE_OPCODE_ESCAPE 0x0f + +/* register numbers */ +#define EBP_REG_NUM 5 +#define ESP_REG_NUM 4 + +/* modrm_byte.regmem for twobyte escape */ +#define ESCAPE_TO_TWO_BYTE_ADDRESSING ESP_REG_NUM +/* index_base_byte.index for no index register addressing */ +#define NO_INDEX_REGISTER ESP_REG_NUM +/* index_base_byte.base for no base register addressing */ +#define NO_BASE_REGISTER EBP_REG_NUM + +/* these are the att as opcode suffixes, making movl --> mov, for example */ +#define DWORD_OPCODE_SUFFIX 'l' +#define WORD_OPCODE_SUFFIX 'w' +#define BYTE_OPCODE_SUFFIX 'b' + +/* modrm.mode = REGMEM_FIELD_HAS_REG when a register is in there */ +#define REGMEM_FIELD_HAS_REG 0x3 /* always = 0x3 */ +#define REGMEM_FIELD_HAS_MEM (~REGMEM_FIELD_HAS_REG) + +#define END_OF_INSN '\0' + +/* +When an operand is read in it is classified by its type. This type includes +all the possible ways an operand can be used. Thus, '%eax' is both 'register +# 0' and 'The Accumulator'. In our language this is expressed by OR'ing +'Reg32' (any 32 bit register) and 'Acc' (the accumulator). +Operands are classified so that we can match given operand types with +the opcode table in i386-opcode.h. + */ +#define Unknown 0x0 +/* register */ +#define Reg8 0x1 /* 8 bit reg */ +#define Reg16 0x2 /* 16 bit reg */ +#define Reg32 0x4 /* 32 bit reg */ +#define Reg (Reg8|Reg16|Reg32) /* gen'l register */ +#define WordReg (Reg16|Reg32) /* for push/pop operands */ +/* immediate */ +#define Imm8 0x8 /* 8 bit immediate */ +#define Imm8S 0x10 /* 8 bit immediate sign extended */ +#define Imm16 0x20 /* 16 bit immediate */ +#define Imm32 0x40 /* 32 bit immediate */ +#define Imm1 0x80 /* 1 bit immediate */ +#define ImmUnknown Imm32 /* for unknown expressions */ +#define Imm (Imm8|Imm8S|Imm16|Imm32) /* gen'l immediate */ +/* memory */ +#define Disp8 0x200 /* 8 bit displacement (for jumps) */ +#define Disp16 0x400 /* 16 bit displacement */ +#define Disp32 0x800 /* 32 bit displacement */ +#define Disp (Disp8|Disp16|Disp32) /* General displacement */ +#define DispUnknown Disp32 /* for unknown size displacements */ +#define Mem8 0x1000 +#define Mem16 0x2000 +#define Mem32 0x4000 +#define BaseIndex 0x8000 +#define Mem (Disp|Mem8|Mem16|Mem32|BaseIndex) /* General memory */ +#define WordMem (Mem16|Mem32|Disp|BaseIndex) +#define ByteMem (Mem8|Disp|BaseIndex) +/* specials */ +#define InOutPortReg 0x10000 /* register to hold in/out port addr = dx */ +#define ShiftCount 0x20000 /* register to hold shift cound = cl */ +#define Control 0x40000 /* Control register */ +#define Debug 0x80000 /* Debug register */ +#define Test 0x100000 /* Test register */ +#define FloatReg 0x200000 /* Float register */ +#define FloatAcc 0x400000 /* Float stack top %st(0) */ +#define SReg2 0x800000 /* 2 bit segment register */ +#define SReg3 0x1000000 /* 3 bit segment register */ +#define Acc 0x2000000 /* Accumulator %al or %ax or %eax */ +#define ImplicitRegister (InOutPortReg|ShiftCount|Acc|FloatAcc) +#define JumpAbsolute 0x4000000 +#define Abs8 0x08000000 +#define Abs16 0x10000000 +#define Abs32 0x20000000 +#define Abs (Abs8|Abs16|Abs32) + +#define MODE_FROM_DISP_SIZE(t) \ + ((t&(Disp8)) ? 1 : \ + ((t&(Disp32)) ? 2 : 0)) + +#define Byte (Reg8|Imm8|Imm8S) +#define Word (Reg16|Imm16) +#define DWord (Reg32|Imm32) + +/* convert opcode suffix ('b' 'w' 'l' typically) into type specifyer */ +#define OPCODE_SUFFIX_TO_TYPE(s) \ + (s == BYTE_OPCODE_SUFFIX ? Byte : \ + (s == WORD_OPCODE_SUFFIX ? Word : DWord)) + +#define FITS_IN_SIGNED_BYTE(num) ((num) >= -128 && (num) <= 127) +#define FITS_IN_UNSIGNED_BYTE(num) ((num) >= 0 && (num) <= 255) +#define FITS_IN_UNSIGNED_WORD(num) ((num) >= 0 && (num) <= 65535) +#define FITS_IN_SIGNED_WORD(num) ((num) >= -32768 && (num) <= 32767) + +#define SMALLEST_DISP_TYPE(num) \ + FITS_IN_SIGNED_BYTE(num) ? (Disp8|Disp32|Abs8|Abs32) : (Disp32|Abs32) + +#define SMALLEST_IMM_TYPE(num) \ + (num == 1) ? (Imm1|Imm8|Imm8S|Imm16|Imm32): \ + FITS_IN_SIGNED_BYTE(num) ? (Imm8S|Imm8|Imm16|Imm32) : \ + FITS_IN_UNSIGNED_BYTE(num) ? (Imm8|Imm16|Imm32): \ + (FITS_IN_SIGNED_WORD(num)||FITS_IN_UNSIGNED_WORD(num)) ? (Imm16|Imm32) : \ + (Imm32) + +typedef unsigned char uchar; +typedef unsigned int uint; + +typedef struct { + /* instruction name sans width suffix ("mov" for movl insns) */ + char *name; + + /* how many operands */ + uint operands; + + /* base_opcode is the fundamental opcode byte with a optional prefix(es). */ + uint base_opcode; + + /* extension_opcode is the 3 bit extension for group <n> insns. + If this template has no extension opcode (the usual case) use None */ + uchar extension_opcode; +#define None 0xff /* If no extension_opcode is possible. */ + + /* the bits in opcode_modifier are used to generate the final opcode from + the base_opcode. These bits also are used to detect alternate forms of + the same instruction */ + uint opcode_modifier; + +/* opcode_modifier bits: */ +#define W 0x1 /* set if operands are words or dwords */ +#define D 0x2 /* D = 0 if Reg --> Regmem; D = 1 if Regmem --> Reg */ +/* direction flag for floating insns: MUST BE 0x400 */ +#define FloatD 0x400 +/* shorthand */ +#define DW (D|W) +#define ShortForm 0x10 /* register is in low 3 bits of opcode */ +#define ShortFormW 0x20 /* ShortForm and W bit is 0x8 */ +#define Seg2ShortForm 0x40 /* encoding of load segment reg insns */ +#define Seg3ShortForm 0x80 /* fs/gs segment register insns. */ +#define Jump 0x100 /* special case for jump insns. */ +#define JumpInterSegment 0x200 /* special case for intersegment leaps/calls */ +/* 0x400 CANNOT BE USED since it's already used by FloatD above */ +#define DONT_USE 0x400 +#define NoModrm 0x800 +#define Modrm 0x1000 +#define imulKludge 0x2000 +#define JumpByte 0x4000 +#define JumpDword 0x8000 +#define ReverseRegRegmem 0x10000 + + /* (opcode_modifier & COMES_IN_ALL_SIZES) is true if the + instuction comes in byte, word, and dword sizes and is encoded into + machine code in the canonical way. */ +#define COMES_IN_ALL_SIZES (W) + + /* (opcode_modifier & COMES_IN_BOTH_DIRECTIONS) indicates that the + source and destination operands can be reversed by setting either + the D (for integer insns) or the FloatD (for floating insns) bit + in base_opcode. */ +#define COMES_IN_BOTH_DIRECTIONS (D|FloatD) + + /* operand_types[i] describes the type of operand i. This is made + by OR'ing together all of the possible type masks. (e.g. + 'operand_types[i] = Reg|Imm' specifies that operand i can be + either a register or an immediate operand */ + uint operand_types[3]; +} template; + +/* + 'templates' is for grouping together 'template' structures for opcodes + of the same name. This is only used for storing the insns in the grand + ole hash table of insns. + The templates themselves start at START and range up to (but not including) + END. +*/ +typedef struct { + template *start; + template *end; +} templates; + +/* these are for register name --> number & type hash lookup */ +typedef struct { + char * reg_name; + uint reg_type; + uint reg_num; +} reg_entry; + +typedef struct { + char * seg_name; + uint seg_prefix; +} seg_entry; + +/* these are for prefix name --> prefix code hash lookup */ +typedef struct { + char * prefix_name; + uchar prefix_code; +} prefix_entry; + +/* 386 operand encoding bytes: see 386 book for details of this. */ +typedef struct { + unsigned regmem:3; /* codes register or memory operand */ + unsigned reg:3; /* codes register operand (or extended opcode) */ + unsigned mode:2; /* how to interpret regmem & reg */ +} modrm_byte; + +/* 386 opcode byte to code indirect addressing. */ +typedef struct { + unsigned base:3; + unsigned index:3; + unsigned scale:2; +} base_index_byte; + +/* 'md_assemble ()' gathers together information and puts it into a + i386_insn. */ + +typedef struct { + /* TM holds the template for the insn were currently assembling. */ + template tm; + /* SUFFIX holds the opcode suffix (e.g. 'l' for 'movl') if given. */ + char suffix; + /* Operands are coded with OPERANDS, TYPES, DISPS, IMMS, and REGS. */ + + /* OPERANDS gives the number of given operands. */ + uint operands; + + /* REG_OPERANDS, DISP_OPERANDS, MEM_OPERANDS, IMM_OPERANDS give the number of + given register, displacement, memory operands and immediate operands. */ + uint reg_operands, disp_operands, mem_operands, imm_operands; + + /* TYPES [i] is the type (see above #defines) which tells us how to + search through DISPS [i] & IMMS [i] & REGS [i] for the required + operand. */ + uint types [MAX_OPERANDS]; + + /* Displacements (if given) for each operand. */ + expressionS * disps [MAX_OPERANDS]; + + /* Immediate operands (if given) for each operand. */ + expressionS * imms [MAX_OPERANDS]; + + /* Register operands (if given) for each operand. */ + reg_entry * regs [MAX_OPERANDS]; + + /* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode + the base index byte below. */ + reg_entry * base_reg; + reg_entry * index_reg; + uint log2_scale_factor; + + /* SEG gives the seg_entry of this insn. It is equal to zero unless + an explicit segment override is given. */ + seg_entry * seg; /* segment for memory operands (if given) */ + + /* PREFIX holds all the given prefix opcodes (usually null). + PREFIXES is the size of PREFIX. */ + char prefix [MAX_PREFIXES]; + uint prefixes; + + /* RM and IB are the modrm byte and the base index byte where the addressing + modes of this insn are encoded. */ + + modrm_byte rm; + base_index_byte bi; +} i386_insn; diff --git a/gnu/usr.bin/as/expr.c b/gnu/usr.bin/as/expr.c new file mode 100644 index 0000000..f3a377d --- /dev/null +++ b/gnu/usr.bin/as/expr.c @@ -0,0 +1,980 @@ +/* expr.c -operands, expressions- + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * This is really a branch office of as-read.c. I split it out to clearly + * distinguish the world of expressions from the world of statements. + * (It also gives smaller files to re-compile.) + * Here, "operand"s are of expressions, not instructions. + */ + +#include <ctype.h> +#include "as.h" +#include "flonum.h" +#include "read.h" +#include "struc-symbol.h" +#include "expr.h" +#include "obstack.h" +#include "symbols.h" + +static void clean_up_expression(); /* Internal. */ +extern const char EXP_CHARS[]; /* JF hide MD floating pt stuff all the same place */ +extern const char FLT_CHARS[]; + +#ifdef SUN_ASM_SYNTAX +extern int local_label_defined[]; +#endif + +/* + * Build any floating-point literal here. + * Also build any bignum literal here. + */ + +/* LITTLENUM_TYPE generic_buffer [6]; /* JF this is a hack */ +/* Seems atof_machine can backscan through generic_bignum and hit whatever + happens to be loaded before it in memory. And its way too complicated + for me to fix right. Thus a hack. JF: Just make generic_bignum bigger, + and never write into the early words, thus they'll always be zero. + I hate Dean's floating-point code. Bleh. + */ +LITTLENUM_TYPE generic_bignum [SIZE_OF_LARGE_NUMBER+6]; +FLONUM_TYPE generic_floating_point_number = +{ + & generic_bignum [6], /* low (JF: Was 0) */ + & generic_bignum [SIZE_OF_LARGE_NUMBER+6 - 1], /* high JF: (added +6) */ + 0, /* leader */ + 0, /* exponent */ + 0 /* sign */ +}; +/* If nonzero, we've been asked to assemble nan, +inf or -inf */ +int generic_floating_point_magic; + +/* + * Summary of operand(). + * + * in: Input_line_pointer points to 1st char of operand, which may + * be a space. + * + * out: A expressionS. X_seg determines how to understand the rest of the + * expressionS. + * The operand may have been empty: in this case X_seg == SEG_NONE. + * Input_line_pointer -> (next non-blank) char after operand. + * + */ + +static segT +operand (expressionP) + register expressionS * expressionP; +{ + register char c; + register char *name; /* points to name of symbol */ + register struct symbol * symbolP; /* Points to symbol */ + + extern char hex_value[]; /* In hex_value.c */ + char *local_label_name(); + + SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */ + c = * input_line_pointer ++; /* Input_line_pointer -> past char in c. */ + if (isdigit(c)) + { + register valueT number; /* offset or (absolute) value */ + register short int digit; /* value of next digit in current radix */ + /* invented for humans only, hope */ + /* optimising compiler flushes it! */ + register short int radix; /* 8, 10 or 16 */ + /* 0 means we saw start of a floating- */ + /* point constant. */ + register short int maxdig;/* Highest permitted digit value. */ + register int too_many_digits; /* If we see >= this number of */ + /* digits, assume it is a bignum. */ + register char * digit_2; /* -> 2nd digit of number. */ + int small; /* TRUE if fits in 32 bits. */ + + if (c=='0') + { /* non-decimal radix */ + if ((c = * input_line_pointer ++)=='x' || c=='X') + { + c = * input_line_pointer ++; /* read past "0x" or "0X" */ + maxdig = radix = 16; + too_many_digits = 9; + } + else + { + /* If it says '0f' and the line ends or it DOESN'T look like + a floating point #, its a local label ref. DTRT */ + if(c=='f' && (! *input_line_pointer || + (!index("+-.0123456789",*input_line_pointer) && + !index(EXP_CHARS,*input_line_pointer)))) + { + maxdig = radix = 10; + too_many_digits = 11; + c='0'; + input_line_pointer-=2; + } + else if (c && index (FLT_CHARS,c)) + { + radix = 0; /* Start of floating-point constant. */ + /* input_line_pointer -> 1st char of number. */ + expressionP -> X_add_number = - (isupper(c) ? tolower(c) : c); + } + else + { /* By elimination, assume octal radix. */ + radix = 8; + maxdig = 10; /* Un*x sux. Compatibility. */ + too_many_digits = 11; + } + } + /* c == char after "0" or "0x" or "0X" or "0e" etc.*/ + } + else + { + maxdig = radix = 10; + too_many_digits = 11; + } + if (radix) + { /* Fixed-point integer constant. */ + /* May be bignum, or may fit in 32 bits. */ +/* + * Most numbers fit into 32 bits, and we want this case to be fast. + * So we pretend it will fit into 32 bits. If, after making up a 32 + * bit number, we realise that we have scanned more digits than + * comfortably fit into 32 bits, we re-scan the digits coding + * them into a bignum. For decimal and octal numbers we are conservative: some + * numbers may be assumed bignums when in fact they do fit into 32 bits. + * Numbers of any radix can have excess leading zeros: we strive + * to recognise this and cast them back into 32 bits. + * We must check that the bignum really is more than 32 + * bits, and change it back to a 32-bit number if it fits. + * The number we are looking for is expected to be positive, but + * if it fits into 32 bits as an unsigned number, we let it be a 32-bit + * number. The cavalier approach is for speed in ordinary cases. + */ + digit_2 = input_line_pointer; + for (number=0; (digit=hex_value[c])<maxdig; c = * input_line_pointer ++) + { + number = number * radix + digit; + } + /* C contains character after number. */ + /* Input_line_pointer -> char after C. */ + small = input_line_pointer - digit_2 < too_many_digits; + if ( ! small) + { + /* + * We saw a lot of digits. Manufacture a bignum the hard way. + */ + LITTLENUM_TYPE * leader; /* -> high order littlenum of the bignum. */ + LITTLENUM_TYPE * pointer; /* -> littlenum we are frobbing now. */ + long int carry; + + leader = generic_bignum; + generic_bignum [0] = 0; + generic_bignum [1] = 0; + /* We could just use digit_2, but lets be mnemonic. */ + input_line_pointer = -- digit_2; /* -> 1st digit. */ + c = *input_line_pointer ++; + for (; (carry = hex_value [c]) < maxdig; c = * input_line_pointer ++) + { + for (pointer = generic_bignum; + pointer <= leader; + pointer ++) + { + long int work; + + work = carry + radix * * pointer; + * pointer = work & LITTLENUM_MASK; + carry = work >> LITTLENUM_NUMBER_OF_BITS; + } + if (carry) + { + if (leader < generic_bignum + SIZE_OF_LARGE_NUMBER - 1) + { /* Room to grow a longer bignum. */ + * ++ leader = carry; + } + } + } + /* Again, C is char after number, */ + /* input_line_pointer -> after C. */ + know( BITS_PER_INT == 32 ); + know( LITTLENUM_NUMBER_OF_BITS == 16 ); + /* Hence the constant "2" in the next line. */ + if (leader < generic_bignum + 2) + { /* Will fit into 32 bits. */ + number = + ( (generic_bignum [1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS ) + | (generic_bignum [0] & LITTLENUM_MASK); + small = TRUE; + } + else + { + number = leader - generic_bignum + 1; /* Number of littlenums in the bignum. */ + } + } + if (small) + { + /* + * Here with number, in correct radix. c is the next char. + * Note that unlike Un*x, we allow "011f" "0x9f" to + * both mean the same as the (conventional) "9f". This is simply easier + * than checking for strict canonical form. Syntax sux! + */ + if (number<10) + { +#ifdef SUN_ASM_SYNTAX + if (c=='b' || (c=='$' && local_label_defined[number])) +#else + if (c=='b') +#endif + { + /* + * Backward ref to local label. + * Because it is backward, expect it to be DEFINED. + */ + /* + * Construct a local label. + */ + name = local_label_name ((int)number, 0); + if ( (symbolP = symbol_table_lookup(name)) /* seen before */ + && (symbolP -> sy_type & N_TYPE) != N_UNDF /* symbol is defined: OK */ + ) + { /* Expected path: symbol defined. */ + /* Local labels are never absolute. Don't waste time checking absoluteness. */ + know( (symbolP -> sy_type & N_TYPE) == N_DATA + || (symbolP -> sy_type & N_TYPE) == N_TEXT ); + expressionP -> X_add_symbol = symbolP; + expressionP -> X_add_number = 0; + expressionP -> X_seg = N_TYPE_seg [symbolP -> sy_type]; + } + else + { /* Either not seen or not defined. */ + as_warn( "Backw. ref to unknown label \"%d:\", 0 assumed.", + number + ); + expressionP -> X_add_number = 0; + expressionP -> X_seg = SEG_ABSOLUTE; + } + } + else + { +#ifdef SUN_ASM_SYNTAX + if (c=='f' || (c=='$' && !local_label_defined[number])) +#else + if (c=='f') +#endif + { + /* + * Forward reference. Expect symbol to be undefined or + * unknown. Undefined: seen it before. Unknown: never seen + * it in this pass. + * Construct a local label name, then an undefined symbol. + * Don't create a XSEG frag for it: caller may do that. + * Just return it as never seen before. + */ + name = local_label_name ((int)number, 1); + if ( symbolP = symbol_table_lookup( name )) + { + /* We have no need to check symbol properties. */ + know( (symbolP -> sy_type & N_TYPE) == N_UNDF + || (symbolP -> sy_type & N_TYPE) == N_DATA + || (symbolP -> sy_type & N_TYPE) == N_TEXT); + } + else + { + symbolP = symbol_new (name, N_UNDF, 0,0,0, & zero_address_frag); + symbol_table_insert (symbolP); + } + expressionP -> X_add_symbol = symbolP; + expressionP -> X_seg = SEG_UNKNOWN; + expressionP -> X_subtract_symbol = NULL; + expressionP -> X_add_number = 0; + } + else + { /* Really a number, not a local label. */ + expressionP -> X_add_number = number; + expressionP -> X_seg = SEG_ABSOLUTE; + input_line_pointer --; /* Restore following character. */ + } /* if (c=='f') */ + } /* if (c=='b') */ + } + else + { /* Really a number. */ + expressionP -> X_add_number = number; + expressionP -> X_seg = SEG_ABSOLUTE; + input_line_pointer --; /* Restore following character. */ + } /* if (number<10) */ + } + else + { + expressionP -> X_add_number = number; + expressionP -> X_seg = SEG_BIG; + input_line_pointer --; /* -> char following number. */ + } /* if (small) */ + } /* (If integer constant) */ + else + { /* input_line_pointer -> */ + /* floating-point constant. */ + int error_code; + + error_code = atof_generic + (& input_line_pointer, ".", EXP_CHARS, + & generic_floating_point_number); + + if (error_code) + { + if (error_code == ERROR_EXPONENT_OVERFLOW) + { + as_warn( "Bad floating-point constant: exponent overflow, probably assembling junk" ); + } + else + { + as_warn( "Bad floating-point constant: unknown error code=%d.", error_code); + } + } + expressionP -> X_seg = SEG_BIG; + /* input_line_pointer -> just after constant, */ + /* which may point to whitespace. */ + know( expressionP -> X_add_number < 0 ); /* < 0 means "floating point". */ + } /* if (not floating-point constant) */ + } + else if(c=='.' && !is_part_of_name(*input_line_pointer)) { + extern struct obstack frags; + + /* + JF: '.' is pseudo symbol with value of current location in current + segment. . . + */ + symbolP = symbol_new("L0\001", + (unsigned char)(seg_N_TYPE[(int)now_seg]), + 0, + 0, + (valueT)(obstack_next_free(&frags)-frag_now->fr_literal), + frag_now); + expressionP->X_add_number=0; + expressionP->X_add_symbol=symbolP; + expressionP->X_seg = now_seg; + + } else if ( is_name_beginner(c) ) /* here if did not begin with a digit */ + { + /* + * Identifier begins here. + * This is kludged for speed, so code is repeated. + */ + name = -- input_line_pointer; + c = get_symbol_end(); + symbolP = symbol_table_lookup(name); + if (symbolP) + { + /* + * If we have an absolute symbol, then we know it's value now. + */ + register segT seg; + + seg = N_TYPE_seg [(int) symbolP -> sy_type & N_TYPE]; + if ((expressionP -> X_seg = seg) == SEG_ABSOLUTE ) + { + expressionP -> X_add_number = symbolP -> sy_value; + } + else + { + expressionP -> X_add_number = 0; + expressionP -> X_add_symbol = symbolP; + } + } + else + { + expressionP -> X_add_symbol + = symbolP + = symbol_new (name, N_UNDF, 0,0,0, & zero_address_frag); + + expressionP -> X_add_number = 0; + expressionP -> X_seg = SEG_UNKNOWN; + symbol_table_insert (symbolP); + } + * input_line_pointer = c; + expressionP -> X_subtract_symbol = NULL; + } + else if (c=='(')/* didn't begin with digit & not a name */ + { + (void)expression( expressionP ); + /* Expression() will pass trailing whitespace */ + if ( * input_line_pointer ++ != ')' ) + { + as_warn( "Missing ')' assumed"); + input_line_pointer --; + } + /* here with input_line_pointer -> char after "(...)" */ + } + else if ( c=='~' || c=='-' ) + { /* unary operator: hope for SEG_ABSOLUTE */ + switch(operand (expressionP)) { + case SEG_ABSOLUTE: + /* input_line_pointer -> char after operand */ + if ( c=='-' ) + { + expressionP -> X_add_number = - expressionP -> X_add_number; +/* + * Notice: '-' may overflow: no warning is given. This is compatible + * with other people's assemblers. Sigh. + */ + } + else + { + expressionP -> X_add_number = ~ expressionP -> X_add_number; + } + break; + + case SEG_TEXT: + case SEG_DATA: + case SEG_BSS: + case SEG_PASS1: + case SEG_UNKNOWN: + if(c=='-') { /* JF I hope this hack works */ + expressionP->X_subtract_symbol=expressionP->X_add_symbol; + expressionP->X_add_symbol=0; + expressionP->X_seg=SEG_DIFFERENCE; + break; + } + default: /* unary on non-absolute is unsuported */ + as_warn("Unary operator %c ignored because bad operand follows", c); + break; + /* Expression undisturbed from operand(). */ + } + } + else if (c=='\'') + { +/* + * Warning: to conform to other people's assemblers NO ESCAPEMENT is permitted + * for a single quote. The next character, parity errors and all, is taken + * as the value of the operand. VERY KINKY. + */ + expressionP -> X_add_number = * input_line_pointer ++; + expressionP -> X_seg = SEG_ABSOLUTE; + } + else + { + /* can't imagine any other kind of operand */ + expressionP -> X_seg = SEG_NONE; + input_line_pointer --; + } +/* + * It is more 'efficient' to clean up the expressions when they are created. + * Doing it here saves lines of code. + */ + clean_up_expression (expressionP); + SKIP_WHITESPACE(); /* -> 1st char after operand. */ + know( * input_line_pointer != ' ' ); + return (expressionP -> X_seg); +} /* operand */ + +/* Internal. Simplify a struct expression for use by expr() */ + +/* + * In: address of a expressionS. + * The X_seg field of the expressionS may only take certain values. + * Now, we permit SEG_PASS1 to make code smaller & faster. + * Elsewise we waste time special-case testing. Sigh. Ditto SEG_NONE. + * Out: expressionS may have been modified: + * 'foo-foo' symbol references cancelled to 0, + * which changes X_seg from SEG_DIFFERENCE to SEG_ABSOLUTE; + * Unused fields zeroed to help expr(). + */ + +static void +clean_up_expression (expressionP) + register expressionS * expressionP; +{ + switch (expressionP -> X_seg) + { + case SEG_NONE: + case SEG_PASS1: + expressionP -> X_add_symbol = NULL; + expressionP -> X_subtract_symbol = NULL; + expressionP -> X_add_number = 0; + break; + + case SEG_BIG: + case SEG_ABSOLUTE: + expressionP -> X_subtract_symbol = NULL; + expressionP -> X_add_symbol = NULL; + break; + + case SEG_TEXT: + case SEG_DATA: + case SEG_BSS: + case SEG_UNKNOWN: + expressionP -> X_subtract_symbol = NULL; + break; + + case SEG_DIFFERENCE: + /* + * It does not hurt to 'cancel' NULL==NULL + * when comparing symbols for 'eq'ness. + * It is faster to re-cancel them to NULL + * than to check for this special case. + */ + if (expressionP -> X_subtract_symbol == expressionP -> X_add_symbol + || ( expressionP->X_subtract_symbol + && expressionP->X_add_symbol + && expressionP->X_subtract_symbol->sy_frag==expressionP->X_add_symbol->sy_frag + && expressionP->X_subtract_symbol->sy_value==expressionP->X_add_symbol->sy_value)) + { + expressionP -> X_subtract_symbol = NULL; + expressionP -> X_add_symbol = NULL; + expressionP -> X_seg = SEG_ABSOLUTE; + } + break; + + default: + BAD_CASE( expressionP -> X_seg); + break; + } +} + +/* + * expr_part () + * + * Internal. Made a function because this code is used in 2 places. + * Generate error or correct X_?????_symbol of expressionS. + */ + +/* + * symbol_1 += symbol_2 ... well ... sort of. + */ + +static segT +expr_part (symbol_1_PP, symbol_2_P) + struct symbol ** symbol_1_PP; + struct symbol * symbol_2_P; +{ + segT return_value; + + know( (* symbol_1_PP) == NULL + || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_TEXT + || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_DATA + || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_BSS + || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF + ); + know( symbol_2_P == NULL + || (symbol_2_P -> sy_type & N_TYPE) == N_TEXT + || (symbol_2_P -> sy_type & N_TYPE) == N_DATA + || (symbol_2_P -> sy_type & N_TYPE) == N_BSS + || (symbol_2_P -> sy_type & N_TYPE) == N_UNDF + ); + if (* symbol_1_PP) + { + if (((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF) + { + if (symbol_2_P) + { + return_value = SEG_PASS1; + * symbol_1_PP = NULL; + } + else + { + know( ((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF) + return_value = SEG_UNKNOWN; + } + } + else + { + if (symbol_2_P) + { + if ((symbol_2_P -> sy_type & N_TYPE) == N_UNDF) + { + * symbol_1_PP = NULL; + return_value = SEG_PASS1; + } + else + { + /* {seg1} - {seg2} */ + as_warn( "Expression too complex, 2 symbols forgotten: \"%s\" \"%s\"", + (* symbol_1_PP) -> sy_name, symbol_2_P -> sy_name ); + * symbol_1_PP = NULL; + return_value = SEG_ABSOLUTE; + } + } + else + { + return_value = N_TYPE_seg [(* symbol_1_PP) -> sy_type & N_TYPE]; + } + } + } + else + { /* (* symbol_1_PP) == NULL */ + if (symbol_2_P) + { + * symbol_1_PP = symbol_2_P; + return_value = N_TYPE_seg [(symbol_2_P) -> sy_type & N_TYPE]; + } + else + { + * symbol_1_PP = NULL; + return_value = SEG_ABSOLUTE; + } + } + know( return_value == SEG_ABSOLUTE + || return_value == SEG_TEXT + || return_value == SEG_DATA + || return_value == SEG_BSS + || return_value == SEG_UNKNOWN + || return_value == SEG_PASS1 + ); + know( (* symbol_1_PP) == NULL + || ((* symbol_1_PP) -> sy_type & N_TYPE) == seg_N_TYPE [(int) return_value] ); + return (return_value); +} /* expr_part() */ + +/* Expression parser. */ + +/* + * We allow an empty expression, and just assume (absolute,0) silently. + * Unary operators and parenthetical expressions are treated as operands. + * As usual, Q==quantity==operand, O==operator, X==expression mnemonics. + * + * We used to do a aho/ullman shift-reduce parser, but the logic got so + * warped that I flushed it and wrote a recursive-descent parser instead. + * Now things are stable, would anybody like to write a fast parser? + * Most expressions are either register (which does not even reach here) + * or 1 symbol. Then "symbol+constant" and "symbol-symbol" are common. + * So I guess it doesn't really matter how inefficient more complex expressions + * are parsed. + * + * After expr(RANK,resultP) input_line_pointer -> operator of rank <= RANK. + * Also, we have consumed any leading or trailing spaces (operand does that) + * and done all intervening operators. + */ + +typedef enum +{ +O_illegal, /* (0) what we get for illegal op */ + +O_multiply, /* (1) * */ +O_divide, /* (2) / */ +O_modulus, /* (3) % */ +O_left_shift, /* (4) < */ +O_right_shift, /* (5) > */ +O_bit_inclusive_or, /* (6) | */ +O_bit_or_not, /* (7) ! */ +O_bit_exclusive_or, /* (8) ^ */ +O_bit_and, /* (9) & */ +O_add, /* (10) + */ +O_subtract /* (11) - */ +} +operatorT; + +#define __ O_illegal + +static const operatorT op_encoding [256] = { /* maps ASCII -> operators */ + +__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, +__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + +__, O_bit_or_not, __, __, __, O_modulus, O_bit_and, __, +__, __, O_multiply, O_add, __, O_subtract, __, O_divide, +__, __, __, __, __, __, __, __, +__, __, __, __, O_left_shift, __, O_right_shift, __, +__, __, __, __, __, __, __, __, +__, __, __, __, __, __, __, __, +__, __, __, __, __, __, __, __, +__, __, __, __, __, __, O_bit_exclusive_or, __, +__, __, __, __, __, __, __, __, +__, __, __, __, __, __, __, __, +__, __, __, __, __, __, __, __, +__, __, __, __, O_bit_inclusive_or, __, __, __, + +__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, +__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, +__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, +__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, +__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, +__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, +__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, +__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __ +}; + + +/* + * Rank Examples + * 0 operand, (expression) + * 1 + - + * 2 & ^ ! | + * 3 * / % < > + */ +typedef char operator_rankT; +static const operator_rankT +op_rank [] = { 0, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1 }; + +segT /* Return resultP -> X_seg. */ +expr (rank, resultP) + register operator_rankT rank; /* Larger # is higher rank. */ + register expressionS * resultP; /* Deliver result here. */ +{ + expressionS right; + register operatorT op_left; + register char c_left; /* 1st operator character. */ + register operatorT op_right; + register char c_right; + + know( rank >= 0 ); + (void)operand (resultP); + know( * input_line_pointer != ' ' ); /* Operand() gobbles spaces. */ + c_left = * input_line_pointer; /* Potential operator character. */ + op_left = op_encoding [c_left]; + while (op_left != O_illegal && op_rank [(int) op_left] > rank) + { + input_line_pointer ++; /* -> after 1st character of operator. */ + /* Operators "<<" and ">>" have 2 characters. */ + if (* input_line_pointer == c_left && (c_left == '<' || c_left == '>') ) + { + input_line_pointer ++; + } /* -> after operator. */ + if (SEG_NONE == expr (op_rank[(int) op_left], &right)) + { + as_warn("Missing operand value assumed absolute 0."); + resultP -> X_add_number = 0; + resultP -> X_subtract_symbol = NULL; + resultP -> X_add_symbol = NULL; + resultP -> X_seg = SEG_ABSOLUTE; + } + know( * input_line_pointer != ' ' ); + c_right = * input_line_pointer; + op_right = op_encoding [c_right]; + if (* input_line_pointer == c_right && (c_right == '<' || c_right == '>') ) + { + input_line_pointer ++; + } /* -> after operator. */ + know( (int) op_right == 0 + || op_rank [(int) op_right] <= op_rank[(int) op_left] ); + /* input_line_pointer -> after right-hand quantity. */ + /* left-hand quantity in resultP */ + /* right-hand quantity in right. */ + /* operator in op_left. */ + if ( resultP -> X_seg == SEG_PASS1 || right . X_seg == SEG_PASS1 ) + { + resultP -> X_seg = SEG_PASS1; + } + else + { + if ( resultP -> X_seg == SEG_BIG ) + { + as_warn( "Left operand of %c is a %s. Integer 0 assumed.", + c_left, resultP -> X_add_number > 0 ? "bignum" : "float"); + resultP -> X_seg = SEG_ABSOLUTE; + resultP -> X_add_symbol = 0; + resultP -> X_subtract_symbol = 0; + resultP -> X_add_number = 0; + } + if ( right . X_seg == SEG_BIG ) + { + as_warn( "Right operand of %c is a %s. Integer 0 assumed.", + c_left, right . X_add_number > 0 ? "bignum" : "float"); + right . X_seg = SEG_ABSOLUTE; + right . X_add_symbol = 0; + right . X_subtract_symbol = 0; + right . X_add_number = 0; + } + if ( op_left == O_subtract ) + { + /* + * Convert - into + by exchanging symbols and negating number. + * I know -infinity can't be negated in 2's complement: + * but then it can't be subtracted either. This trick + * does not cause any further inaccuracy. + */ + + register struct symbol * symbolP; + + right . X_add_number = - right . X_add_number; + symbolP = right . X_add_symbol; + right . X_add_symbol = right . X_subtract_symbol; + right . X_subtract_symbol = symbolP; + if (symbolP) + { + right . X_seg = SEG_DIFFERENCE; + } + op_left = O_add; + } + + if ( op_left == O_add ) + { + segT seg1; + segT seg2; + + know( resultP -> X_seg == SEG_DATA + || resultP -> X_seg == SEG_TEXT + || resultP -> X_seg == SEG_BSS + || resultP -> X_seg == SEG_UNKNOWN + || resultP -> X_seg == SEG_DIFFERENCE + || resultP -> X_seg == SEG_ABSOLUTE + || resultP -> X_seg == SEG_PASS1 + ); + know( right . X_seg == SEG_DATA + || right . X_seg == SEG_TEXT + || right . X_seg == SEG_BSS + || right . X_seg == SEG_UNKNOWN + || right . X_seg == SEG_DIFFERENCE + || right . X_seg == SEG_ABSOLUTE + || right . X_seg == SEG_PASS1 + ); + + clean_up_expression (& right); + clean_up_expression (resultP); + + seg1 = expr_part (& resultP -> X_add_symbol, right . X_add_symbol); + seg2 = expr_part (& resultP -> X_subtract_symbol, right . X_subtract_symbol); + if (seg1 == SEG_PASS1 || seg2 == SEG_PASS1) { + need_pass_2 = TRUE; + resultP -> X_seg = SEG_PASS1; + } else if (seg2 == SEG_ABSOLUTE) + resultP -> X_seg = seg1; + else if ( seg1 != SEG_UNKNOWN + && seg1 != SEG_ABSOLUTE + && seg2 != SEG_UNKNOWN + && seg1 != seg2) { + know( seg2 != SEG_ABSOLUTE ); + know( resultP -> X_subtract_symbol ); + + know( seg1 == SEG_TEXT || seg1 == SEG_DATA || seg1== SEG_BSS ); + know( seg2 == SEG_TEXT || seg2 == SEG_DATA || seg2== SEG_BSS ); + know( resultP -> X_add_symbol ); + know( resultP -> X_subtract_symbol ); + as_warn("Expression too complex: forgetting %s - %s", + resultP -> X_add_symbol -> sy_name, + resultP -> X_subtract_symbol -> sy_name); + resultP -> X_seg = SEG_ABSOLUTE; + /* Clean_up_expression() will do the rest. */ + } else + resultP -> X_seg = SEG_DIFFERENCE; + + resultP -> X_add_number += right . X_add_number; + clean_up_expression (resultP); + } + else + { /* Not +. */ + if ( resultP -> X_seg == SEG_UNKNOWN || right . X_seg == SEG_UNKNOWN ) + { + resultP -> X_seg = SEG_PASS1; + need_pass_2 = TRUE; + } + else + { + resultP -> X_subtract_symbol = NULL; + resultP -> X_add_symbol = NULL; + /* Will be SEG_ABSOLUTE. */ + if ( resultP -> X_seg != SEG_ABSOLUTE || right . X_seg != SEG_ABSOLUTE ) + { + as_warn( "Relocation error. Absolute 0 assumed."); + resultP -> X_seg = SEG_ABSOLUTE; + resultP -> X_add_number = 0; + } + else + { + switch ( op_left ) + { + case O_bit_inclusive_or: + resultP -> X_add_number |= right . X_add_number; + break; + + case O_modulus: + if (right . X_add_number) + { + resultP -> X_add_number %= right . X_add_number; + } + else + { + as_warn( "Division by 0. 0 assumed." ); + resultP -> X_add_number = 0; + } + break; + + case O_bit_and: + resultP -> X_add_number &= right . X_add_number; + break; + + case O_multiply: + resultP -> X_add_number *= right . X_add_number; + break; + + case O_divide: + if (right . X_add_number) + { + resultP -> X_add_number /= right . X_add_number; + } + else + { + as_warn( "Division by 0. 0 assumed." ); + resultP -> X_add_number = 0; + } + break; + + case O_left_shift: + resultP -> X_add_number <<= right . X_add_number; + break; + + case O_right_shift: + resultP -> X_add_number >>= right . X_add_number; + break; + + case O_bit_exclusive_or: + resultP -> X_add_number ^= right . X_add_number; + break; + + case O_bit_or_not: + resultP -> X_add_number |= ~ right . X_add_number; + break; + + default: + BAD_CASE( op_left ); + break; + } /* switch(operator) */ + } + } /* If we have to force need_pass_2. */ + } /* If operator was +. */ + } /* If we didn't set need_pass_2. */ + op_left = op_right; + } /* While next operator is >= this rank. */ + return (resultP -> X_seg); +} + +/* + * get_symbol_end() + * + * This lives here because it belongs equally in expr.c & read.c. + * Expr.c is just a branch office read.c anyway, and putting it + * here lessens the crowd at read.c. + * + * Assume input_line_pointer is at start of symbol name. + * Advance input_line_pointer past symbol name. + * Turn that character into a '\0', returning its former value. + * This allows a string compare (RMS wants symbol names to be strings) + * of the symbol name. + * There will always be a char following symbol name, because all good + * lines end in end-of-line. + */ +char +get_symbol_end() +{ + register char c; + + while ( is_part_of_name( c = * input_line_pointer ++ ) ) + ; + * -- input_line_pointer = 0; + return (c); +} + +/* end: expr.c */ diff --git a/gnu/usr.bin/as/expr.h b/gnu/usr.bin/as/expr.h new file mode 100644 index 0000000..964d3b9 --- /dev/null +++ b/gnu/usr.bin/as/expr.h @@ -0,0 +1,69 @@ +/* expr.h -> header file for expr.c + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Abbreviations (mnemonics). + * + * O operator + * Q quantity, operand + * X eXpression + */ + +/* + * By popular demand, we define a struct to represent an expression. + * This will no doubt mutate as expressions become baroque. + * + * Currently, we support expressions like "foo-bar+42". + * In other words we permit a (possibly undefined) minuend, a + * (possibly undefined) subtrahend and an (absolute) augend. + * RMS says this is so we can have 1-pass assembly for any compiler + * emmissions, and a 'case' statement might emit 'undefined1 - undefined2'. + * + * To simplify table-driven dispatch, we also have a "segment" for the + * entire expression. That way we don't require complex reasoning about + * whether particular components are defined; and we can change component + * semantics without re-working all the dispatch tables in the assembler. + * In other words the "type" of an expression is its segment. + */ + +typedef struct +{ + symbolS *X_add_symbol; /* foo */ + symbolS *X_subtract_symbol; /* bar */ + long int X_add_number; /* 42. Must be signed. */ + segT X_seg; /* What segment (expr type)? */ +} +expressionS; + + /* result should be type (expressionS *). */ +#define expression(result) expr(0,result) + + /* If an expression is SEG_BIG, look here */ + /* for its value. These common data may */ + /* be clobbered whenever expr() is called. */ +extern FLONUM_TYPE generic_floating_point_number; /* Flonums returned here. */ + /* Enough to hold most precise flonum. */ +extern LITTLENUM_TYPE generic_bignum []; /* Bignums returned here. */ +#define SIZE_OF_LARGE_NUMBER (20) /* Number of littlenums in above. */ + + +segT expr(); +char get_symbol_end(); + +/* end: expr.h */ diff --git a/gnu/usr.bin/as/flonum-const.c b/gnu/usr.bin/as/flonum-const.c new file mode 100644 index 0000000..617e585 --- /dev/null +++ b/gnu/usr.bin/as/flonum-const.c @@ -0,0 +1,157 @@ +/* flonum_const.c - Useful Flonum constants + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "flonum.h" +/* JF: I added the last entry to this table, and I'm not + sure if its right or not. Could go either way. I wish + I really understood this stuff. */ + + +const int table_size_of_flonum_powers_of_ten = 11; + +static const LITTLENUM_TYPE zero[] = { 1 }; + +/***********************************************************************\ +* * +* Warning: the low order bits may be WRONG here. * +* I took this from a suspect bc(1) script. * +* "minus_X"[] is supposed to be 10^(2^-X) expressed in base 2^16. * +* The radix point is just AFTER the highest element of the [] * +* * +* Because bc rounds DOWN for printing (I think), the lowest * +* significance littlenums should probably have 1 added to them. * +* * +\***********************************************************************/ + +/* JF: If this equals 6553/(2^16)+39321/(2^32)+... it approaches .1 */ +static const LITTLENUM_TYPE minus_1 [] = { + 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, + 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 6553 }; +static const LITTLENUM_TYPE plus_1 [] = { 10 }; + +/* JF: If this equals 655/(2^16) + 23592/(2^32) + ... it approaches .01 */ +static const LITTLENUM_TYPE minus_2 [] = { + 10485, 36700, 62914, 23592, 49807, 10485, 36700, 62914, 23592, 49807, + 10485, 36700, 62914, 23592, 49807, 10485, 36700, 62914, 23592, 655 }; +static const LITTLENUM_TYPE plus_2 [] = { 100 }; + +/* This approaches .0001 */ +static const LITTLENUM_TYPE minus_3 [] = { + 52533, 20027, 37329, 65116, 64067, 60397, 14784, 18979, 33659, 19503, + 2726, 9542, 629, 2202, 40475, 10590, 4299, 47815, 36280, 6 }; +static const LITTLENUM_TYPE plus_3 [] = { 10000 }; + +/* JF: this approaches 1e-8 */ +static const LITTLENUM_TYPE minus_4 [] = { + 22516, 49501, 54293, 19424, 60699, 6716, 24348, 22618, 23904, 21327, + 3919, 44703, 19149, 28803, 48959, 6259, 50273, 62237, 42 }; +/* This equals 1525 * 2^16 + 57600 */ +static const LITTLENUM_TYPE plus_4 [] = { 57600, 1525 }; + +/* This approaches 1e-16 */ +static const LITTLENUM_TYPE minus_5 [] = { + 22199, 45957, 17005, 26266, 10526, 16260, 55017, 35680, 40443, 19789, + 17356, 30195, 55905, 28426, 63010, 44197, 1844 }; +static const LITTLENUM_TYPE plus_5 [] = { 28609, 34546, 35 }; + +static const LITTLENUM_TYPE minus_6 [] = { + 30926, 26518, 13110, 43018, 54982, 48258, 24658, 15209, 63366, 11929, + 20069, 43857, 60487, 51 }; +static const LITTLENUM_TYPE plus_6 [] = { 61313, 34220, 16731, 11629, 1262 }; + +static const LITTLENUM_TYPE minus_7 [] = { + 29819, 14733, 21490, 40602, 31315, 65186, 2695 }; +static const LITTLENUM_TYPE plus_7 [] = { + 7937, 49002, 60772, 28216, 38893, 55975, 63988, 59711, 20227, 24 }; + +static const LITTLENUM_TYPE minus_8 [] = { + 45849, 19069, 18068, 36324, 37948, 48745, 10873, 64360, 15961, 20566, + 24178, 15922, 59427, 110 }; +static const LITTLENUM_TYPE plus_8 [] = { + 15873, 11925, 39177, 991, 14589, 19735, 25347, 65086, 53853, 938, + 37209, 47086, 33626, 23253, 32586, 42547, 9731, 59679, 590 }; + +static const LITTLENUM_TYPE minus_9 [] = { + 63601, 55221, 43562, 33661, 29067, 28203, 65417, 64352, 22462, 41110, + 12570, 28635, 23199, 50572, 28471, 27074, 46375, 64028, 13106, 63700, + 32698, 17493, 32420, 34382, 22750, 20681, 12300 }; +static const LITTLENUM_TYPE plus_9 [] = { + 63564, 61556, 29377, 54467, 18621, 28141, 36415, 61241, 47119, 30026, + 19740, 46002, 13541, 61413, 30480, 38664, 32205, 50593, 51112, 48904, + 48263, 43814, 286, 30826, 52813, 62575, 61390, 24540, 21495, 5 }; + +static const LITTLENUM_TYPE minus_10 [] = { + 50313, 34681, 1464, 25889, 19575, 41125, 17635, 4598, 49708, 13427, + 17287, 56115, 53783, 38255, 32415, 17778, 31596, 7557, 20951, 18477, + 40353, 1178, 44405, 11837, 11571, 50963, 15649, 11698, 40675, 2308, }; +static const LITTLENUM_TYPE plus_10[] = { +18520, 53764, 54535, 61910, 61962, 59843, 46270, 58053, 12473, 63785, + 2449, 43230, 50044, 47595, 10403, 35766, 32607, 1124, 24966, 35044, +25524, 23631, 18826, 14518, 58448, 14562, 49618, 5588, 25396, 28 }; + +static const LITTLENUM_TYPE minus_11 [] = { + 6223, 59909, 62437, 59960, 14652, 45336, 48800, 7647, 51962, 37982, + 60436, 58176, 26767, 8440, 9831, 48556, 20994, 14148, 6757, 17221, + 60624, 46129, 53210, 44085, 54016, 24259, 11232, 21229, 21313, 81, }; +static const LITTLENUM_TYPE plus_11 [] = { + 36159, 2055, 33615, 61362, 23581, 62454, 9748, 15275, 39284, 58636, + 16269, 42793, 47240, 45774, 50861, 48400, 9413, 40281, 4030, 9572, + 7984, 33038, 59522, 19450, 40593, 24486, 54320, 6661, 55766, 805, }; + +/* Shut up complaints about differing pointer types. They only differ + in the const attribute, but there isn't any easy way to do this + */ +#define X (LITTLENUM_TYPE *) + +const FLONUM_TYPE flonum_negative_powers_of_ten [] = { + {X zero, X zero, X zero, 0, '+'}, + {X minus_1, X minus_1 +19, X minus_1 + 19, -20, '+'}, + {X minus_2, X minus_2 +19, X minus_2 + 19, -20, '+'}, + {X minus_3, X minus_3 +19, X minus_3 + 19, -20, '+'}, + {X minus_4, X minus_4 +18, X minus_4 + 18, -20, '+'}, + {X minus_5, X minus_5 +16, X minus_5 + 16, -20, '+'}, + {X minus_6, X minus_6 +13, X minus_6 + 13, -20, '+'}, + {X minus_7, X minus_7 + 6, X minus_7 + 6, -20, '+'}, + {X minus_8, X minus_8 +13, X minus_8 + 13, -40, '+'}, + {X minus_9, X minus_9 +26, X minus_9 + 26, -80, '+'}, + {X minus_10, X minus_10+29, X minus_10 + 29,-136, '+'}, + {X minus_11, X minus_11+29, X minus_11 + 29,-242, '+'}, +}; + +const FLONUM_TYPE flonum_positive_powers_of_ten [] = { + {X zero, X zero, X zero, 0, '+'}, + {X plus_1, X plus_1 + 0, X plus_1 + 0, 0, '+'}, + {X plus_2, X plus_2 + 0, X plus_2 + 0, 0, '+'}, + {X plus_3, X plus_3 + 0, X plus_3 + 0, 0, '+'}, + {X plus_4, X plus_4 + 1, X plus_4 + 1, 0, '+'}, + {X plus_5, X plus_5 + 2, X plus_5 + 2, 1, '+'}, + {X plus_6, X plus_6 + 4, X plus_6 + 4, 2, '+'}, + {X plus_7, X plus_7 + 9, X plus_7 + 9, 4, '+'}, + {X plus_8, X plus_8 + 18, X plus_8 + 18, 8, '+'}, + {X plus_9, X plus_9 + 29, X plus_9 + 29, 24, '+'}, + {X plus_10, X plus_10 + 29, X plus_10 + 29, 77, '+'}, + {X plus_11, X plus_11 + 29, X plus_11 + 29, 183, '+'}, +}; + +#ifdef VMS +dummy1() +{ +} +#endif +/* end: flonum_const.c */ diff --git a/gnu/usr.bin/as/flonum-copy.c b/gnu/usr.bin/as/flonum-copy.c new file mode 100644 index 0000000..3a51f06 --- /dev/null +++ b/gnu/usr.bin/as/flonum-copy.c @@ -0,0 +1,76 @@ +/* flonum_copy.c - copy a flonum + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "flonum.h" +#ifdef USG +#define bzero(s,n) memset(s,0,n) +#define bcopy(from,to,n) memcpy(to,from,n) +#endif + +void +flonum_copy (in, out) + FLONUM_TYPE * in; + FLONUM_TYPE * out; +{ + int in_length; /* 0 origin */ + int out_length; /* 0 origin */ + + out -> sign = in -> sign; + in_length = in -> leader - in -> low; + if (in_length < 0) + { + out -> leader = out -> low - 1; /* 0.0 case */ + } + else + { + out_length = out -> high - out -> low; + /* + * Assume no GAPS in packing of littlenums. + * I.e. sizeof(array) == sizeof(element) * number_of_elements. + */ + if (in_length <= out_length) + { + { + /* + * For defensive programming, zero any high-order littlenums we don't need. + * This is destroying evidence and wasting time, so why bother??? + */ + if (in_length < out_length) + { + bzero ((char *)(out->low + in_length + 1), out_length - in_length); + } + } + bcopy ((char *)(in->low), (char *)(out->low), (int)((in_length + 1) * sizeof(LITTLENUM_TYPE))); + out -> exponent = in -> exponent; + out -> leader = in -> leader - in -> low + out -> low; + } + else + { + int shorten; /* 1-origin. Number of littlenums we drop. */ + + shorten = in_length - out_length; + /* Assume out_length >= 0 ! */ + bcopy ((char *)(in->low + shorten),(char *)( out->low), (int)((out_length + 1) * sizeof(LITTLENUM_TYPE))); + out -> leader = out -> high; + out -> exponent = in -> exponent + shorten; + } + } /* if any significant bits */ +} + +/* end: flonum_copy.c */ diff --git a/gnu/usr.bin/as/flonum-mult.c b/gnu/usr.bin/as/flonum-mult.c new file mode 100644 index 0000000..1b7b5ea --- /dev/null +++ b/gnu/usr.bin/as/flonum-mult.c @@ -0,0 +1,200 @@ +/* flonum_multip.c - multiply two flonums + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of Gas, the GNU Assembler. + +The GNU assembler is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY. No author or distributor +accepts responsibility to anyone for the consequences of using it +or for whether it serves any particular purpose or works at all, +unless he says so in writing. Refer to the GNU Assembler General +Public License for full details. + +Everyone is granted permission to copy, modify and redistribute +the GNU Assembler, but only under the conditions described in the +GNU Assembler General Public License. A copy of this license is +supposed to have been given to you along with the GNU Assembler +so you can know your rights and responsibilities. It should be +in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. */ + +#include "flonum.h" + +/* plan for a . b => p(roduct) + + + +-------+-------+-/ /-+-------+-------+ + | a | a | ... | a | a | + | A | A-1 | | 1 | 0 | + +-------+-------+-/ /-+-------+-------+ + + + +-------+-------+-/ /-+-------+-------+ + | b | b | ... | b | b | + | B | B-1 | | 1 | 0 | + +-------+-------+-/ /-+-------+-------+ + + + +-------+-------+-/ /-+-------+-/ /-+-------+-------+ + | p | p | ... | p | ... | p | p | + | A+B+1| A+B | | N | | 1 | 0 | + +-------+-------+-/ /-+-------+-/ /-+-------+-------+ + + /^\ + (carry) a .b ... | ... a .b a .b + A B | 0 1 0 0 + | + ... | ... a .b + | 1 0 + | + | ... + | + | + | + | ___ + | \ + +----- P = > a .b + N /__ i j + + N = 0 ... A+B + + for all i,j where i+j=N + [i,j integers > 0] + +a[], b[], p[] may not intersect. +Zero length factors signify 0 significant bits: treat as 0.0. +0.0 factors do the right thing. +Zero length product OK. + +I chose the ForTran accent "foo[bar]" instead of the C accent "*garply" +because I felt the ForTran way was more intuitive. The C way would +probably yield better code on most C compilers. Dean Elsner. +(C style also gives deeper insight [to me] ... oh well ...) +*/ + +void +flonum_multip (a, b, product) + FLONUM_TYPE * a, + * b, + * product; +{ + int size_of_a; /* 0 origin */ + int size_of_b; /* 0 origin */ + int size_of_product; /* 0 origin */ + int size_of_sum; /* 0 origin */ + int extra_product_positions;/* 1 origin */ + unsigned long int work; + unsigned long int carry; + long int exponent; + LITTLENUM_TYPE * q; + long int significant; /* TRUE when we emit a non-0 littlenum */ + /* ForTran accent follows. */ + int P; /* Scan product low-order -> high. */ + int N; /* As in sum above. */ + int A; /* Which [] of a? */ + int B; /* Which [] of b? */ + + if((a->sign!='-' && a->sign!='+') || (b->sign!='-' && b->sign!='+')) { + /* ... + Got to fail somehow. Any suggestions? */ + product->sign=0; + return; + } + product -> sign = (a->sign == b->sign) ? '+' : '-'; + size_of_a = a -> leader - a -> low; + size_of_b = b -> leader - b -> low; + exponent = a -> exponent + b -> exponent; + size_of_product = product -> high - product -> low; + size_of_sum = size_of_a + size_of_b; + extra_product_positions = size_of_product - size_of_sum; + if (extra_product_positions < 0) + { + P = extra_product_positions; /* P < 0 */ + exponent -= extra_product_positions; /* Increases exponent. */ + } + else + { + P = 0; + } + carry = 0; + significant = 0; + for (N = 0; + N <= size_of_sum; + N++) + { + work = carry; + carry = 0; + for (A = 0; + A <= N; + A ++) + { + B = N - A; + if (A <= size_of_a && B <= size_of_b && B >= 0) + { +#ifdef TRACE +printf("a:low[%d.]=%04x b:low[%d.]=%04x work_before=%08x\n", A, a->low[A], B, b->low[B], work); +#endif + work += a -> low [A] * b -> low [B]; + carry += work >> LITTLENUM_NUMBER_OF_BITS; + work &= LITTLENUM_MASK; +#ifdef TRACE +printf("work=%08x carry=%04x\n", work, carry); +#endif + } + } + significant |= work; + if (significant || P<0) + { + if (P >= 0) + { + product -> low [P] = work; +#ifdef TRACE +printf("P=%d. work[p]:=%04x\n", P, work); +#endif + } + P ++; + } + else + { + extra_product_positions ++; + exponent ++; + } + } + /* + * [P]-> position # size_of_sum + 1. + * This is where 'carry' should go. + */ +#ifdef TRACE +printf("final carry =%04x\n", carry); +#endif + if (carry) + { + if (extra_product_positions > 0) + { + product -> low [P] = carry; + } + else + { + /* No room at high order for carry littlenum. */ + /* Shift right 1 to make room for most significant littlenum. */ + exponent ++; + P --; + for (q = product -> low + P; + q >= product -> low; + q --) + { + work = * q; + * q = carry; + carry = work; + } + } + } + else + { + P --; + } + product -> leader = product -> low + P; + product -> exponent = exponent; +} + +/* end: flonum_multip.c */ diff --git a/gnu/usr.bin/as/flonum.h b/gnu/usr.bin/as/flonum.h new file mode 100644 index 0000000..b2e841a --- /dev/null +++ b/gnu/usr.bin/as/flonum.h @@ -0,0 +1,111 @@ +/* flonum.h - Floating point package + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/***********************************************************************\ +* * +* Arbitrary-precision floating point arithmetic. * +* * +* * +* Notation: a floating point number is expressed as * +* MANTISSA * (2 ** EXPONENT). * +* * +* If this offends more traditional mathematicians, then * +* please tell me your nomenclature for flonums! * +* * +\***********************************************************************/ +#if !defined(__STDC__) && !defined(const) +#define const /* empty */ +#endif + +#include "bignum.h" + +/***********************************************************************\ +* * +* Variable precision floating point numbers. * +* * +* Exponent is the place value of the low littlenum. E.g.: * +* If 0: low points to the units littlenum. * +* If 1: low points to the LITTLENUM_RADIX littlenum. * +* If -1: low points to the 1/LITTLENUM_RADIX littlenum. * +* * +\***********************************************************************/ + +/* JF: A sign value of 0 means we have been asked to assemble NaN + A sign value of 'P' means we've been asked to assemble +Inf + A sign value of 'N' means we've been asked to assemble -Inf + */ +struct FLONUM_STRUCT +{ + LITTLENUM_TYPE * low; /* low order littlenum of a bignum */ + LITTLENUM_TYPE * high; /* high order littlenum of a bignum */ + LITTLENUM_TYPE * leader; /* -> 1st non-zero littlenum */ + /* If flonum is 0.0, leader==low-1 */ + long int exponent; /* base LITTLENUM_RADIX */ + char sign; /* '+' or '-' */ +}; + +typedef struct FLONUM_STRUCT FLONUM_TYPE; + + +/***********************************************************************\ +* * +* Since we can (& do) meet with exponents like 10^5000, it * +* is silly to make a table of ~ 10,000 entries, one for each * +* power of 10. We keep a table where item [n] is a struct * +* FLONUM_FLOATING_POINT representing 10^(2^n). We then * +* multiply appropriate entries from this table to get any * +* particular power of 10. For the example of 10^5000, a table * +* of just 25 entries suffices: 10^(2^-12)...10^(2^+12). * +* * +\***********************************************************************/ + + +extern const FLONUM_TYPE flonum_positive_powers_of_ten[]; +extern const FLONUM_TYPE flonum_negative_powers_of_ten[]; +extern const int table_size_of_flonum_powers_of_ten; + /* Flonum_XXX_powers_of_ten[] table has */ + /* legal indices from 0 to */ + /* + this number inclusive. */ + + + +/***********************************************************************\ +* * +* Declare worker functions. * +* * +\***********************************************************************/ + +void flonum_multip(); +void flonum_copy(); +void flonum_print(); +char * flonum_get(); /* Returns "" or error string. */ +void flonum_normal(); + +int atof_generic(); + + +/***********************************************************************\ +* * +* Declare error codes. * +* * +\***********************************************************************/ + +#define ERROR_EXPONENT_OVERFLOW (2) + +/* end: flonum.h */ diff --git a/gnu/usr.bin/as/frags.c b/gnu/usr.bin/as/frags.c new file mode 100644 index 0000000..ee10321 --- /dev/null +++ b/gnu/usr.bin/as/frags.c @@ -0,0 +1,292 @@ +/* frags.c - manage frags - + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "as.h" +#include "subsegs.h" +#include "obstack.h" +#include "frags.h" +#include "struc-symbol.h" + +struct obstack frags; /* All, and only, frags live here. */ + +fragS zero_address_frag = { + 0, /* fr_address */ + NULL, /* fr_next */ + 0, /* fr_fix */ + 0, /* fr_var */ + 0, /* fr_symbol */ + 0, /* fr_offset */ + NULL, /* fr_opcode */ + rs_fill, /* fr_type */ + 0, /* fr_subtype */ + 0, /* fr_pcrel_adjust */ + 0, /* fr_bsr */ + 0 /* fr_literal [0] */ +}; + +fragS bss_address_frag = { + 0, /* fr_address. Gets filled in to make up + sy_value-s. */ + NULL, /* fr_next */ + 0, /* fr_fix */ + 0, /* fr_var */ + 0, /* fr_symbol */ + 0, /* fr_offset */ + NULL, /* fr_opcode */ + rs_fill, /* fr_type */ + 0, /* fr_subtype */ + 0, /* fr_pcrel_adjust */ + 0, /* fr_bsr */ + 0 /* fr_literal [0] */ +}; + +/* + * frag_grow() + * + * Internal. + * Try to augment current frag by nchars chars. + * If there is no room, close of the current frag with a ".fill 0" + * and begin a new frag. Unless the new frag has nchars chars available + * do not return. Do not set up any fields of *now_frag. + */ +static void +frag_grow (nchars) +int nchars; +{ + if (obstack_room (&frags) < nchars) { + unsigned int n,oldn; + long oldc; + + frag_wane (frag_now); + frag_new (0); + oldn=(unsigned)-1; + oldc=frags.chunk_size; + frags.chunk_size=2*nchars; + while((n=obstack_room(&frags))<nchars && n<oldn) { + frag_wane(frag_now); + frag_new(0); + oldn=n; + } + frags.chunk_size=oldc; + } + if (obstack_room (&frags) < nchars) + as_fatal ("Can't extend frag %d. chars", nchars); +} + +/* + * frag_new() + * + * Call this to close off a completed frag, and start up a new (empty) + * frag, in the same subsegment as the old frag. + * [frchain_now remains the same but frag_now is updated.] + * Because this calculates the correct value of fr_fix by + * looking at the obstack 'frags', it needs to know how many + * characters at the end of the old frag belong to (the maximal) + * fr_var: the rest must belong to fr_fix. + * It doesn't actually set up the old frag's fr_var: you may have + * set fr_var == 1, but allocated 10 chars to the end of the frag: + * in this case you pass old_frags_var_max_size == 10. + * + * Make a new frag, initialising some components. Link new frag at end + * of frchain_now. + */ +void +frag_new (old_frags_var_max_size) +int old_frags_var_max_size; /* Number of chars (already allocated on + obstack frags) */ + /* in variable_length part of frag. */ +{ + register fragS * former_last_fragP; +/* char *throw_away_pointer; JF unused */ + register frchainS * frchP; + long tmp; /* JF */ + + frag_now->fr_fix = (char *) (obstack_next_free (&frags)) - + (frag_now->fr_literal) - old_frags_var_max_size; + /* Fix up old frag's fr_fix. */ + + obstack_finish (&frags); + /* This will align the obstack so the */ + /* next struct we allocate on it will */ + /* begin at a correct boundary. */ + frchP = frchain_now; + know (frchP); + former_last_fragP = frchP->frch_last; + know (former_last_fragP); + know (former_last_fragP == frag_now); + obstack_blank (&frags, SIZEOF_STRUCT_FRAG); + /* We expect this will begin at a correct */ + /* boundary for a struct. */ + tmp=obstack_alignment_mask(&frags); + obstack_alignment_mask(&frags)=0; /* Turn off alignment */ + /* If we ever hit a machine + where strings must be + aligned, we Lose Big */ + frag_now=(fragS *)obstack_finish(&frags); + obstack_alignment_mask(&frags)=tmp; /* Restore alignment */ + + /* Just in case we don't get zero'd bytes */ + bzero(frag_now, SIZEOF_STRUCT_FRAG); + +/* obstack_unaligned_done (&frags, &frag_now); */ +/* know (frags.obstack_c_next_free == frag_now->fr_literal); */ + /* Generally, frag_now->points to an */ + /* address rounded up to next alignment. */ + /* However, characters will add to obstack */ + /* frags IMMEDIATELY after the struct frag, */ + /* even if they are not starting at an */ + /* alignment address. */ + former_last_fragP->fr_next = frag_now; + frchP->frch_last = frag_now; + frag_now->fr_next = NULL; +} /* frag_new() */ + +/* + * frag_more() + * + * Start a new frag unless we have n more chars of room in the current frag. + * Close off the old frag with a .fill 0. + * + * Return the address of the 1st char to write into. Advance + * frag_now_growth past the new chars. + */ + +char * +frag_more (nchars) +int nchars; +{ + register char *retval; + + frag_grow (nchars); + retval = obstack_next_free (&frags); + obstack_blank_fast (&frags, nchars); + return (retval); +} /* frag_more() */ + +/* + * frag_var() + * + * Start a new frag unless we have max_chars more chars of room in the current frag. + * Close off the old frag with a .fill 0. + * + * Set up a machine_dependent relaxable frag, then start a new frag. + * Return the address of the 1st char of the var part of the old frag + * to write into. + */ + +char * +frag_var (type, max_chars, var, subtype, symbol, offset, opcode) +relax_stateT type; +int max_chars; +int var; +relax_substateT subtype; +symbolS * symbol; +long int offset; +char * opcode; +{ + register char *retval; + + frag_grow (max_chars); + retval = obstack_next_free (&frags); + obstack_blank_fast (&frags, max_chars); + frag_now->fr_var = var; + frag_now->fr_type = type; + frag_now->fr_subtype = subtype; + frag_now->fr_symbol = symbol; + frag_now->fr_offset = offset; + frag_now->fr_opcode = opcode; + /* default these to zero. */ + frag_now->fr_pcrel_adjust = 0; + frag_now->fr_bsr = 0; + frag_new (max_chars); + return (retval); +} /* frag_var() */ + +/* + * frag_variant() + * + * OVE: This variant of frag_var assumes that space for the tail has been + * allocated by caller. + * No call to frag_grow is done. + * Two new arguments have been added. + */ + +char * +frag_variant (type, max_chars, var, subtype, symbol, offset, opcode, pcrel_adjust,bsr) + relax_stateT type; + int max_chars; + int var; + relax_substateT subtype; + symbolS *symbol; + long int offset; + char *opcode; + char pcrel_adjust; + char bsr; +{ + register char *retval; + +/* frag_grow (max_chars); */ + retval = obstack_next_free (&frags); +/* obstack_blank_fast (&frags, max_chars); */ /* OVE: so far the only diff */ + frag_now->fr_var = var; + frag_now->fr_type = type; + frag_now->fr_subtype = subtype; + frag_now->fr_symbol = symbol; + frag_now->fr_offset = offset; + frag_now->fr_opcode = opcode; + frag_now->fr_pcrel_adjust = pcrel_adjust; + frag_now->fr_bsr = bsr; + frag_new (max_chars); + return (retval); +} /* frag_variant() */ + +/* + * frag_wane() + * + * Reduce the variable end of a frag to a harmless state. + */ +void +frag_wane (fragP) +register fragS * fragP; +{ + fragP->fr_type = rs_fill; + fragP->fr_offset = 0; + fragP->fr_var = 0; +} + +/* + * frag_align() + * + * Make a frag for ".align foo,bar". Call is "frag_align (foo,bar);". + * Foo & bar are absolute integers. + * + * Call to close off the current frag with a ".align", then start a new + * (so far empty) frag, in the same subsegment as the last frag. + */ + +void +frag_align (alignment, fill_character) +int alignment; +int fill_character; +{ + *(frag_var (rs_align, 1, 1, (relax_substateT)0, (symbolS *)0, + (long)alignment, (char *)0)) = fill_character; +} + +/* end: frags.c */ diff --git a/gnu/usr.bin/as/frags.h b/gnu/usr.bin/as/frags.h new file mode 100644 index 0000000..6d7310b --- /dev/null +++ b/gnu/usr.bin/as/frags.h @@ -0,0 +1,41 @@ +/* frags.h - Header file for the frag concept. + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern struct obstack frags; + /* Frags ONLY live in this obstack. */ + /* We use obstack_next_free() macro */ + /* so please don't put any other objects */ + /* on this stack! */ + +/* + * A macro to speed up appending exactly 1 char + * to current frag. + */ +/* JF changed < 1 to <= 1 to avoid a race conditon */ +#define FRAG_APPEND_1_CHAR(datum) \ +{ \ + if (obstack_room( &frags ) <= 1) {\ + frag_wane (frag_now); \ + frag_new (0); \ + } \ + obstack_1grow( &frags, datum ); \ +} + + +/* end: frags.h */ diff --git a/gnu/usr.bin/as/hash.c b/gnu/usr.bin/as/hash.c new file mode 100644 index 0000000..21f0cc0 --- /dev/null +++ b/gnu/usr.bin/as/hash.c @@ -0,0 +1,981 @@ +/* hash.c - hash table lookup strings - + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * BUGS, GRIPES, APOLOGIA etc. + * + * A typical user doesn't need ALL this: I intend to make a library out + * of it one day - Dean Elsner. + * Also, I want to change the definition of a symbol to (address,length) + * so I can put arbitrary binary in the names stored. [see hsh.c for that] + * + * This slime is common coupled inside the module. Com-coupling (and other + * vandalism) was done to speed running time. The interfaces at the + * module's edges are adequately clean. + * + * There is no way to (a) run a test script through this heap and (b) + * compare results with previous scripts, to see if we have broken any + * code. Use GNU (f)utilities to do this. A few commands assist test. + * The testing is awkward: it tries to be both batch & interactive. + * For now, interactive rules! + */ + +/* + * The idea is to implement a symbol table. A test jig is here. + * Symbols are arbitrary strings; they can't contain '\0'. + * [See hsh.c for a more general symbol flavour.] + * Each symbol is associated with a char*, which can point to anything + * you want, allowing an arbitrary property list for each symbol. + * + * The basic operations are: + * + * new creates symbol table, returns handle + * find (symbol) returns char* + * insert (symbol,char*) error if symbol already in table + * delete (symbol) returns char* if symbol was in table + * apply so you can delete all symbols before die() + * die destroy symbol table (free up memory) + * + * Supplementary functions include: + * + * say how big? what % full? + * replace (symbol,newval) report previous value + * jam (symbol,value) assert symbol:=value + * + * You, the caller, have control over errors: this just reports them. + * + * This package requires malloc(), free(). + * Malloc(size) returns NULL or address of char[size]. + * Free(address) frees same. + */ + +/* + * The code and its structures are re-enterent. + * Before you do anything else, you must call hash_new() which will + * return the address of a hash-table-control-block (or NULL if there + * is not enough memory). You then use this address as a handle of the + * symbol table by passing it to all the other hash_...() functions. + * The only approved way to recover the memory used by the symbol table + * is to call hash_die() with the handle of the symbol table. + * + * Before you call hash_die() you normally delete anything pointed to + * by individual symbols. After hash_die() you can't use that symbol + * table again. + * + * The char* you associate with a symbol may not be NULL (0) because + * NULL is returned whenever a symbol is not in the table. Any other + * value is OK, except DELETED, #defined below. + * + * When you supply a symbol string for insertion, YOU MUST PRESERVE THE + * STRING until that symbol is deleted from the table. The reason is that + * only the address you supply, NOT the symbol string itself, is stored + * in the symbol table. + * + * You may delete and add symbols arbitrarily. + * Any or all symbols may have the same 'value' (char *). In fact, these + * routines don't do anything with your symbol values. + * + * You have no right to know where the symbol:char* mapping is stored, + * because it moves around in memory; also because we may change how it + * works and we don't want to break your code do we? However the handle + * (address of struct hash_control) is never changed in + * the life of the symbol table. + * + * What you CAN find out about a symbol table is: + * how many slots are in the hash table? + * how many slots are filled with symbols? + * (total hashes,collisions) for (reads,writes) (*) + * All of the above values vary in time. + * (*) some of these numbers will not be meaningful if we change the + * internals. + */ + +/* + * I N T E R N A L + * + * Hash table is an array of hash_entries; each entry is a pointer to a + * a string and a user-supplied value 1 char* wide. + * + * The array always has 2 ** n elements, n>0, n integer. + * There is also a 'wall' entry after the array, which is always empty + * and acts as a sentinel to stop running off the end of the array. + * When the array gets too full, we create a new array twice as large + * and re-hash the symbols into the new array, then forget the old array. + * (Of course, we copy the values into the new array before we junk the + * old array!) + * + */ + +#include <stdio.h> +#define TRUE (1) +#define FALSE (0) +#include <ctype.h> +#define min(a, b) ((a) < (b) ? (a) : (b)) + +#include "hash.h" +char *xmalloc(); + +#define DELETED ((char *)1) /* guarenteed invalid address */ +#define START_POWER (11) /* power of two: size of new hash table *//* JF was 6 */ +/* JF These next two aren't used any more. */ +/* #define START_SIZE (64) / * 2 ** START_POWER */ +/* #define START_FULL (32) / * number of entries before table expands */ +#define islive(ptr) (ptr->hash_string && ptr->hash_string!=DELETED) + /* above TRUE if a symbol is in entry @ ptr */ + +#define STAT_SIZE (0) /* number of slots in hash table */ + /* the wall does not count here */ + /* we expect this is always a power of 2 */ +#define STAT_ACCESS (1) /* number of hash_ask()s */ +#define STAT__READ (0) /* reading */ +#define STAT__WRITE (1) /* writing */ +#define STAT_COLLIDE (3) /* number of collisions (total) */ + /* this may exceed STAT_ACCESS if we have */ + /* lots of collisions/access */ +#define STAT_USED (5) /* slots used right now */ +#define STATLENGTH (6) /* size of statistics block */ +#if STATLENGTH != HASH_STATLENGTH +Panic! Please make #include "stat.h" agree with previous definitions! +#endif + +/* #define SUSPECT to do runtime checks */ +/* #define TEST to be a test jig for hash...() */ + +#ifdef TEST /* TEST: use smaller hash table */ +#undef START_POWER +#define START_POWER (3) +#undef START_SIZE +#define START_SIZE (8) +#undef START_FULL +#define START_FULL (4) +#endif + +/*------------------ plan ---------------------------------- i = internal + +struct hash_control * c; +struct hash_entry * e; i +int b[z]; buffer for statistics + z size of b +char * s; symbol string (address) [ key ] +char * v; value string (address) [datum] +boolean f; TRUE if we found s in hash table i +char * t; error string; "" means OK +int a; access type [0...n) i + +c=hash_new () create new hash_control + +hash_die (c) destroy hash_control (and hash table) + table should be empty. + doesn't check if table is empty. + c has no meaning after this. + +hash_say (c,b,z) report statistics of hash_control. + also report number of available statistics. + +v=hash_delete (c,s) delete symbol, return old value if any. + ask() NULL means no old value. + f + +v=hash_replace (c,s,v) replace old value of s with v. + ask() NULL means no old value: no table change. + f + +t=hash_insert (c,s,v) insert (s,v) in c. + ask() return error string. + f it is an error to insert if s is already + in table. + if any error, c is unchanged. + +t=hash_jam (c,s,v) assert that new value of s will be v. i + ask() it may decide to GROW the table. i + f i + grow() i +t=hash_grow (c) grow the hash table. i + jam() will invoke JAM. i + +?=hash_apply (c,y) apply y() to every symbol in c. + y evtries visited in 'unspecified' order. + +v=hash_find (c,s) return value of s, or NULL if s not in c. + ask() + f + +f,e=hash_ask() (c,s,a) return slot where s SHOULD live. i + code() maintain collision stats in c. i + +.=hash_code (c,s) compute hash-code for s, i + from parameters of c. i + +*/ + +static char hash_found; /* returned by hash_ask() to stop extra */ + /* testing. hash_ask() wants to return both */ + /* a slot and a status. This is the status. */ + /* TRUE: found symbol */ + /* FALSE: absent: empty or deleted slot */ + /* Also returned by hash_jam(). */ + /* TRUE: we replaced a value */ + /* FALSE: we inserted a value */ + +static struct hash_entry * hash_ask(); +static int hash_code (); +static char * hash_grow(); + +/* + * h a s h _ n e w ( ) + * + */ +struct hash_control * +hash_new() /* create a new hash table */ + /* return NULL if failed */ + /* return handle (address of struct hash) */ +{ + register struct hash_control * retval; + register struct hash_entry * room; /* points to hash table */ + register struct hash_entry * wall; + register struct hash_entry * entry; + char * malloc(); + register int * ip; /* scan stats block of struct hash_control */ + register int * nd; /* limit of stats block */ + + if ( room = (struct hash_entry *) malloc( sizeof(struct hash_entry)*((1<<START_POWER) + 1) ) ) + /* +1 for the wall entry */ + { + if ( retval = (struct hash_control *) malloc(sizeof(struct hash_control)) ) + { + nd = retval->hash_stat + STATLENGTH; + for (ip=retval->hash_stat; ip<nd; ip++) + { + *ip = 0; + } + + retval -> hash_stat[STAT_SIZE] = 1<<START_POWER; + retval -> hash_mask = (1<<START_POWER) - 1; + retval -> hash_sizelog = START_POWER; + /* works for 1's compl ok */ + retval -> hash_where = room; + retval -> hash_wall = + wall = room + (1<<START_POWER); + retval -> hash_full = (1<<START_POWER)/2; + for (entry=room; entry<=wall; entry++) + { + entry->hash_string = NULL; + } + } + } + else + { + retval = NULL; /* no room for table: fake a failure */ + } + return(retval); /* return NULL or set-up structs */ +} + +/* + * h a s h _ d i e ( ) + * + * Table should be empty, but this is not checked. + * To empty the table, try hash_apply()ing a symbol deleter. + * Return to free memory both the hash table and it's control + * block. + * 'handle' has no meaning after this function. + * No errors are recoverable. + */ +void +hash_die(handle) + struct hash_control * handle; +{ + free((char *)handle->hash_where); + free((char *)handle); +} + +/* + * h a s h _ s a y ( ) + * + * Return the size of the statistics table, and as many statistics as + * we can until either (a) we have run out of statistics or (b) caller + * has run out of buffer. + * NOTE: hash_say treats all statistics alike. + * These numbers may change with time, due to insertions, deletions + * and expansions of the table. + * The first "statistic" returned is the length of hash_stat[]. + * Then contents of hash_stat[] are read out (in ascending order) + * until your buffer or hash_stat[] is exausted. + */ +void +hash_say(handle,buffer,bufsiz) + register struct hash_control * handle; + register int buffer[/*bufsiz*/]; + register int bufsiz; +{ + register int * nd; /* limit of statistics block */ + register int * ip; /* scan statistics */ + + ip = handle -> hash_stat; + nd = ip + min(bufsiz-1,STATLENGTH); + if (bufsiz>0) /* trust nothing! bufsiz<=0 is dangerous */ + { + *buffer++ = STATLENGTH; + for (; ip<nd; ip++,buffer++) + { + *buffer = *ip; + } + } +} + +/* + * h a s h _ d e l e t e ( ) + * + * Try to delete a symbol from the table. + * If it was there, return its value (and adjust STAT_USED). + * Otherwise, return NULL. + * Anyway, the symbol is not present after this function. + * + */ +char * /* NULL if string not in table, else */ + /* returns value of deleted symbol */ +hash_delete(handle,string) + register struct hash_control * handle; + register char * string; +{ + register char * retval; /* NULL if string not in table */ + register struct hash_entry * entry; /* NULL or entry of this symbol */ + + entry = hash_ask(handle,string,STAT__WRITE); + if (hash_found) + { + retval = entry -> hash_value; + entry -> hash_string = DELETED; /* mark as deleted */ + handle -> hash_stat[STAT_USED] -= 1; /* slots-in-use count */ +#ifdef SUSPECT + if (handle->hash_stat[STAT_USED]<0) + { + error("hash_delete"); + } +#endif /* def SUSPECT */ + } + else + { + retval = NULL; + } + return(retval); +} + +/* + * h a s h _ r e p l a c e ( ) + * + * Try to replace the old value of a symbol with a new value. + * Normally return the old value. + * Return NULL and don't change the table if the symbol is not already + * in the table. + */ +char * +hash_replace(handle,string,value) + register struct hash_control * handle; + register char * string; + register char * value; +{ + register struct hash_entry * entry; + register char * retval; + + entry = hash_ask(handle,string,STAT__WRITE); + if (hash_found) + { + retval = entry -> hash_value; + entry -> hash_value = value; + } + else + { + retval = NULL; + } + ; + return (retval); +} + +/* + * h a s h _ i n s e r t ( ) + * + * Insert a (symbol-string, value) into the hash table. + * Return an error string, "" means OK. + * It is an 'error' to insert an existing symbol. + */ + +char * /* return error string */ +hash_insert(handle,string,value) + register struct hash_control * handle; + register char * string; + register char * value; +{ + register struct hash_entry * entry; + register char * retval; + + retval = ""; + if (handle->hash_stat[STAT_USED] > handle->hash_full) + { + retval = hash_grow(handle); + } + if ( ! * retval) + { + entry = hash_ask(handle,string,STAT__WRITE); + if (hash_found) + { + retval = "exists"; + } + else + { + entry -> hash_value = value; + entry -> hash_string = string; + handle-> hash_stat[STAT_USED] += 1; + } + } + return(retval); +} + +/* + * h a s h _ j a m ( ) + * + * Regardless of what was in the symbol table before, after hash_jam() + * the named symbol has the given value. The symbol is either inserted or + * (its value is) relpaced. + * An error message string is returned, "" means OK. + * + * WARNING: this may decide to grow the hashed symbol table. + * To do this, we call hash_grow(), WHICH WILL recursively CALL US. + * + * We report status internally: hash_found is TRUE if we replaced, but + * false if we inserted. + */ +char * +hash_jam(handle,string,value) + register struct hash_control * handle; + register char * string; + register char * value; +{ + register char * retval; + register struct hash_entry * entry; + + retval = ""; + if (handle->hash_stat[STAT_USED] > handle->hash_full) + { + retval = hash_grow(handle); + } + if (! * retval) + { + entry = hash_ask(handle,string,STAT__WRITE); + if ( ! hash_found) + { + entry -> hash_string = string; + handle->hash_stat[STAT_USED] += 1; + } + entry -> hash_value = value; + } + return(retval); +} + +/* + * h a s h _ g r o w ( ) + * + * Grow a new (bigger) hash table from the old one. + * We choose to double the hash table's size. + * Return a human-scrutible error string: "" if OK. + * Warning! This uses hash_jam(), which had better not recurse + * back here! Hash_jam() conditionally calls us, but we ALWAYS + * call hash_jam()! + * Internal. + */ +static char * +hash_grow(handle) /* make a hash table grow */ + struct hash_control * handle; +{ + register struct hash_entry * newwall; + register struct hash_entry * newwhere; + struct hash_entry * newtrack; + register struct hash_entry * oldtrack; + register struct hash_entry * oldwhere; + register struct hash_entry * oldwall; + register int temp; + int newsize; + char * string; + char * retval; +#ifdef SUSPECT + int oldused; +#endif + + /* + * capture info about old hash table + */ + oldwhere = handle -> hash_where; + oldwall = handle -> hash_wall; +#ifdef SUSPECT + oldused = handle -> hash_stat[STAT_USED]; +#endif + /* + * attempt to get enough room for a hash table twice as big + */ + temp = handle->hash_stat[STAT_SIZE]; + if ( newwhere = (struct hash_entry *) xmalloc((long)((temp+temp+1)*sizeof(struct hash_entry)))) + /* +1 for wall slot */ + { + retval = ""; /* assume success until proven otherwise */ + /* + * have enough room: now we do all the work. + * double the size of everything in handle, + * note: hash_mask frob works for 1's & for 2's complement machines + */ + handle->hash_mask = handle->hash_mask + handle->hash_mask + 1; + handle->hash_stat[STAT_SIZE] <<= 1; + newsize = handle->hash_stat[STAT_SIZE]; + handle->hash_where = newwhere; + handle->hash_full <<= 1; + handle->hash_sizelog += 1; + handle->hash_stat[STAT_USED] = 0; + handle->hash_wall = + newwall = newwhere + newsize; + /* + * set all those pesky new slots to vacant. + */ + for (newtrack=newwhere; newtrack <= newwall; newtrack++) + { + newtrack -> hash_string = NULL; + } + /* + * we will do a scan of the old table, the hard way, using the + * new control block to re-insert the data into new hash table. + */ + handle -> hash_stat[STAT_USED] = 0; /* inserts will bump it up to correct */ + for (oldtrack=oldwhere; oldtrack < oldwall; oldtrack++) + { + if ( (string=oldtrack->hash_string) && string!=DELETED ) + { + if ( * (retval = hash_jam(handle,string,oldtrack->hash_value) ) ) + { + break; + } + } + } +#ifdef SUSPECT + if ( !*retval && handle->hash_stat[STAT_USED] != oldused) + { + retval = "hash_used"; + } +#endif + if (!*retval) + { + /* + * we have a completely faked up control block. + * return the old hash table. + */ + free((char *)oldwhere); + /* + * Here with success. retval is already "". + */ + } + } + else + { + retval = "no room"; + } + return(retval); +} + +/* + * h a s h _ a p p l y ( ) + * + * Use this to scan each entry in symbol table. + * For each symbol, this calls (applys) a nominated function supplying the + * symbol's value (and the symbol's name). + * The idea is you use this to destroy whatever is associted with + * any values in the table BEFORE you destroy the table with hash_die. + * Of course, you can use it for other jobs; whenever you need to + * visit all extant symbols in the table. + * + * We choose to have a call-you-back idea for two reasons: + * asthetic: it is a neater idea to use apply than an explicit loop + * sensible: if we ever had to grow the symbol table (due to insertions) + * then we would lose our place in the table when we re-hashed + * symbols into the new table in a different order. + * + * The order symbols are visited depends entirely on the hashing function. + * Whenever you insert a (symbol, value) you risk expanding the table. If + * you do expand the table, then the hashing function WILL change, so you + * MIGHT get a different order of symbols visited. In other words, if you + * want the same order of visiting symbols as the last time you used + * hash_apply() then you better not have done any hash_insert()s or + * hash_jam()s since the last time you used hash_apply(). + * + * In future we may use the value returned by your nominated function. + * One idea is to abort the scan if, after applying the function to a + * certain node, the function returns a certain code. + * To be safe, please make your functions of type char *. If you always + * return NULL, then the scan will complete, visiting every symbol in + * the table exactly once. ALL OTHER RETURNED VALUES have no meaning yet! + * Caveat Actor! + * + * The function you supply should be of the form: + * char * myfunct(string,value) + * char * string; |* the symbol's name *| + * char * value; |* the symbol's value *| + * { + * |* ... *| + * return(NULL); + * } + * + * The returned value of hash_apply() is (char*)NULL. In future it may return + * other values. NULL means "completed scan OK". Other values have no meaning + * yet. (The function has no graceful failures.) + */ +char * +hash_apply(handle,function) + struct hash_control * handle; + char* (*function)(); +{ + register struct hash_entry * entry; + register struct hash_entry * wall; + + wall = handle->hash_wall; + for (entry = handle->hash_where; entry < wall; entry++) + { + if (islive(entry)) /* silly code: tests entry->string twice! */ + { + (*function)(entry->hash_string,entry->hash_value); + } + } + return (NULL); +} + +/* + * h a s h _ f i n d ( ) + * + * Given symbol string, find value (if any). + * Return found value or NULL. + */ +char * +hash_find(handle,string) /* return char* or NULL */ + struct hash_control * handle; + char * string; +{ + register struct hash_entry * entry; + register char * retval; + + entry = hash_ask(handle,string,STAT__READ); + if (hash_found) + { + retval = entry->hash_value; + } + else + { + retval = NULL; + } + return(retval); +} + +/* + * h a s h _ a s k ( ) + * + * Searches for given symbol string. + * Return the slot where it OUGHT to live. It may be there. + * Return hash_found: TRUE only if symbol is in that slot. + * Access argument is to help keep statistics in control block. + * Internal. + */ +static struct hash_entry * /* string slot, may be empty or deleted */ +hash_ask(handle,string,access) + struct hash_control * handle; + char * string; + int access; /* access type */ +{ + register char *string1; /* JF avoid strcmp calls */ + register char * s; + register int c; + register struct hash_entry * slot; + register int collision; /* count collisions */ + + slot = handle->hash_where + hash_code(handle,string); /* start looking here */ + handle->hash_stat[STAT_ACCESS+access] += 1; + collision = 0; + hash_found = FALSE; + while ( (s = slot->hash_string) && s!=DELETED ) + { + for(string1=string;;) { + if(!(c= *s++)) { + if(!*string1) + hash_found = TRUE; + break; + } + if(*string1++!=c) + break; + } + if(hash_found) + break; + collision++; + slot++; + } + /* + * slot: return: + * in use: we found string slot + * at empty: + * at wall: we fell off: wrap round ???? + * in table: dig here slot + * at DELETED: dig here slot + */ + if (slot==handle->hash_wall) + { + slot = handle->hash_where; /* now look again */ + while( (s = slot->hash_string) && s!=DELETED ) + { + for(string1=string;*s;string1++,s++) { + if(*string1!=*s) + break; + } + if(*s==*string1) { + hash_found = TRUE; + break; + } + collision++; + slot++; + } + /* + * slot: return: + * in use: we found it slot + * empty: wall: ERROR IMPOSSIBLE !!!! + * in table: dig here slot + * DELETED:dig here slot + */ + } +/* fprintf(stderr,"hash_ask(%s)->%d(%d)\n",string,hash_code(handle,string),collision); */ + handle -> hash_stat[STAT_COLLIDE+access] += collision; + return(slot); /* also return hash_found */ +} + +/* + * h a s h _ c o d e + * + * Does hashing of symbol string to hash number. + * Internal. + */ +static int +hash_code(handle,string) + struct hash_control * handle; + register char * string; +{ + register long int h; /* hash code built here */ + register long int c; /* each character lands here */ + register int n; /* Amount to shift h by */ + + n = (handle->hash_sizelog - 3); + h = 0; + while (c = *string++) + { + h += c; + h = (h<<3) + (h>>n) + c; + } + return (h & handle->hash_mask); +} + +/* + * Here is a test program to exercise above. + */ +#ifdef TEST + +#define TABLES (6) /* number of hash tables to maintain */ + /* (at once) in any testing */ +#define STATBUFSIZE (12) /* we can have 12 statistics */ + +int statbuf[STATBUFSIZE]; /* display statistics here */ +char answer[100]; /* human farts here */ +char * hashtable[TABLES]; /* we test many hash tables at once */ +char * h; /* points to curent hash_control */ +char ** pp; +char * p; +char * name; +char * value; +int size; +int used; +char command; +int number; /* number 0:TABLES-1 of current hashed */ + /* symbol table */ + +main() +{ + char (*applicatee()); + char * hash_find(); + char * destroy(); + char * what(); + struct hash_control * hash_new(); + char * hash_replace(); + int * ip; + + number = 0; + h = 0; + printf("type h <RETURN> for help\n"); + for(;;) + { + printf("hash_test command: "); + gets(answer); + command = answer[0]; + if (isupper(command)) command = tolower(command); /* ecch! */ + switch (command) + { + case '#': + printf("old hash table #=%d.\n",number); + whattable(); + break; + case '?': + for (pp=hashtable; pp<hashtable+TABLES; pp++) + { + printf("address of hash table #%d control block is %xx\n" + ,pp-hashtable,*pp); + } + break; + case 'a': + hash_apply(h,applicatee); + break; + case 'd': + hash_apply(h,destroy); + hash_die(h); + break; + case 'f': + p = hash_find(h,name=what("symbol")); + printf("value of \"%s\" is \"%s\"\n",name,p?p:"NOT-PRESENT"); + break; + case 'h': + printf("# show old, select new default hash table number\n"); + printf("? display all hashtable control block addresses\n"); + printf("a apply a simple display-er to each symbol in table\n"); + printf("d die: destroy hashtable\n"); + printf("f find value of nominated symbol\n"); + printf("h this help\n"); + printf("i insert value into symbol\n"); + printf("j jam value into symbol\n"); + printf("n new hashtable\n"); + printf("r replace a value with another\n"); + printf("s say what %% of table is used\n"); + printf("q exit this program\n"); + printf("x delete a symbol from table, report its value\n"); + break; + case 'i': + p = hash_insert(h,name=what("symbol"),value=what("value")); + if (*p) + { + printf("symbol=\"%s\" value=\"%s\" error=%s\n",name,value,p); + } + break; + case 'j': + p = hash_jam(h,name=what("symbol"),value=what("value")); + if (*p) + { + printf("symbol=\"%s\" value=\"%s\" error=%s\n",name,value,p); + } + break; + case 'n': + h = hashtable[number] = (char *) hash_new(); + break; + case 'q': + exit(); + case 'r': + p = hash_replace(h,name=what("symbol"),value=what("value")); + printf("old value was \"%s\"\n",p?p:"{}"); + break; + case 's': + hash_say(h,statbuf,STATBUFSIZE); + for (ip=statbuf; ip<statbuf+STATBUFSIZE; ip++) + { + printf("%d ",*ip); + } + printf("\n"); + break; + case 'x': + p = hash_delete(h,name=what("symbol")); + printf("old value was \"%s\"\n",p?p:"{}"); + break; + default: + printf("I can't understand command \"%c\"\n",command); + break; + } + } +} + +char * +what(description) + char * description; +{ + char * retval; + char * malloc(); + + printf(" %s : ",description); + gets(answer); + /* will one day clean up answer here */ + retval = malloc(strlen(answer)+1); + if (!retval) + { + error("room"); + } + (void)strcpy(retval,answer); + return(retval); +} + +char * +destroy(string,value) + char * string; + char * value; +{ + free(string); + free(value); + return(NULL); +} + + +char * +applicatee(string,value) + char * string; + char * value; +{ + printf("%.20s-%.20s\n",string,value); + return(NULL); +} + +whattable() /* determine number: what hash table to use */ + /* also determine h: points to hash_control */ +{ + + for (;;) + { + printf(" what hash table (%d:%d) ? ",0,TABLES-1); + gets(answer); + sscanf(answer,"%d",&number); + if (number>=0 && number<TABLES) + { + h = hashtable[number]; + if (!h) + { + printf("warning: current hash-table-#%d. has no hash-control\n",number); + } + return; + } + else + { + printf("invalid hash table number: %d\n",number); + } + } +} + + + +#endif /* #ifdef TEST */ + +/* end: hash.c */ diff --git a/gnu/usr.bin/as/hash.h b/gnu/usr.bin/as/hash.h new file mode 100644 index 0000000..fb68fd3 --- /dev/null +++ b/gnu/usr.bin/as/hash.h @@ -0,0 +1,59 @@ +/* hash.h - for hash.c + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef hashH +#define hashH + +struct hash_entry +{ + char * hash_string; /* points to where the symbol string is */ + /* NULL means slot is not used */ + /* DELETED means slot was deleted */ + char * hash_value; /* user's datum, associated with symbol */ +}; + + +#define HASH_STATLENGTH (6) +struct hash_control +{ + struct hash_entry * hash_where; /* address of hash table */ + int hash_sizelog; /* Log of ( hash_mask + 1 ) */ + int hash_mask; /* masks a hash into index into table */ + int hash_full; /* when hash_stat[STAT_USED] exceeds this, */ + /* grow table */ + struct hash_entry * hash_wall; /* point just after last (usable) entry */ + /* here we have some statistics */ + int hash_stat[HASH_STATLENGTH]; /* lies & statistics */ + /* we need STAT_USED & STAT_SIZE */ +}; + + +/* returns */ +struct hash_control * hash_new(); /* [control block] */ +void hash_die(); +void hash_say(); +char * hash_delete(); /* previous value */ +char * hash_relpace(); /* previous value */ +char * hash_insert(); /* error string */ +char * hash_apply(); /* 0 means OK */ +char * hash_find(); /* value */ +char * hash_jam(); /* error text (internal) */ +#endif /* #ifdef hashH */ + +/* end: hash.c */ diff --git a/gnu/usr.bin/as/hex-value.c b/gnu/usr.bin/as/hex-value.c new file mode 100644 index 0000000..f97c2ab3 --- /dev/null +++ b/gnu/usr.bin/as/hex-value.c @@ -0,0 +1,55 @@ +/* hex_value.c - char=>radix-value - + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Export: Hex_value[]. Converts digits to their radix-values. + * As distributed assumes 8 bits per char (256 entries) and ASCII. + */ + +#define __ (42) /* blatently illegal digit value */ + /* exceeds any normal radix */ +#if !defined(__STDC__) && !defined(const) +#define const /* empty */ +#endif +const char +hex_value [256] = { /* for fast ASCII -> binary */ + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, __, __, __, __, __, __, + __, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __ + }; + +#ifdef VMS +dummy2() +{ +} +#endif +/* end:hex_value.c */ diff --git a/gnu/usr.bin/as/input-file.c b/gnu/usr.bin/as/input-file.c new file mode 100644 index 0000000..8de1dcf --- /dev/null +++ b/gnu/usr.bin/as/input-file.c @@ -0,0 +1,306 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + */ + +#ifndef lint +static char sccsid[] = "@(#)input-file.c 6.2 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* input_file.c - Deal with Input Files - + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Confines all details of reading source bytes to this module. + * All O/S specific crocks should live here. + * What we lose in "efficiency" we gain in modularity. + * Note we don't need to #include the "as.h" file. No common coupling! + */ + +#define NDEBUG /* JF remove asserts */ + +#ifdef USG +#define index strchr +/* JF: What's the difference between _IOLBF and _IOFBF ? */ +#define setbuffer(stream, buf, size) setvbuf((stream), (buf), _IOFBF, (size)) +#endif + +#include <stdio.h> +#include <assert.h> +/* #include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <sys/wait.h> */ + +/* #include "style.h" */ +#include "input-file.h" + +/* This variable is non-zero if the file currently being read should be + preprocessed by app. It is zero if the file can be read straight in. + */ +int preprocess = 0; + +void as_perror(); + +/* + * This code opens a file, then delivers BUFFER_SIZE character + * chunks of the file on demand. + * BUFFER_SIZE is supposed to be a number chosen for speed. + * The caller only asks once what BUFFER_SIZE is, and asks before + * the nature of the input files (if any) is known. + */ + +#define BUFFER_SIZE (32 * 1024) + +static char in_buf[BUFFER_SIZE]; + +/* + * We use static data: the data area is not sharable. + */ + +FILE *f_in; /* JF do things the RIGHT way */ +/* static JF remove static so app.c can use file_name */ +char * file_name; + +/* These hooks accomodate most operating systems. */ + +void +input_file_begin () +{ + /* file_handle = -1; */ + f_in = (FILE *)0; +} + +void +input_file_end () +{ +} + +int /* Return BUFFER_SIZE. */ +input_file_buffer_size () +{ + return (BUFFER_SIZE); +} + +int +input_file_is_open () +{ + /* return (file_handle >= 0); */ + return f_in!=(FILE *)0; +} + +#ifdef DONTDEF /* JF save old version in case we need it */ +void +input_file_open (filename, preprocess, debugging) + char * filename; /* "" means use stdin. Must not be 0. */ + int preprocess; /* TRUE if needs app. */ + int debugging; /* TRUE if we are debugging assembler. */ +{ + assert( filename != 0 ); /* Filename may not be NULL. */ + if (filename [0]) + { /* We have a file name. Suck it and see. */ + file_handle = open (filename, O_RDONLY, 0); + file_name = filename; + } + else + { /* use stdin for the input file. */ + file_handle = fileno (stdin); + file_name = "{standard input}"; /* For error messages. */ + } + if (file_handle < 0) + as_perror ("Can't open %s for reading", file_name); + if ( preprocess ) + { +/* + * This code was written in haste for a frobbed BSD 4.2. + * I have a flight to catch: will someone please do proper + * error checks? - Dean. + */ + int pid; + char temporary_file_name [12]; + int fd; + union wait status; + char *mktemp(); + + (void)strcpy (temporary_file_name, "#appXXXXXX"); + (void)mktemp (temporary_file_name); + pid = vfork (); + if (pid == -1) + { + as_perror ("Vfork failed", file_name); + _exit (144); + } + if (pid == 0) + { + (void)dup2 (file_handle, fileno(stdin)); + fd = open (temporary_file_name, O_WRONLY + O_TRUNC + O_CREAT, 0666); + if (fd == -1) + { + (void)write(2,"Can't open temporary\n",21); + _exit (99); + } + (void)dup2 (fd, fileno(stdout)); +/* JF for testing #define PREPROCESSOR "/lib/app" */ +#define PREPROCESSOR "./app" + execl (PREPROCESSOR, PREPROCESSOR, 0); + execl ("app","app",0); + (void)write(2,"Exec of app failed. Get help.\n",31); + (void)unlink(temporary_file_name); + _exit (11); + } + (void)wait (& status); + if (status.w_status & 0xFF00) /* JF was 0xF000, was wrong */ + { + file_handle = -1; + as_warn( "Can't preprocess file \"%s\", status = %xx", file_name, status.w_status ); + } + else + { + file_handle = open (temporary_file_name, O_RDONLY, 0); + if ( ! debugging && unlink(temporary_file_name)) + as_perror ("Can't delete temp file %s", temporary_file_name); + } + if (file_handle == -1) + as_perror ("Can't retrieve temp file %s", temporary_file_name); + } +} +#else + +void +input_file_open (filename,pre) + char * filename; /* "" means use stdin. Must not be 0. */ + int pre; +{ + int c; + char buf[80]; + + preprocess = pre; + + assert( filename != 0 ); /* Filename may not be NULL. */ + if (filename [0]) { /* We have a file name. Suck it and see. */ + f_in=fopen(filename,"r"); + file_name=filename; + } else { /* use stdin for the input file. */ + f_in = stdin; + file_name = "{standard input}"; /* For error messages. */ + } + if (f_in==(FILE *)0) { + as_perror ("Can't open %s for reading", file_name); + return; + } +#ifndef VMS + setbuffer(f_in,in_buf,BUFFER_SIZE); +#endif /* VMS */ + c=getc(f_in); + if(c=='#') { /* Begins with comment, may not want to preprocess */ + c=getc(f_in); + if(c=='N') { + fgets(buf,80,f_in); + if(!strcmp(buf,"O_APP\n")) + preprocess=0; + if(!index(buf,'\n')) + ungetc('#',f_in); /* It was longer */ + else + ungetc('\n',f_in); + } else if(c=='\n') + ungetc('\n',f_in); + else + ungetc('#',f_in); + } else + ungetc(c,f_in); + +#ifdef DONTDEF + if ( preprocess ) { + char temporary_file_name [17]; + char *mktemp(); + FILE *f_out; + + (void)strcpy (temporary_file_name, "/tmp/#appXXXXXX"); + (void)mktemp (temporary_file_name); + f_out=fopen(temporary_file_name,"w+"); + if(f_out==(FILE *)0) + as_perror("Can't open temp file %s",temporary_file_name); + + /* JF this will have to be moved on any system that + does not support removal of open files. */ + (void)unlink(temporary_file_name);/* JF do it NOW */ + do_scrub(f_in,f_out); + (void)fclose(f_in); /* All done with it */ + (void)rewind(f_out); + f_in=f_out; + } +#endif +} +#endif + +char * +input_file_give_next_buffer (where) + char * where; /* Where to place 1st character of new buffer. */ +{ + char * return_value; /* -> Last char of what we read, + 1. */ + register int size; + + if (f_in == (FILE *)0) + return 0; + /* + * fflush (stdin); could be done here if you want to synchronise + * stdin and stdout, for the case where our input file is stdin. + * Since the assembler shouldn't do any output to stdout, we + * don't bother to synch output and input. + */ + /* size = read (file_handle, where, BUFFER_SIZE); */ + if(preprocess) { + char *p; + int n; + int ch; + extern FILE *scrub_file; + int scrub_from_file(); + void scrub_to_file(); + int do_scrub_next_char(); + + scrub_file=f_in; + for(p=where,n=BUFFER_SIZE;n;--n) { + ch=do_scrub_next_char(scrub_from_file,scrub_to_file); + if(ch==EOF) + break; + *p++=ch; + } + size=BUFFER_SIZE-n; + } else + size= fread(where,sizeof(char),BUFFER_SIZE,f_in); + if (size < 0) + { + as_perror ("Can't read from %s", file_name); + size = 0; + } + if (size) + return_value = where + size; + else + { + if (fclose (f_in)) + as_perror ("Can't close %s", file_name); + f_in = (FILE *)0; + return_value = 0; + } + return (return_value); +} + +/* end: input_file.c */ diff --git a/gnu/usr.bin/as/input-file.h b/gnu/usr.bin/as/input-file.h new file mode 100644 index 0000000..42f490a --- /dev/null +++ b/gnu/usr.bin/as/input-file.h @@ -0,0 +1,57 @@ +/* input_file.h header for input-file.c + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/*"input_file.c":Operating-system dependant functions to read source files.*/ + + +/* + * No matter what the operating system, this module must provide the + * following services to its callers. + * + * input_file_begin() Call once before anything else. + * + * input_file_end() Call once after everything else. + * + * input_file_buffer_size() Call anytime. Returns largest possible + * delivery from + * input_file_give_next_buffer(). + * + * input_file_open(name) Call once for each input file. + * + * input_file_give_next_buffer(where) Call once to get each new buffer. + * Return 0: no more chars left in file, + * the file has already been closed. + * Otherwise: return a pointer to just + * after the last character we read + * into the buffer. + * If we can only read 0 characters, then + * end-of-file is faked. + * + * All errors are reported (using as_perror) so caller doesn't have to think + * about I/O errors. No I/O errors are fatal: an end-of-file may be faked. + */ + +void input_file_begin(); +void input_file_end(); +int input_file_buffer_size(); +int input_file_is_open(); +void input_file_open(); +char * input_file_give_next_buffer(); + +/* end: input_file.h */ diff --git a/gnu/usr.bin/as/input-scrub.c b/gnu/usr.bin/as/input-scrub.c new file mode 100644 index 0000000..71af8a0 --- /dev/null +++ b/gnu/usr.bin/as/input-scrub.c @@ -0,0 +1,427 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + */ + +#ifndef lint +static char sccsid[] = "@(#)input-scrub.c 6.4 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* input_scrub.c - layer between app and the rest of the world + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "as.h" +#include "read.h" +#include "input-file.h" + +/* + * O/S independent module to supply buffers of sanitised source code + * to rest of assembler. We get raw input data of some length. + * Also looks after line numbers, for e.g. error messages. + * This module used to do the sanitising, but now a pre-processor program + * (app) does that job so this module is degenerate. + * Now input is pre-sanitised, so we only worry about finding the + * last partial line. A buffer of full lines is returned to caller. + * The last partial line begins the next buffer we build and return to caller. + * The buffer returned to caller is preceeded by BEFORE_STRING and followed + * by AFTER_STRING. The last character before AFTER_STRING is a newline. + */ + +/* + * We expect the following sanitation has already been done. + * + * No comments, reduce a comment to a space. + * Reduce a tab to a space unless it is 1st char of line. + * All multiple tabs and spaces collapsed into 1 char. Tab only + * legal if 1st char of line. + * # line file statements converted to .line x;.file y; statements. + * Escaped newlines at end of line: remove them but add as many newlines + * to end of statement as you removed in the middle, to synch line numbers. + */ + +#define BEFORE_STRING ("\n") +#define AFTER_STRING ("\0") /* bcopy of 0 chars might choke. */ +#define BEFORE_SIZE (1) +#define AFTER_SIZE (1) + +static char * buffer_start; /* -> 1st char of full buffer area. */ +static char * partial_where; /* -> after last full line in buffer. */ +static int partial_size; /* >=0. Number of chars in partial line in buffer. */ +static char save_source [AFTER_SIZE]; + /* Because we need AFTER_STRING just after last */ + /* full line, it clobbers 1st part of partial */ + /* line. So we preserve 1st part of partial */ + /* line here. */ +static int buffer_length; /* What is the largest size buffer that */ + /* input_file_give_next_buffer() could */ + /* return to us? */ + +static void as_1_char (); + +/* +We never have more than one source file open at once. +We may, however, read more than 1 source file in an assembly. +NULL means we have no file open right now. +*/ + + +/* +We must track the physical file and line number for error messages. +We also track a "logical" file and line number corresponding to (C?) +compiler source line numbers. +Whenever we open a file we must fill in physical_input_file. So if it is NULL +we have not opened any files yet. +*/ + +static +char * physical_input_file, + * logical_input_file; + + + +typedef unsigned int line_numberT; /* 1-origin line number in a source file. */ + /* A line ends in '\n' or eof. */ + +static +line_numberT physical_input_line, + logical_input_line; + +void +input_scrub_begin () +{ + know( strlen(BEFORE_STRING) == BEFORE_SIZE ); + know( strlen( AFTER_STRING) == AFTER_SIZE ); + + input_file_begin (); + + buffer_length = input_file_buffer_size (); + + buffer_start = xmalloc ((long)(BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE)); + bcopy (BEFORE_STRING, buffer_start, (int)BEFORE_SIZE); + + /* Line number things. */ + logical_input_line = 0; + logical_input_file = (char *)NULL; + physical_input_file = NULL; /* No file read yet. */ + do_scrub_begin(); +} + +void +input_scrub_end () +{ + input_file_end (); +} + +char * /* Return start of caller's part of buffer. */ +input_scrub_new_file (filename) + char * filename; +{ + input_file_open (filename, !flagseen['f']); + physical_input_file = filename[0] ? filename : "{standard input}"; + physical_input_line = 0; + + partial_size = 0; + return (buffer_start + BEFORE_SIZE); +} + +char * +input_scrub_next_buffer (bufp) +char **bufp; +{ + register char * limit; /* -> just after last char of buffer. */ + +#ifdef DONTDEF + if(preprocess) { + if(save_buffer) { + *bufp = save_buffer; + save_buffer = 0; + } + limit = input_file_give_next_buffer(buffer_start+BEFORE_SIZE); + if (!limit) { + partial_where = 0; + if(partial_size) + as_warn("Partial line at end of file ignored"); + return partial_where; + } + + if(partial_size) + bcopy(save_source, partial_where,(int)AFTER_SIZE); + do_scrub(partial_where,partial_size,buffer_start+BEFORE_SIZE,limit-(buffer_start+BEFORE_SIZE),&out_string,&out_length); + limit=out_string + out_length; + for(p=limit;*--p!='\n';) + ; + p++; + if(p<=buffer_start+BEFORE_SIZE) + as_fatal("Source line too long. Please change file '%s' and re-make the assembler.",__FILE__); + + partial_where = p; + partial_size = limit-p; + bcopy(partial_where, save_source,(int)AFTER_SIZE); + bcopy(AFTER_STRING, partial_where, (int)AFTER_SIZE); + + save_buffer = *bufp; + *bufp = out_string; + + return partial_where; + } + + /* We're not preprocessing. Do the right thing */ +#endif + if (partial_size) + { + bcopy (partial_where, buffer_start + BEFORE_SIZE, (int)partial_size); + bcopy (save_source, buffer_start + BEFORE_SIZE, (int)AFTER_SIZE); + } + limit = input_file_give_next_buffer (buffer_start + BEFORE_SIZE + partial_size); + if (limit) + { + register char * p; /* Find last newline. */ + + for (p = limit; * -- p != '\n'; ) + { + } + ++ p; + if (p <= buffer_start + BEFORE_SIZE) + { + as_fatal ("Source line too long. Please change file %s then rebuild assembler.", __FILE__); + } + partial_where = p; + partial_size = limit - p; + bcopy (partial_where, save_source, (int)AFTER_SIZE); + bcopy (AFTER_STRING, partial_where, (int)AFTER_SIZE); + } + else + { + partial_where = 0; + if (partial_size > 0) + { + as_warn( "Partial line at end of file ignored" ); + } + } + return (partial_where); +} + +/* + * The remaining part of this file deals with line numbers, error + * messages and so on. + */ + + +int +seen_at_least_1_file () /* TRUE if we opened any file. */ +{ + return (physical_input_file != NULL); +} + +void +bump_line_counters () +{ + ++ physical_input_line; + ++ logical_input_line; +} + +/* + * new_logical_line() + * + * Tells us what the new logical line number and file are. + * If the line_number is <0, we don't change the current logical line number. + * If the fname is NULL, we don't change the current logical file name. + */ +void +new_logical_line (fname, line_number) + char * fname; /* DON'T destroy it! We point to it! */ + int line_number; +{ + if ( fname ) + { + logical_input_file = fname; + } + if ( line_number >= 0 ) + { + logical_input_line = line_number; + } +} + +/* + * a s _ w h e r e ( ) + * + * Write a line to stderr locating where we are in reading + * input source files. + * As a sop to the debugger of AS, pretty-print the offending line. + */ +void +as_where() +{ + char *p; + line_numberT line; + + if (physical_input_file) + { /* we tried to read SOME source */ + if (input_file_is_open()) + { /* we can still read lines from source */ +#ifdef DONTDEF + fprintf (stderr," @ physical line %ld., file \"%s\"", + (long) physical_input_line, physical_input_file); + fprintf (stderr," @ logical line %ld., file \"%s\"\n", + (long) logical_input_line, logical_input_file); + (void)putc(' ', stderr); + as_howmuch (stderr); + (void)putc('\n', stderr); +#else + p = logical_input_file ? logical_input_file : physical_input_file; + line = logical_input_line ? logical_input_line : physical_input_line; + fprintf(stderr,"%s:%u:", p, line); +#endif + } + else + { +#ifdef DONTDEF + fprintf (stderr," After reading source.\n"); +#else + p = logical_input_file ? logical_input_file : physical_input_file; + line = logical_input_line ? logical_input_line : physical_input_line; + fprintf (stderr,"%s:unknown:", p); +#endif + } + } + else + { +#ifdef DONTDEF + fprintf (stderr," Before reading source.\n"); +#else +#endif + } +} + +/* + * Support for source file debugging. These functions handle + * logical lines and logical files. + */ +static char *saved_file; +static int saved_len; +static line_numberT saved_line; + +void +filestab() +{ + char *file; + int len; + + if (!physical_input_file || + !input_file_is_open()) + return; + + file = logical_input_file ? logical_input_file : physical_input_file; + + if (saved_file == 0 || strcmp(file, saved_file) != 0) + { + stabs(file); + len = strlen(file) + 1; + if (len > saved_len) + { + if (saved_file == 0) + saved_file = xmalloc(len); + else + saved_file = xrealloc(saved_file, len); + memcpy(saved_file, file, len); + saved_len = len; + } + else + strcpy(saved_file, file); + saved_line = 0; + } +} + +void +funcstab(func) + char *func; +{ + if (now_seg != SEG_TEXT) + return; + + filestab(); + stabf(func); +} + +void +linestab() +{ + line_numberT line; + + if (now_seg != SEG_TEXT) + return; + + filestab(); + + line = logical_input_line ? logical_input_line : physical_input_line; + + if (saved_line == 0 || line != saved_line) + { + stabd(line); + saved_line = line; + } +} + +/* + * a s _ h o w m u c h ( ) + * + * Output to given stream how much of line we have scanned so far. + * Assumes we have scanned up to and including input_line_pointer. + * No free '\n' at end of line. + */ +void +as_howmuch (stream) + FILE * stream; /* Opened for write please. */ +{ + register char * p; /* Scan input line. */ + /* register char c; JF unused */ + + for (p = input_line_pointer - 1; * p != '\n'; --p) + { + } + ++ p; /* p -> 1st char of line. */ + for (; p <= input_line_pointer; p++) + { + /* Assume ASCII. EBCDIC & other micro-computer char sets ignored. */ + /* c = *p & 0xFF; JF unused */ + as_1_char (*p, stream); + } +} + +static void +as_1_char (c,stream) + unsigned char c; + FILE * stream; +{ + if ( c > 127 ) + { + (void)putc( '%', stream); + c -= 128; + } + if ( c < 32 ) + { + (void)putc( '^', stream); + c += '@'; + } + (void)putc( c, stream); +} + +/* end: input_scrub.c */ diff --git a/gnu/usr.bin/as/md.h b/gnu/usr.bin/as/md.h new file mode 100644 index 0000000..681d027 --- /dev/null +++ b/gnu/usr.bin/as/md.h @@ -0,0 +1,57 @@ +/* md.h -machine dependent- */ + +/* Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of Gas, the GNU Assembler. + +The GNU assembler is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY. No author or distributor +accepts responsibility to anyone for the consequences of using it +or for whether it serves any particular purpose or works at all, +unless he says so in writing. Refer to the GNU Assembler General +Public License for full details. + +Everyone is granted permission to copy, modify and redistribute +the GNU Assembler, but only under the conditions described in the +GNU Assembler General Public License. A copy of this license is +supposed to have been given to you along with the GNU Assembler +so you can know your rights and responsibilities. It should be +in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. */ + +/* In theory (mine, at least!) the machine dependent part of the assembler + should only have to include one file. This one. -- JF */ + +/* JF added this here */ +typedef struct { + char * poc_name; /* assembler mnemonic, lower case, no '.' */ + void (*poc_handler)(); /* Do the work */ + int poc_val; /* Value to pass to handler */ +} +pseudo_typeS; +extern const pseudo_typeS md_pseudo_table[]; + +/* JF moved this here from as.h under the theory that nobody except MACHINE.c + and write.c care about it anyway. */ + +typedef struct +{ + long rlx_forward; /* Forward reach. Signed number. > 0. */ + long rlx_backward; /* Backward reach. Signed number. < 0. */ + unsigned char rlx_length; /* Bytes length of this address. */ + relax_substateT rlx_more; /* Next longer relax-state. */ + /* 0 means there is no 'next' relax-state. */ +} +relax_typeS; + +extern const relax_typeS md_relax_table[]; /* Define it in MACHINE.c */ + +char * md_atof(); +void md_assemble(); +void md_begin(); +void md_convert_frag(); +void md_end(); +int md_estimate_size_before_relax(); +void md_number_to_chars(); + +/* end: md.h */ diff --git a/gnu/usr.bin/as/messages.c b/gnu/usr.bin/as/messages.c new file mode 100644 index 0000000..a7b1205 --- /dev/null +++ b/gnu/usr.bin/as/messages.c @@ -0,0 +1,238 @@ +/* messages.c - error reporter - + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> /* define stderr */ +#ifdef VMS +#include <errno.h> /* Need this to make errno declaration right */ +#include <perror.h> /* Need this to make sys_errlist/sys_nerr right */ +#endif /* VMS */ + +#include "as.h" + +#ifndef NO_VARARGS +#include <varargs.h> +#endif + +/* + ERRORS + + JF: this is now bogus. We now print more standard error messages + that try to look like everyone else's. + + We print the error message 1st, beginning in column 1. + All ancillary info starts in column 2 on lines after the + key error text. + We try to print a location in logical and physical file + just after the main error text. + Caller then prints any appendices after that, begining all + lines with at least 1 space. + + Optionally, we may die. + There is no need for a trailing '\n' in your error text format + because we supply one. + +as_warn(fmt,args) Like fprintf(stderr,fmt,args) but also call errwhere(). + +as_fatal(fmt,args) Like as_warn() but exit with a fatal status. + +*/ + + +/* Nonzero if we've hit a 'bad error', and should not write an obj file, + and exit with a nonzero error code */ + +int bad_error = 0; + + +/* + * a s _ p e r r o r + * + * Like perror(3), but with more info. + */ +/* JF moved from input-scrub.c to here. */ +void +as_perror(gripe, filename) + char * gripe; /* Unpunctuated error theme. */ + char * filename; +{ + extern int errno; /* See perror(3) for details. */ + extern int sys_nerr; + extern char * sys_errlist[]; + + as_where(); + fprintf (stderr,gripe,filename); + if (errno > sys_nerr) + fprintf (stderr, "Unknown error #%d.\n", errno); + else + fprintf (stderr, "%s.\n", sys_errlist [errno]); + errno = 0; /* After reporting, clear it. */ +} + +/* + * a s _ w a r n ( ) + * + * Send to stderr a string (with bell) (JF: Bell is obnoxious!) as a warning, and locate warning + * in input file(s). + * Please only use this for when we have some recovery action. + * Please explain in string (which may have '\n's) what recovery was done. + */ + +#ifdef NO_VARARGS +/*VARARGS1*/ +as_warn(Format,args) +char *Format; +{ + if ( ! flagseen ['W']) /* -W supresses warning messages. */ + { + as_where(); + _doprnt (Format, &args, stderr); + (void)putc ('\n', stderr); + /* as_where(); */ + } +} +#else +void +as_warn(Format,va_alist) +char *Format; +va_dcl +{ + va_list args; + + if( ! flagseen['W']) + { + as_where(); + va_start(args); + vfprintf(stderr, Format, args); + va_end(args); + (void) putc('\n', stderr); + } +} +#endif +#ifdef DONTDEF +void +as_warn(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) +char *format; +{ + if(!flagseen['W']) { + as_where(); + fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an); + (void)putc('\n',stderr); + } +} +#endif +/* + * a s _ b a d ( ) + * + * Send to stderr a string (with bell) (JF: Bell is obnoxious!) as a warning, + * and locate warning in input file(s). + * Please us when there is no recovery, but we want to continue processing + * but not produce an object file. + * Please explain in string (which may have '\n's) what recovery was done. + */ + +#ifdef NO_VARARGS +/*VARARGS1*/ +as_bad(Format,args) +char *Format; +{ + bad_error=1; + as_where(); + _doprnt (Format, &args, stderr); + (void)putc ('\n', stderr); + /* as_where(); */ +} +#else +void +as_bad(Format,va_alist) +char *Format; +va_dcl +{ + va_list args; + + bad_error=1; + as_where(); + va_start(args); + vfprintf(stderr, Format, args); + va_end(args); + (void) putc('\n', stderr); +} +#endif +#ifdef DONTDEF +void +as_bad(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) +char *format; +{ + as_where(); + bad_error=1; + fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an); + (void)putc('\n',stderr); +} +#endif +/* + * a s _ f a t a l ( ) + * + * Send to stderr a string (with bell) (JF: Bell is obnoxious!) as a fatal + * message, and locate stdsource in input file(s). + * Please only use this for when we DON'T have some recovery action. + * It exit()s with a warning status. + */ + +#ifdef NO_VARARGS +/*VARARGS1*/ +as_fatal (Format, args) +char *Format; +{ + as_where(); + fprintf(stderr,"FATAL:"); + _doprnt (Format, &args, stderr); + (void)putc ('\n', stderr); + /* as_where(); */ + exit(42); /* What is a good exit status? */ +} +#else +void +as_fatal(Format,va_alist) +char *Format; +va_dcl +{ + va_list args; + + as_where(); + va_start(args); + fprintf (stderr, "FATAL:"); + vfprintf(stderr, Format, args); + (void) putc('\n', stderr); + va_end(args); + exit(42); +} +#endif +#ifdef DONTDEF +void +as_fatal(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) +char *Format; +{ + as_where(); + fprintf (stderr, "FATAL:"); + fprintf(stderr, Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an); + (void) putc('\n', stderr); + exit(42); +} +#endif + +/* end: messages.c */ diff --git a/gnu/usr.bin/as/objrecdef.h b/gnu/usr.bin/as/objrecdef.h new file mode 100644 index 0000000..fca8af4 --- /dev/null +++ b/gnu/usr.bin/as/objrecdef.h @@ -0,0 +1,255 @@ +/* + * + * $OBJRECDEF + * Generated automatically by "vms_struct Version 1.00" + * Created from VMS definition file "objrecdef.mar" + * Mon Oct 14 14:01:29 1985 + * + */ +struct OBJREC { + unsigned char obj$b_rectyp; + unsigned char obj$b_subtyp; + unsigned char obj$b_mhd_strlv; + unsigned char obj$b_mhd_recsz[2]; + unsigned char obj$t_mhd_name[1]; + }; + +#define OBJ$C_HDR 0 +#define OBJ$C_HDR_MHD 0 +#define OBJ$C_HDR_LNM 1 +#define OBJ$C_HDR_SRC 2 +#define OBJ$C_HDR_TTL 3 +#define OBJ$C_HDR_CPR 4 +#define OBJ$C_HDR_MTC 5 +#define OBJ$C_HDR_GTX 6 +#define OBJ$C_GSD 1 +#define OBJ$C_GSD_PSC 0 +#define OBJ$C_GSD_SYM 1 +#define OBJ$C_GSD_EPM 2 +#define OBJ$C_GSD_PRO 3 +#define OBJ$C_GSD_SYMW 4 +#define OBJ$C_GSD_EPMW 5 +#define OBJ$C_GSD_PROW 6 +#define OBJ$C_GSD_IDC 7 +#define OBJ$C_GSD_ENV 8 +#define OBJ$C_GSD_LSY 9 +#define OBJ$C_GSD_LEPM 10 +#define OBJ$C_GSD_LPRO 11 +#define OBJ$C_GSD_SPSC 12 +#define OBJ$C_TIR 2 +#define OBJ$C_EOM 3 +#define OBJ$C_DBG 4 +#define OBJ$C_TBT 5 +#define OBJ$C_LNK 6 +#define OBJ$C_EOMW 7 +#define OBJ$C_MAXRECTYP 7 +#define OBJ$K_SUBTYP 1 +#define OBJ$C_SUBTYP 1 +#define OBJ$C_MAXRECSIZ 2048 +#define OBJ$C_STRLVL 0 +#define OBJ$C_SYMSIZ 31 +#define OBJ$C_STOREPLIM -1 +#define OBJ$C_PSCALILIM 9 + +#define MHD$C_MHD 0 +#define MHD$C_LNM 1 +#define MHD$C_SRC 2 +#define MHD$C_TTL 3 +#define MHD$C_CPR 4 +#define MHD$C_MTC 5 +#define MHD$C_GTX 6 +#define MHD$C_MAXHDRTYP 6 + +#define GSD$K_ENTRIES 1 +#define GSD$C_ENTRIES 1 +#define GSD$C_PSC 0 +#define GSD$C_SYM 1 +#define GSD$C_EPM 2 +#define GSD$C_PRO 3 +#define GSD$C_SYMW 4 +#define GSD$C_EPMW 5 +#define GSD$C_PROW 6 +#define GSD$C_IDC 7 +#define GSD$C_ENV 8 +#define GSD$C_LSY 9 +#define GSD$C_LEPM 10 +#define GSD$C_LPRO 11 +#define GSD$C_SPSC 12 +#define GSD$C_SYMV 13 +#define GSD$C_EPMV 14 +#define GSD$C_PROV 15 +#define GSD$C_MAXRECTYP 15 + +#define GSY$M_WEAK 1 +#define GSY$M_DEF 2 +#define GSY$M_UNI 4 +#define GSY$M_REL 8 + +#define GPS$M_PIC 1 +#define GPS$M_LIB 2 +#define GPS$M_OVR 4 +#define GPS$M_REL 8 +#define GPS$M_GBL 16 +#define GPS$M_SHR 32 +#define GPS$M_EXE 64 +#define GPS$M_RD 128 +#define GPS$M_WRT 256 +#define GPS$M_VEC 512 +#define GPS$K_NAME 9 +#define GPS$C_NAME 9 + +#define TIR$C_STA_GBL 0 +#define TIR$C_STA_SB 1 +#define TIR$C_STA_SW 2 +#define TIR$C_STA_LW 3 +#define TIR$C_STA_PB 4 +#define TIR$C_STA_PW 5 +#define TIR$C_STA_PL 6 +#define TIR$C_STA_UB 7 +#define TIR$C_STA_UW 8 +#define TIR$C_STA_BFI 9 +#define TIR$C_STA_WFI 10 +#define TIR$C_STA_LFI 11 +#define TIR$C_STA_EPM 12 +#define TIR$C_STA_CKARG 13 +#define TIR$C_STA_WPB 14 +#define TIR$C_STA_WPW 15 +#define TIR$C_STA_WPL 16 +#define TIR$C_STA_LSY 17 +#define TIR$C_STA_LIT 18 +#define TIR$C_STA_LEPM 19 +#define TIR$C_MAXSTACOD 19 +#define TIR$C_MINSTOCOD 20 +#define TIR$C_STO_SB 20 +#define TIR$C_STO_SW 21 +#define TIR$C_STO_L 22 +#define TIR$C_STO_BD 23 +#define TIR$C_STO_WD 24 +#define TIR$C_STO_LD 25 +#define TIR$C_STO_LI 26 +#define TIR$C_STO_PIDR 27 +#define TIR$C_STO_PICR 28 +#define TIR$C_STO_RSB 29 +#define TIR$C_STO_RSW 30 +#define TIR$C_STO_RL 31 +#define TIR$C_STO_VPS 32 +#define TIR$C_STO_USB 33 +#define TIR$C_STO_USW 34 +#define TIR$C_STO_RUB 35 +#define TIR$C_STO_RUW 36 +#define TIR$C_STO_B 37 +#define TIR$C_STO_W 38 +#define TIR$C_STO_RB 39 +#define TIR$C_STO_RW 40 +#define TIR$C_STO_RIVB 41 +#define TIR$C_STO_PIRR 42 +#define TIR$C_MAXSTOCOD 42 +#define TIR$C_MINOPRCOD 50 +#define TIR$C_OPR_NOP 50 +#define TIR$C_OPR_ADD 51 +#define TIR$C_OPR_SUB 52 +#define TIR$C_OPR_MUL 53 +#define TIR$C_OPR_DIV 54 +#define TIR$C_OPR_AND 55 +#define TIR$C_OPR_IOR 56 +#define TIR$C_OPR_EOR 57 +#define TIR$C_OPR_NEG 58 +#define TIR$C_OPR_COM 59 +#define TIR$C_OPR_INSV 60 +#define TIR$C_OPR_ASH 61 +#define TIR$C_OPR_USH 62 +#define TIR$C_OPR_ROT 63 +#define TIR$C_OPR_SEL 64 +#define TIR$C_OPR_REDEF 65 +#define TIR$C_OPR_DFLIT 66 +#define TIR$C_MAXOPRCOD 66 +#define TIR$C_MINCTLCOD 80 +#define TIR$C_CTL_SETRB 80 +#define TIR$C_CTL_AUGRB 81 +#define TIR$C_CTL_DFLOC 82 +#define TIR$C_CTL_STLOC 83 +#define TIR$C_CTL_STKDL 84 +#define TIR$C_MAXCTLCOD 84 + +/* + * Debugger symbol definitions: These are done by hand, as no + * machine-readable version seems + * to be available. + */ +#define DST$C_C 7 /* Language == "C" */ +#define DST$C_VERSION 153 +#define DST$C_SOURCE 155 /* Source file */ +#define DST$C_PROLOG 162 +#define DST$C_BLKBEG 176 /* Beginning of block */ +#define DST$C_BLKEND 177 /* End of block */ +#define DST$C_ENTRY 181 +#define DST$C_PSECT 184 +#define DST$C_LINE_NUM 185 /* Line Number */ +#define DST$C_LBLORLIT 186 +#define DST$C_LABEL 187 +#define DST$C_MODBEG 188 /* Beginning of module */ +#define DST$C_MODEND 189 /* End of module */ +#define DST$C_RTNBEG 190 /* Beginning of routine */ +#define DST$C_RTNEND 191 /* End of routine */ +#define DST$C_DELTA_PC_W 1 /* Incr PC */ +#define DST$C_INCR_LINUM 2 /* Incr Line # */ +#define DST$C_INCR_LINUM_W 3 /* Incr Line # */ +#define DST$C_SET_LINUM_INCR 4 +#define DST$C_SET_LINUM_INCR_W 5 +#define DST$C_RESET_LINUM_INCR 6 +#define DST$C_BEG_STMT_MODE 7 +#define DST$C_END_STMT_MODE 8 +#define DST$C_SET_LINE_NUM 9 /* Set Line # */ +#define DST$C_SET_PC 10 +#define DST$C_SET_PC_W 11 +#define DST$C_SET_PC_L 12 +#define DST$C_SET_STMTNUM 13 +#define DST$C_TERM 14 /* End of lines */ +#define DST$C_TERM_W 15 /* End of lines */ +#define DST$C_SET_ABS_PC 16 /* Set PC */ +#define DST$C_DELTA_PC_L 17 /* Incr PC */ +#define DST$C_INCR_LINUM_L 18 /* Incr Line # */ +#define DST$C_SET_LINUM_B 19 /* Set Line # */ +#define DST$C_SET_LINUM_L 20 /* Set Line # */ +#define DST$C_TERM_L 21 /* End of lines */ +/* these are used with DST$C_SOURCE */ +#define DST$C_SRC_FORMFEED 16 /* ^L counts */ +#define DST$C_SRC_DECLFILE 1 /* Declare file */ +#define DST$C_SRC_SETFILE 2 /* Set file */ +#define DST$C_SRC_SETREC_L 3 /* Set record */ +#define DST$C_SRC_DEFLINES_W 10 /* # of line */ +/* the following are the codes for the various data types. Anything not on + * the list is included under 'advanced_type' + */ +#define DBG$C_UCHAR 0x02 +#define DBG$C_USINT 0x03 +#define DBG$C_ULINT 0x04 +#define DBG$C_SCHAR 0x06 +#define DBG$C_SSINT 0x07 +#define DBG$C_SLINT 0x08 +#define DBG$C_REAL4 0x0a +#define DBG$C_REAL8 0x0b +#define DBG$C_FUNCTION_ADDR 0x17 +#define DBG$C_ADVANCED_TYPE 0xa3 +/* These are the codes that are used to generate the definitions of struct + * union and enum records + */ +#define DBG$C_ENUM_ITEM 0xa4 +#define DBG$C_ENUM_START 0xa5 +#define DBG$C_ENUM_END 0xa6 +#define DBG$C_STRUCT_START 0xab +#define DBG$C_STRUCT_ITEM 0xff +#define DBG$C_STRUCT_END 0xac +/* These are the codes that are used in the suffix records to determine the + * actual data type + */ +#define DBG$C_BASIC 0x01 +#define DBG$C_BASIC_ARRAY 0x02 +#define DBG$C_STRUCT 0x03 +#define DBG$C_POINTER 0x04 +#define DBG$C_VOID 0x05 +#define DBG$C_COMPLEX_ARRAY 0x07 +/* These codes are used in the generation of the symbol definition records + */ +#define DBG$C_FUNCTION_PARAMETER 0xc9 +#define DBG$C_LOCAL_SYM 0xd9 diff --git a/gnu/usr.bin/as/obstack.c b/gnu/usr.bin/as/obstack.c new file mode 100644 index 0000000..c9cf561 --- /dev/null +++ b/gnu/usr.bin/as/obstack.c @@ -0,0 +1,337 @@ +/* obstack.c - subroutines used implicitly by object stack macros + Copyright (C) 1988 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 1, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "obstack.h" + +#ifdef __STDC__ +#define POINTER void * +#else +#define POINTER char * +#endif + +/* Determine default alignment. */ +struct fooalign {char x; double d;}; +#define DEFAULT_ALIGNMENT ((char *)&((struct fooalign *) 0)->d - (char *)0) +/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT. + But in fact it might be less smart and round addresses to as much as + DEFAULT_ROUNDING. So we prepare for it to do that. */ +union fooround {long x; double d;}; +#define DEFAULT_ROUNDING (sizeof (union fooround)) + +/* When we copy a long block of data, this is the unit to do it with. + On some machines, copying successive ints does not work; + in such a case, redefine COPYING_UNIT to `long' (if that works) + or `char' as a last resort. */ +#ifndef COPYING_UNIT +#define COPYING_UNIT int +#endif + +/* The non-GNU-C macros copy the obstack into this global variable + to avoid multiple evaluation. */ + +struct obstack *_obstack; + +/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default). + Objects start on multiples of ALIGNMENT (0 means use default). + CHUNKFUN is the function to use to allocate chunks, + and FREEFUN the function to free them. */ + +void +_obstack_begin (h, size, alignment, chunkfun, freefun) + struct obstack *h; + int size; + int alignment; + POINTER (*chunkfun) (); + void (*freefun) (); +{ + register struct _obstack_chunk* chunk; /* points to new chunk */ + + if (alignment == 0) + alignment = DEFAULT_ALIGNMENT; + if (size == 0) + /* Default size is what GNU malloc can fit in a 4096-byte block. */ + { + /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. + Use the values for range checking, because if range checking is off, + the extra bytes won't be missed terribly, but if range checking is on + and we used a larger request, a whole extra 4096 bytes would be + allocated. + + These number are irrelevant to the new GNU malloc. I suspect it is + less sensitive to the size of the request. */ + int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) + + 4 + DEFAULT_ROUNDING - 1) + & ~(DEFAULT_ROUNDING - 1)); + size = 4096 - extra; + } + + h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun; + h->freefun = freefun; + h->chunk_size = size; + h->alignment_mask = alignment - 1; + + chunk = h->chunk = (*h->chunkfun) (h->chunk_size); + h->next_free = h->object_base = chunk->contents; + h->chunk_limit = chunk->limit + = (char *) chunk + h->chunk_size; + chunk->prev = 0; +} + +/* Allocate a new current chunk for the obstack *H + on the assumption that LENGTH bytes need to be added + to the current object, or a new object of length LENGTH allocated. + Copies any partial object from the end of the old chunk + to the beginning of the new one. */ + +void +_obstack_newchunk (h, length) + struct obstack *h; + int length; +{ + register struct _obstack_chunk* old_chunk = h->chunk; + register struct _obstack_chunk* new_chunk; + register long new_size; + register int obj_size = h->next_free - h->object_base; + register int i; + int already; + + /* Compute size for new chunk. */ + new_size = (obj_size + length) + (obj_size >> 3) + 100; + if (new_size < h->chunk_size) + new_size = h->chunk_size; + + /* Allocate and initialize the new chunk. */ + new_chunk = h->chunk = (*h->chunkfun) (new_size); + new_chunk->prev = old_chunk; + new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size; + + /* Move the existing object to the new chunk. + Word at a time is fast and is safe if the object + is sufficiently aligned. */ + if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT) + { + for (i = obj_size / sizeof (COPYING_UNIT) - 1; + i >= 0; i--) + ((COPYING_UNIT *)new_chunk->contents)[i] + = ((COPYING_UNIT *)h->object_base)[i]; + /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT, + but that can cross a page boundary on a machine + which does not do strict alignment for COPYING_UNITS. */ + already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT); + } + else + already = 0; + /* Copy remaining bytes one by one. */ + for (i = already; i < obj_size; i++) + new_chunk->contents[i] = h->object_base[i]; + + /* If the object just copied was the only data in OLD_CHUNK, + free that chunk and remove it from the chain. */ + if (h->object_base == old_chunk->contents) + { + new_chunk->prev = old_chunk->prev; + (*h->freefun) (old_chunk); + } + + h->object_base = new_chunk->contents; + h->next_free = h->object_base + obj_size; +} + +/* Return nonzero if object OBJ has been allocated from obstack H. + This is here for debugging. + If you use it in a program, you are probably losing. */ + +int +_obstack_allocated_p (h, obj) + struct obstack *h; + POINTER obj; +{ + register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk* plp; /* point to previous chunk if any */ + + lp = (h)->chunk; + while (lp != 0 && ((POINTER)lp > obj || (POINTER)(lp)->limit < obj)) + { + plp = lp -> prev; + lp = plp; + } + return lp != 0; +} + +/* Free objects in obstack H, including OBJ and everything allocate + more recently than OBJ. If OBJ is zero, free everything in H. */ + +void +#ifdef __STDC__ +#undef obstack_free +obstack_free (struct obstack *h, POINTER obj) +#else +_obstack_free (h, obj) + struct obstack *h; + POINTER obj; +#endif +{ + register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk* plp; /* point to previous chunk if any */ + + lp = (h)->chunk; + /* We use >= because there cannot be an object at the beginning of a chunk. + But there can be an empty object at that address + at the end of another chunk. */ + while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj)) + { + plp = lp -> prev; + (*h->freefun) (lp); + lp = plp; + } + if (lp) + { + (h)->object_base = (h)->next_free = (char *)(obj); + (h)->chunk_limit = lp->limit; + (h)->chunk = lp; + } + else if (obj != 0) + /* obj is not in any of the chunks! */ + abort (); +} + +/* Let same .o link with output of gcc and other compilers. */ + +#ifdef __STDC__ +void +_obstack_free (h, obj) + struct obstack *h; + POINTER obj; +{ + obstack_free (h, obj); +} +#endif + +#if 0 +/* These are now turned off because the applications do not use it + and it uses bcopy via obstack_grow, which causes trouble on sysV. */ + +/* Now define the functional versions of the obstack macros. + Define them to simply use the corresponding macros to do the job. */ + +#ifdef __STDC__ +/* These function definitions do not work with non-ANSI preprocessors; + they won't pass through the macro names in parentheses. */ + +/* The function names appear in parentheses in order to prevent + the macro-definitions of the names from being expanded there. */ + +POINTER (obstack_base) (obstack) + struct obstack *obstack; +{ + return obstack_base (obstack); +} + +POINTER (obstack_next_free) (obstack) + struct obstack *obstack; +{ + return obstack_next_free (obstack); +} + +int (obstack_object_size) (obstack) + struct obstack *obstack; +{ + return obstack_object_size (obstack); +} + +int (obstack_room) (obstack) + struct obstack *obstack; +{ + return obstack_room (obstack); +} + +void (obstack_grow) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + obstack_grow (obstack, pointer, length); +} + +void (obstack_grow0) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + obstack_grow0 (obstack, pointer, length); +} + +void (obstack_1grow) (obstack, character) + struct obstack *obstack; + int character; +{ + obstack_1grow (obstack, character); +} + +void (obstack_blank) (obstack, length) + struct obstack *obstack; + int length; +{ + obstack_blank (obstack, length); +} + +void (obstack_1grow_fast) (obstack, character) + struct obstack *obstack; + int character; +{ + obstack_1grow_fast (obstack, character); +} + +void (obstack_blank_fast) (obstack, length) + struct obstack *obstack; + int length; +{ + obstack_blank_fast (obstack, length); +} + +POINTER (obstack_finish) (obstack) + struct obstack *obstack; +{ + return obstack_finish (obstack); +} + +POINTER (obstack_alloc) (obstack, length) + struct obstack *obstack; + int length; +{ + return obstack_alloc (obstack, length); +} + +POINTER (obstack_copy) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + return obstack_copy (obstack, pointer, length); +} + +POINTER (obstack_copy0) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + return obstack_copy0 (obstack, pointer, length); +} + +#endif /* __STDC__ */ + +#endif /* 0 */ diff --git a/gnu/usr.bin/as/obstack.h b/gnu/usr.bin/as/obstack.h new file mode 100644 index 0000000..fd779c4 --- /dev/null +++ b/gnu/usr.bin/as/obstack.h @@ -0,0 +1,418 @@ +/* obstack.h - object stack macros + Copyright (C) 1988 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 1, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Summary: + +All the apparent functions defined here are macros. The idea +is that you would use these pre-tested macros to solve a +very specific set of problems, and they would run fast. +Caution: no side-effects in arguments please!! They may be +evaluated MANY times!! + +These macros operate a stack of objects. Each object starts life +small, and may grow to maturity. (Consider building a word syllable +by syllable.) An object can move while it is growing. Once it has +been "finished" it never changes address again. So the "top of the +stack" is typically an immature growing object, while the rest of the +stack is of mature, fixed size and fixed address objects. + +These routines grab large chunks of memory, using a function you +supply, called `obstack_chunk_alloc'. On occasion, they free chunks, +by calling `obstack_chunk_free'. You must define them and declare +them before using any obstack macros. + +Each independent stack is represented by a `struct obstack'. +Each of the obstack macros expects a pointer to such a structure +as the first argument. + +One motivation for this package is the problem of growing char strings +in symbol tables. Unless you are "fascist pig with a read-only mind" +[Gosper's immortal quote from HAKMEM item 154, out of context] you +would not like to put any arbitrary upper limit on the length of your +symbols. + +In practice this often means you will build many short symbols and a +few long symbols. At the time you are reading a symbol you don't know +how long it is. One traditional method is to read a symbol into a +buffer, realloc()ating the buffer every time you try to read a symbol +that is longer than the buffer. This is beaut, but you still will +want to copy the symbol from the buffer to a more permanent +symbol-table entry say about half the time. + +With obstacks, you can work differently. Use one obstack for all symbol +names. As you read a symbol, grow the name in the obstack gradually. +When the name is complete, finalize it. Then, if the symbol exists already, +free the newly read name. + +The way we do this is to take a large chunk, allocating memory from +low addresses. When you want to build a symbol in the chunk you just +add chars above the current "high water mark" in the chunk. When you +have finished adding chars, because you got to the end of the symbol, +you know how long the chars are, and you can create a new object. +Mostly the chars will not burst over the highest address of the chunk, +because you would typically expect a chunk to be (say) 100 times as +long as an average object. + +In case that isn't clear, when we have enough chars to make up +the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed) +so we just point to it where it lies. No moving of chars is +needed and this is the second win: potentially long strings need +never be explicitly shuffled. Once an object is formed, it does not +change its address during its lifetime. + +When the chars burst over a chunk boundary, we allocate a larger +chunk, and then copy the partly formed object from the end of the old +chunk to the beginning of the new larger chunk. We then carry on +accreting characters to the end of the object as we normally would. + +A special macro is provided to add a single char at a time to a +growing object. This allows the use of register variables, which +break the ordinary 'growth' macro. + +Summary: + We allocate large chunks. + We carve out one object at a time from the current chunk. + Once carved, an object never moves. + We are free to append data of any size to the currently + growing object. + Exactly one object is growing in an obstack at any one time. + You can run one obstack per control block. + You may have as many control blocks as you dare. + Because of the way we do it, you can `unwind' a obstack + back to a previous state. (You may remove objects much + as you would with a stack.) +*/ + + +/* Don't do the contents of this file more than once. */ + +#ifndef __OBSTACKS__ +#define __OBSTACKS__ + +/* We use subtraction of (char *)0 instead of casting to int + because on word-addressable machines a simple cast to int + may ignore the byte-within-word field of the pointer. */ + +#ifndef __PTR_TO_INT +#define __PTR_TO_INT(P) ((P) - (char *)0) +#endif + +#ifndef __INT_TO_PTR +#define __INT_TO_PTR(P) ((P) + (char *)0) +#endif + +struct _obstack_chunk /* Lives at front of each chunk. */ +{ + char *limit; /* 1 past end of this chunk */ + struct _obstack_chunk *prev; /* address of prior chunk or NULL */ + char contents[4]; /* objects begin here */ +}; + +struct obstack /* control current object in current chunk */ +{ + long chunk_size; /* preferred size to allocate chunks in */ + struct _obstack_chunk* chunk; /* address of current struct obstack_chunk */ + char *object_base; /* address of object we are building */ + char *next_free; /* where to add next char to current object */ + char *chunk_limit; /* address of char after current chunk */ + int temp; /* Temporary for some macros. */ + int alignment_mask; /* Mask of alignment for each object. */ + struct _obstack_chunk *(*chunkfun) (); /* User's fcn to allocate a chunk. */ + void (*freefun) (); /* User's function to free a chunk. */ +}; + +/* Declare the external functions we use; they are in obstack.c. */ + +#ifdef __STDC__ + extern void _obstack_newchunk (struct obstack *, int); + extern void _obstack_free (struct obstack *, void *); + extern void _obstack_begin (struct obstack *, int, int, + void *(*) (), void (*) ()); +#else + extern void _obstack_newchunk (); + extern void _obstack_free (); + extern void _obstack_begin (); +#endif + +#ifdef __STDC__ + +/* Do the function-declarations after the structs + but before defining the macros. */ + +void obstack_init (struct obstack *obstack); + +void * obstack_alloc (struct obstack *obstack, int size); + +void * obstack_copy (struct obstack *obstack, void *address, int size); +void * obstack_copy0 (struct obstack *obstack, void *address, int size); + +void obstack_free (struct obstack *obstack, void *block); + +void obstack_blank (struct obstack *obstack, int size); + +void obstack_grow (struct obstack *obstack, void *data, int size); +void obstack_grow0 (struct obstack *obstack, void *data, int size); + +void obstack_1grow (struct obstack *obstack, int data_char); +void obstack_ptr_grow (struct obstack *obstack, void *data); +void obstack_int_grow (struct obstack *obstack, int data); + +void * obstack_finish (struct obstack *obstack); + +int obstack_object_size (struct obstack *obstack); + +int obstack_room (struct obstack *obstack); +void obstack_1grow_fast (struct obstack *obstack, int data_char); +void obstack_ptr_grow_fast (struct obstack *obstack, void *data); +void obstack_int_grow_fast (struct obstack *obstack, int data); +void obstack_blank_fast (struct obstack *obstack, int size); + +void * obstack_base (struct obstack *obstack); +void * obstack_next_free (struct obstack *obstack); +int obstack_alignment_mask (struct obstack *obstack); +int obstack_chunk_size (struct obstack *obstack); + +#endif /* __STDC__ */ + +/* Non-ANSI C cannot really support alternative functions for these macros, + so we do not declare them. */ + +/* Pointer to beginning of object being allocated or to be allocated next. + Note that this might not be the final address of the object + because a new chunk might be needed to hold the final size. */ + +#define obstack_base(h) ((h)->object_base) + +/* Size for allocating ordinary chunks. */ + +#define obstack_chunk_size(h) ((h)->chunk_size) + +/* Pointer to next byte not yet allocated in current chunk. */ + +#define obstack_next_free(h) ((h)->next_free) + +/* Mask specifying low bits that should be clear in address of an object. */ + +#define obstack_alignment_mask(h) ((h)->alignment_mask) + +#define obstack_init(h) \ + _obstack_begin ((h), 0, 0, \ + (void *(*) ()) obstack_chunk_alloc, obstack_chunk_free) + +#define obstack_begin(h, size) \ + _obstack_begin ((h), (size), 0, \ + (void *(*) ()) obstack_chunk_alloc, obstack_chunk_free) + +#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = achar) + +#define obstack_blank_fast(h,n) ((h)->next_free += (n)) + +#if defined (__GNUC__) && defined (__STDC__) + +/* For GNU C, if not -traditional, + we can define these macros to compute all args only once + without using a global variable. + Also, we can avoid using the `temp' slot, to make faster code. */ + +#define obstack_object_size(OBSTACK) \ + ({ struct obstack *__o = (OBSTACK); \ + (unsigned) (__o->next_free - __o->object_base); }) + +#define obstack_room(OBSTACK) \ + ({ struct obstack *__o = (OBSTACK); \ + (unsigned) (__o->chunk_limit - __o->next_free); }) + +/* Note that the call to _obstack_newchunk is enclosed in (..., 0) + so that we can avoid having void expressions + in the arms of the conditional expression. + Casting the third operand to void was tried before, + but some compilers won't accept it. */ +#define obstack_grow(OBSTACK,where,length) \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + ((__o->next_free + __len > __o->chunk_limit) \ + ? (_obstack_newchunk (__o, __len), 0) : 0); \ + bcopy (where, __o->next_free, __len); \ + __o->next_free += __len; \ + (void) 0; }) + +#define obstack_grow0(OBSTACK,where,length) \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + ((__o->next_free + __len + 1 > __o->chunk_limit) \ + ? (_obstack_newchunk (__o, __len + 1), 0) : 0), \ + bcopy (where, __o->next_free, __len), \ + __o->next_free += __len, \ + *(__o->next_free)++ = 0; \ + (void) 0; }) + +#define obstack_1grow(OBSTACK,datum) \ +({ struct obstack *__o = (OBSTACK); \ + ((__o->next_free + 1 > __o->chunk_limit) \ + ? (_obstack_newchunk (__o, 1), 0) : 0), \ + *(__o->next_free)++ = (datum); \ + (void) 0; }) + +/* These assume that the obstack alignment is good enough for pointers or ints, + and that the data added so far to the current object + shares that much alignment. */ + +#define obstack_ptr_grow(OBSTACK,datum) \ +({ struct obstack *__o = (OBSTACK); \ + ((__o->next_free + sizeof (void *) > __o->chunk_limit) \ + ? (_obstack_newchunk (__o, sizeof (void *)), 0) : 0), \ + *((void **)__o->next_free)++ = ((void *)datum); \ + (void) 0; }) + +#define obstack_int_grow(OBSTACK,datum) \ +({ struct obstack *__o = (OBSTACK); \ + ((__o->next_free + sizeof (int) > __o->chunk_limit) \ + ? (_obstack_newchunk (__o, sizeof (int)), 0) : 0), \ + *((int *)__o->next_free)++ = ((int)datum); \ + (void) 0; }) + +#define obstack_ptr_grow_fast(h,aptr) (*((void **)(h)->next_free)++ = (void *)aptr) +#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint) + +#define obstack_blank(OBSTACK,length) \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + ((__o->chunk_limit - __o->next_free < __len) \ + ? (_obstack_newchunk (__o, __len), 0) : 0); \ + __o->next_free += __len; \ + (void) 0; }) + +#define obstack_alloc(OBSTACK,length) \ +({ struct obstack *__h = (OBSTACK); \ + obstack_blank (__h, (length)); \ + obstack_finish (__h); }) + +#define obstack_copy(OBSTACK,where,length) \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow (__h, (where), (length)); \ + obstack_finish (__h); }) + +#define obstack_copy0(OBSTACK,where,length) \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow0 (__h, (where), (length)); \ + obstack_finish (__h); }) + +#define obstack_finish(OBSTACK) \ +({ struct obstack *__o = (OBSTACK); \ + void *value = (void *) __o->object_base; \ + __o->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT (__o->next_free)+__o->alignment_mask)\ + & ~ (__o->alignment_mask)); \ + ((__o->next_free - (char *)__o->chunk \ + > __o->chunk_limit - (char *)__o->chunk) \ + ? (__o->next_free = __o->chunk_limit) : 0); \ + __o->object_base = __o->next_free; \ + value; }) + +#define obstack_free(OBSTACK, OBJ) \ +({ struct obstack *__o = (OBSTACK); \ + void *__obj = (OBJ); \ + if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \ + __o->next_free = __o->object_base = __obj; \ + else (obstack_free) (__o, __obj); }) + +#else /* not __GNUC__ or not __STDC__ */ + +#define obstack_object_size(h) \ + (unsigned) ((h)->next_free - (h)->object_base) + +#define obstack_room(h) \ + (unsigned) ((h)->chunk_limit - (h)->next_free) + +#define obstack_grow(h,where,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \ + bcopy (where, (h)->next_free, (h)->temp), \ + (h)->next_free += (h)->temp) + +#define obstack_grow0(h,where,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp + 1 > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp + 1), 0) : 0), \ + bcopy (where, (h)->next_free, (h)->temp), \ + (h)->next_free += (h)->temp, \ + *((h)->next_free)++ = 0) + +#define obstack_1grow(h,datum) \ +( (((h)->next_free + 1 > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), 1), 0) : 0), \ + *((h)->next_free)++ = (datum)) + +#define obstack_ptr_grow(h,datum) \ +( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \ + *((char **)(((h)->next_free+=sizeof(char *))-sizeof(char *))) = ((char *)datum)) + +#define obstack_int_grow(h,datum) \ +( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \ + *((int *)(((h)->next_free+=sizeof(int))-sizeof(int))) = ((int)datum)) + +#define obstack_ptr_grow_fast(h,aptr) (*((char **)(h)->next_free)++ = (char *)aptr) +#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint) + +#define obstack_blank(h,length) \ +( (h)->temp = (length), \ + (((h)->chunk_limit - (h)->next_free < (h)->temp) \ + ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \ + (h)->next_free += (h)->temp) + +#define obstack_alloc(h,length) \ + (obstack_blank ((h), (length)), obstack_finish ((h))) + +#define obstack_copy(h,where,length) \ + (obstack_grow ((h), (where), (length)), obstack_finish ((h))) + +#define obstack_copy0(h,where,length) \ + (obstack_grow0 ((h), (where), (length)), obstack_finish ((h))) + +#define obstack_finish(h) \ +( (h)->temp = __PTR_TO_INT ((h)->object_base), \ + (h)->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \ + & ~ ((h)->alignment_mask)), \ + (((h)->next_free - (char *)(h)->chunk \ + > (h)->chunk_limit - (char *)(h)->chunk) \ + ? ((h)->next_free = (h)->chunk_limit) : 0), \ + (h)->object_base = (h)->next_free, \ + __INT_TO_PTR ((h)->temp)) + +#ifdef __STDC__ +#define obstack_free(h,obj) \ +( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \ + (((h)->temp >= 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0))) +#else +#define obstack_free(h,obj) \ +( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \ + (((h)->temp >= 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0))) +#endif + +#endif /* not __GNUC__ or not __STDC__ */ + +#endif /* not __OBSTACKS__ */ diff --git a/gnu/usr.bin/as/output-file.c b/gnu/usr.bin/as/output-file.c new file mode 100644 index 0000000..ff71f40 --- /dev/null +++ b/gnu/usr.bin/as/output-file.c @@ -0,0 +1,81 @@ +/* output-file.c - Deal with the output file + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Confines all details of emitting object bytes to this module. + * All O/S specific crocks should live here. + * What we lose in "efficiency" we gain in modularity. + * Note we don't need to #include the "as.h" file. No common coupling! + */ + +/* #include "style.h" */ +#include <stdio.h> + +void as_perror(); + +static FILE * +stdoutput; + +void +output_file_create (name) + char * name; +{ + if(name[0]=='-' && name[1]=='\0') + stdoutput=stdout; + else if ( ! (stdoutput = fopen( name, "w" )) ) + { + as_perror ("FATAL: Can't create %s", name); + exit(42); + } +} + + + +void +output_file_close (filename) + char * filename; +{ + if ( EOF == fclose( stdoutput ) ) + { + as_perror ("FATAL: Can't close %s", filename); + exit(42); + } + stdoutput = NULL; /* Trust nobody! */ +} + +void +output_file_append (where, length, filename) + char * where; + long int length; + char * filename; +{ + + for (; length; length--,where++) + { + (void)putc(*where,stdoutput); + if(ferror(stdoutput)) + /* if ( EOF == (putc( *where, stdoutput )) ) */ + { + as_perror("Failed to emit an object byte", filename); + as_fatal("Can't continue"); + } + } +} + +/* end: output-file.c */ diff --git a/gnu/usr.bin/as/read.c b/gnu/usr.bin/as/read.c new file mode 100644 index 0000000..8357107 --- /dev/null +++ b/gnu/usr.bin/as/read.c @@ -0,0 +1,2188 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + */ + +#ifndef lint +static char sccsid[] = "@(#)read.c 6.4 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* read.c - read a source file - + Copyright (C) 1986,1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define MASK_CHAR (0xFF) /* If your chars aren't 8 bits, you will + change this a bit. But then, GNU isn't + spozed to run on your machine anyway. + (RMS is so shortsighted sometimes.) + */ + +#define MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT (16) + /* This is the largest known floating point */ + /* format (for now). It will grow when we */ + /* do 4361 style flonums. */ + + +/* Routines that read assembler source text to build spagetti in memory. */ +/* Another group of these functions is in the as-expr.c module */ + +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "as.h" +#include "read.h" +#include "md.h" +#include "hash.h" +#include "obstack.h" +#include "frags.h" +#include "flonum.h" +#include "struc-symbol.h" +#include "expr.h" +#include "symbols.h" + +#ifdef SPARC +#include "sparc.h" +#define OTHER_ALIGN +#endif +#ifdef I860 +#include "i860.h" +#endif + +char * input_line_pointer; /* -> next char of source file to parse. */ + + +#if BITS_PER_CHAR != 8 +The following table is indexed by [ (char) ] and will break if +a char does not have exactly 256 states (hopefully 0:255!) ! +#endif + +const char /* used by is_... macros. our ctype[] */ +lex_type [256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ABCDEFGHIJKLMNO */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* PQRSTUVWXYZ[\]^_ */ + 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0123456789:;<=>? */ + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, /* PQRSTUVWXYZ[\]^_ */ + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, /* pqrstuvwxyz{|}~. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +/* + * In: a character. + * Out: TRUE if this character ends a line. + */ +#define _ (0) +const char is_end_of_line [256] = { + _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, _, /* @abcdefghijklmno */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, /* 0123456789:;<=>? */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ /* */ +}; +#undef _ + + /* Functions private to this file. */ +void equals(); +void big_cons(); +void cons(); +static char* demand_copy_C_string(); +static char* demand_copy_string(); +void demand_empty_rest_of_line(); +void float_cons(); +long int get_absolute_expression(); +static char get_absolute_expression_and_terminator(); +static segT get_known_segmented_expression(); +void ignore_rest_of_line(); +static int is_it_end_of_statement(); +static void pobegin(); +static void pseudo_set(); +static void stab(); +static void stringer(); + +extern char line_comment_chars[]; + +static char * buffer_limit; /* -> 1 + last char in buffer. */ + +static char * bignum_low; /* Lowest char of bignum. */ +static char * bignum_limit; /* 1st illegal address of bignum. */ +static char * bignum_high; /* Highest char of bignum. */ + /* May point to (bignum_start-1). */ + /* Never >= bignum_limit. */ +static char *old_buffer = 0; /* JF a hack */ +static char *old_input; +static char *old_limit; + +#ifndef WORKING_DOT_WORD +struct broken_word *broken_words; +int new_broken_words = 0; +#endif + +static void grow_bignum (); +static int next_char_of_string (); + +void +read_begin() +{ + pobegin(); + obstack_begin( ¬es, 5000 ); +#define BIGNUM_BEGIN_SIZE (16) + bignum_low = xmalloc((long)BIGNUM_BEGIN_SIZE); + bignum_limit = bignum_low + BIGNUM_BEGIN_SIZE; +} + +/* set up pseudo-op tables */ + +static struct hash_control * +po_hash = NULL; /* use before set up: NULL-> address error */ + + +void s_abort(), s_align(), s_comm(), s_data(); +void s_desc(), s_even(), s_file(), s_fill(); +void s_globl(), s_lcomm(), s_line(), s_lsym(); +void s_org(), s_set(), s_space(), s_text(); +#ifdef VMS +char const_flag = 0; +void s_const(); +#endif + +#ifdef DONTDEF +void s_gdbline(), s_gdblinetab(); +void s_gdbbeg(), s_gdbblock(), s_gdbend(), s_gdbsym(); +#endif + +void stringer(); +void cons(); +void float_cons(); +void big_cons(); +void stab(); + +static const pseudo_typeS +potable[] = +{ + { "abort", s_abort, 0 }, + { "align", s_align, 0 }, + { "ascii", stringer, 0 }, + { "asciz", stringer, 1 }, + { "byte", cons, 1 }, + { "comm", s_comm, 0 }, +#ifdef VMS + { "const", s_const, 0 }, +#endif + { "data", s_data, 0 }, + { "desc", s_desc, 0 }, + { "double", float_cons, 'd' }, + { "file", s_file, 0 }, + { "fill", s_fill, 0 }, + { "float", float_cons, 'f' }, +#ifdef DONTDEF + { "gdbbeg", s_gdbbeg, 0 }, + { "gdbblock", s_gdbblock, 0 }, + { "gdbend", s_gdbend, 0 }, + { "gdbsym", s_gdbsym, 0 }, + { "gdbline", s_gdbline, 0 }, + { "gdblinetab",s_gdblinetab, 0 }, +#endif + { "globl", s_globl, 0 }, + { "int", cons, 4 }, + { "lcomm", s_lcomm, 0 }, + { "line", s_line, 0 }, + { "long", cons, 4 }, + { "lsym", s_lsym, 0 }, + { "octa", big_cons, 16 }, + { "org", s_org, 0 }, + { "quad", big_cons, 8 }, + { "set", s_set, 0 }, + { "short", cons, 2 }, + { "single", float_cons, 'f' }, + { "space", s_space, 0 }, + { "stabd", stab, 'd' }, + { "stabn", stab, 'n' }, + { "stabs", stab, 's' }, + { "text", s_text, 0 }, +#ifndef SPARC + { "word", cons, 2 }, +#endif + { NULL} /* end sentinel */ +}; + +static void +pobegin() +{ + char * errtxt; /* error text */ + const pseudo_typeS * pop; + + po_hash = hash_new(); + errtxt = ""; /* OK so far */ + for (pop=potable; pop->poc_name && !*errtxt; pop++) + { + errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop); + } + + for(pop=md_pseudo_table; pop->poc_name && !*errtxt; pop++) + errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop); + + if (*errtxt) + { + as_fatal ("error constructing pseudo-op table"); + } +} /* pobegin() */ + +/* read_a_source_file() + * + * File has already been opened, and will be closed by our caller. + * + * We read the file, putting things into a web that + * represents what we have been reading. + */ +void +read_a_source_file (buffer) + char * buffer; /* 1st character of each buffer of lines is here. */ +{ + register char c; + register char * s; /* string of symbol, '\0' appended */ + register int temp; + /* register struct frag * fragP; JF unused */ /* a frag we just made */ + pseudo_typeS *pop; +#ifdef DONTDEF + void gdb_block_beg(); + void gdb_block_position(); + void gdb_block_end(); + void gdb_symbols_fixup(); +#endif + + subseg_new (SEG_TEXT, 0); + while ( buffer_limit = input_scrub_next_buffer (&buffer) ) + { /* We have another line to parse. */ + know( buffer_limit [-1] == '\n' ); /* Must have a sentinel. */ + input_line_pointer = buffer; + contin: /* JF this goto is my fault I admit it. Someone brave please re-write + the whole input section here? Pleeze??? */ + while ( input_line_pointer < buffer_limit ) + { /* We have more of this buffer to parse. */ + /* + * We now have input_line_pointer -> 1st char of next line. + * If input_line_pointer [-1] == '\n' then we just + * scanned another line: so bump line counters. + */ + if (input_line_pointer [-1] == '\n') + { + bump_line_counters (); + } + /* + * We are at the begining of a line, or similar place. + * We expect a well-formed assembler statement. + * A "symbol-name:" is a statement. + * + * Depending on what compiler is used, the order of these tests + * may vary to catch most common case 1st. + * Each test is independent of all other tests at the (top) level. + * PLEASE make a compiler that doesn't use this assembler. + * It is crufty to waste a compiler's time encoding things for this + * assembler, which then wastes more time decoding it. + * (And communicating via (linear) files is silly! + * If you must pass stuff, please pass a tree!) + */ + if ( (c= * input_line_pointer ++) == '\t' || c == ' ' || c=='\f') + { + c = * input_line_pointer ++; + } + know( c != ' ' ); /* No further leading whitespace. */ + /* + * C is the 1st significant character. + * Input_line_pointer points after that character. + */ + if ( is_name_beginner(c) ) + { /* want user-defined label or pseudo/opcode */ + s = -- input_line_pointer; + c = get_symbol_end(); /* name's delimiter */ + /* + * C is character after symbol. + * That character's place in the input line is now '\0'. + * S points to the beginning of the symbol. + * [In case of pseudo-op, s -> '.'.] + * Input_line_pointer -> '\0' where c was. + */ + if ( c == ':' ) + { + if (flagseen['g']) + /* set line number for function definition */ + funcstab(s); + colon(s); /* user-defined label */ + * input_line_pointer ++ = ':'; /* Put ':' back for error messages' sake. */ + /* Input_line_pointer -> after ':'. */ + SKIP_WHITESPACE(); + } + else if(c=='=' || input_line_pointer[1]=='=') /* JF deal with FOO=BAR */ + { + equals(s); + demand_empty_rest_of_line(); + } + else + { /* expect pseudo-op or machine instruction */ + if ( *s=='.' ) + { + /* + * PSEUDO - OP. + * + * WARNING: c has next char, which may be end-of-line. + * We lookup the pseudo-op table with s+1 because we + * already know that the pseudo-op begins with a '.'. + */ + + pop= (pseudo_typeS *) hash_find (po_hash, s+1); + + /* Print the error msg now, while we still can */ + if(!pop) + as_bad("Unknown pseudo-op: '%s'",s); + + /* Put it back for error messages etc. */ + * input_line_pointer = c; + /* The following skip of whitespace is compulsory. */ + /* A well shaped space is sometimes all that seperates keyword from operands. */ + if ( c == ' ' || c == '\t' ) + { /* Skip seperator after keyword. */ + input_line_pointer ++; + } + /* + * Input_line is restored. + * Input_line_pointer -> 1st non-blank char + * after pseudo-operation. + */ + if(!pop) { + ignore_rest_of_line(); + break; + } + else + (*pop->poc_handler)(pop->poc_val); + } + else + { /* machine instruction */ + /* If source file debugging, emit a stab. */ + if (flagseen['g']) + linestab(); + + /* WARNING: c has char, which may be end-of-line. */ + /* Also: input_line_pointer -> `\0` where c was. */ + * input_line_pointer = c; + while ( ! is_end_of_line [* input_line_pointer] ) + { + input_line_pointer ++; + } + c = * input_line_pointer; + * input_line_pointer = '\0'; + md_assemble (s); /* Assemble 1 instruction. */ + * input_line_pointer ++ = c; + /* We resume loop AFTER the end-of-line from this instruction */ + } /* if (*s=='.') */ + } /* if c==':' */ + continue; + } /* if (is_name_beginner(c) */ + + + if ( is_end_of_line [c] ) + { /* empty statement */ + continue; + } + + if ( isdigit(c) ) + { /* local label ("4:") */ + temp = c - '0'; +#ifdef SUN_ASM_SYNTAX + if( *input_line_pointer=='$') + input_line_pointer++; +#endif + if ( * input_line_pointer ++ == ':' ) + { + local_colon (temp); + } + else + { + as_bad( "Spurious digit %d.", temp); + input_line_pointer -- ; + ignore_rest_of_line(); + } + continue; + } + if(c && index(line_comment_chars,c)) { /* Its a comment. Better say APP or NO_APP */ + char *ends; + char *strstr(); + char *new_buf; + char *new_tmp; + int new_length; + char *tmp_buf = 0; + extern char *scrub_string,*scrub_last_string; + int scrub_from_string(); + void scrub_to_string(); + + bump_line_counters(); + s=input_line_pointer; + if(strncmp(s,"APP\n",4)) + continue; /* We ignore it */ + s+=4; + + ends=strstr(s,"#NO_APP\n"); + + if(!ends) { + int tmp_len; + int num; + + /* The end of the #APP wasn't in this buffer. We + keep reading in buffers until we find the #NO_APP + that goes with this #APP There is one. The specs + guarentee it. . .*/ + tmp_len=buffer_limit-s; + tmp_buf=xmalloc(tmp_len); + bcopy(s,tmp_buf,tmp_len); + do { + new_tmp = input_scrub_next_buffer(&buffer); + if(!new_tmp) + break; + else + buffer_limit = new_tmp; + input_line_pointer = buffer; + ends = strstr(buffer,"#NO_APP\n"); + if(ends) + num=ends-buffer; + else + num=buffer_limit-buffer; + + tmp_buf=xrealloc(tmp_buf,tmp_len+num); + bcopy(buffer,tmp_buf+tmp_len,num); + tmp_len+=num; + } while(!ends); + + input_line_pointer= ends ? ends+8 : NULL; + + s=tmp_buf; + ends=s+tmp_len; + + } else { + input_line_pointer=ends+8; + } + new_buf=xmalloc(100); + new_length=100; + new_tmp=new_buf; + + scrub_string=s; + scrub_last_string = ends; + for(;;) { + int ch; + + ch=do_scrub_next_char(scrub_from_string,scrub_to_string); + if(ch==EOF) break; + *new_tmp++=ch; + if(new_tmp==new_buf+new_length) { + new_buf=xrealloc(new_buf,new_length+100); + new_tmp=new_buf+new_length; + new_length+=100; + } + } + + if(tmp_buf) + free(tmp_buf); + old_buffer=buffer; + old_input=input_line_pointer; + old_limit=buffer_limit; + buffer=new_buf; + input_line_pointer=new_buf; + buffer_limit=new_tmp; + continue; + } + + as_bad("Junk character %d.",c); + ignore_rest_of_line(); + } /* while (input_line_pointer<buffer_limit )*/ + if(old_buffer) { + bump_line_counters(); + if(old_input == 0) + return; + buffer=old_buffer; + input_line_pointer=old_input; + buffer_limit=old_limit; + old_buffer = 0; + goto contin; + } + } /* while (more bufrers to scan) */ +} /* read_a_source_file() */ + +void +s_abort() +{ + as_fatal(".abort detected. Abandoning ship."); +} + +#ifdef OTHER_ALIGN +static void +s_align() +{ + register unsigned int temp; + register long int temp_fill; + unsigned int i; + + temp = get_absolute_expression (); +#define MAX_ALIGNMENT (1 << 15) + if ( temp > MAX_ALIGNMENT ) { + as_bad("Alignment too large: %d. assumed.", temp = MAX_ALIGNMENT); + } + + /* + * For the sparc, `.align (1<<n)' actually means `.align n' + * so we have to convert it. + */ + if (temp != 0) { + for (i = 0; (temp & 1) == 0; temp >>= 1, ++i) + ; + } + if (temp != 1) + as_bad("Alignment not a power of 2"); + + temp = i; + if (*input_line_pointer == ',') { + input_line_pointer ++; + temp_fill = get_absolute_expression (); + } else { + temp_fill = 0; + } + /* Only make a frag if we HAVE to. . . */ + if (temp && ! need_pass_2) + frag_align (temp, (int)temp_fill); + + demand_empty_rest_of_line(); +} +#else + +void +s_align() +{ + register int temp; + register long int temp_fill; + + temp = get_absolute_expression (); +#define MAX_ALIGNMENT (15) + if ( temp > MAX_ALIGNMENT ) + as_bad("Alignment too large: %d. assumed.", temp = MAX_ALIGNMENT); + else if ( temp < 0 ) { + as_bad("Alignment negative. 0 assumed."); + temp = 0; + } + if ( *input_line_pointer == ',' ) { + input_line_pointer ++; + temp_fill = get_absolute_expression (); + } else + temp_fill = 0; + /* Only make a frag if we HAVE to. . . */ + if ( temp && ! need_pass_2 ) + frag_align (temp, (int)temp_fill); + demand_empty_rest_of_line(); +} +#endif + +void +s_comm() +{ + register char *name; + register char c; + register char *p; + register int temp; + register symbolS * symbolP; + + name = input_line_pointer; + c = get_symbol_end(); + /* just after name is now '\0' */ + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE(); + if ( * input_line_pointer != ',' ) { + as_bad("Expected comma after symbol-name"); + ignore_rest_of_line(); + return; + } + input_line_pointer ++; /* skip ',' */ + if ( (temp = get_absolute_expression ()) < 0 ) { + as_warn(".COMMon length (%d.) <0! Ignored.", temp); + ignore_rest_of_line(); + return; + } + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; + if ( (symbolP -> sy_type & N_TYPE) != N_UNDF || + symbolP -> sy_other != 0 || symbolP -> sy_desc != 0) { + as_warn( "Ignoring attempt to re-define symbol"); + ignore_rest_of_line(); + return; + } + if (symbolP -> sy_value) { + if (symbolP -> sy_value != temp) + as_warn( "Length of .comm \"%s\" is already %d. Not changed to %d.", + symbolP -> sy_name, symbolP -> sy_value, temp); + } else { + symbolP -> sy_value = temp; + symbolP -> sy_type |= N_EXT; + } +#ifdef VMS + if(!temp) + symbolP->sy_other = const_flag; +#endif + know( symbolP -> sy_frag == &zero_address_frag ); + demand_empty_rest_of_line(); +} + +#ifdef VMS +void +s_const() +{ + register int temp; + + temp = get_absolute_expression (); + subseg_new (SEG_DATA, (subsegT)temp); + const_flag = 1; + demand_empty_rest_of_line(); +} +#endif + +void +s_data() +{ + register int temp; + + temp = get_absolute_expression (); + subseg_new (SEG_DATA, (subsegT)temp); +#ifdef VMS + const_flag = 0; +#endif + demand_empty_rest_of_line(); +} + +void +s_desc() +{ + register char *name; + register char c; + register char *p; + register symbolS * symbolP; + register int temp; + + /* + * Frob invented at RMS' request. Set the n_desc of a symbol. + */ + name = input_line_pointer; + c = get_symbol_end(); + p = input_line_pointer; + symbolP = symbol_table_lookup (name); + * p = c; + SKIP_WHITESPACE(); + if ( * input_line_pointer != ',' ) { + *p = 0; + as_bad("Expected comma after name \"%s\"", name); + *p = c; + ignore_rest_of_line(); + } else { + input_line_pointer ++; + temp = get_absolute_expression (); + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; + symbolP -> sy_desc = temp; + } + demand_empty_rest_of_line(); +} + +void +s_file() +{ + register char *s; + int length; + + /* Some assemblers tolerate immediately following '"' */ + if ( s = demand_copy_string( & length ) ) { + new_logical_line (s, -1); + demand_empty_rest_of_line(); + } +} + +void +s_fill() +{ + long int temp_repeat; + long int temp_size; + register long int temp_fill; + char *p; + + if ( get_absolute_expression_and_terminator(& temp_repeat) != ',' ) { + input_line_pointer --; /* Backup over what was not a ','. */ + as_warn("Expect comma after rep-size in .fill"); + ignore_rest_of_line(); + return; + } + if ( get_absolute_expression_and_terminator( & temp_size) != ',' ) { + input_line_pointer --; /* Backup over what was not a ','. */ + as_warn("Expected comma after size in .fill"); + ignore_rest_of_line(); + return; + } + /* + * This is to be compatible with BSD 4.2 AS, not for any rational reason. + */ +#define BSD_FILL_SIZE_CROCK_8 (8) + if ( temp_size > BSD_FILL_SIZE_CROCK_8 ) { + as_bad(".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8); + temp_size = BSD_FILL_SIZE_CROCK_8 ; + } if ( temp_size < 0 ) { + as_warn("Size negative: .fill ignored."); + temp_size = 0; + } else if ( temp_repeat <= 0 ) { + as_warn("Repeat < 0, .fill ignored"); + temp_size = 0; + } + temp_fill = get_absolute_expression (); + if ( temp_size && !need_pass_2 ) { + p = frag_var (rs_fill, (int)temp_size, (int)temp_size, (relax_substateT)0, (symbolS *)0, temp_repeat, (char *)0); + bzero (p, (int)temp_size); +/* + * The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX flavoured AS. + * The following bizzare behaviour is to be compatible with above. + * I guess they tried to take up to 8 bytes from a 4-byte expression + * and they forgot to sign extend. Un*x Sux. + */ +#define BSD_FILL_SIZE_CROCK_4 (4) + md_number_to_chars (p, temp_fill, temp_size > BSD_FILL_SIZE_CROCK_4 ? BSD_FILL_SIZE_CROCK_4 : (int)temp_size); +/* + * Note: .fill (),0 emits no frag (since we are asked to .fill 0 bytes) + * but emits no error message because it seems a legal thing to do. + * It is a degenerate case of .fill but could be emitted by a compiler. + */ + } + demand_empty_rest_of_line(); +} + +#ifdef DONTDEF +void +s_gdbbeg() +{ + register int temp; + + temp = get_absolute_expression (); + if (temp < 0) + as_warn( "Block number <0. Ignored." ); + else if (flagseen ['G']) + gdb_block_beg ( (long int) temp, frag_now, (long int)(obstack_next_free(& frags) - frag_now -> fr_literal)); + demand_empty_rest_of_line (); +} + +void +s_gdbblock() +{ + register int position; + int temp; + + if (get_absolute_expression_and_terminator (&temp) != ',') { + as_warn( "expected comma before position in .gdbblock"); + --input_line_pointer; + ignore_rest_of_line (); + return; + } + position = get_absolute_expression (); + if (flagseen ['G']) + gdb_block_position ((long int) temp, (long int) position); + demand_empty_rest_of_line (); +} + +void +s_gdbend() +{ + register int temp; + + temp = get_absolute_expression (); + if (temp < 0) + as_warn( "Block number <0. Ignored." ); + else if (flagseen ['G']) + gdb_block_end ( (long int) temp, frag_now, (long int)(obstack_next_free(& frags) - frag_now -> fr_literal)); + demand_empty_rest_of_line (); +} + +void +s_gdbsym() +{ + register char *name, + *p; + register char c; + register symbolS * symbolP; + register int temp; + + name = input_line_pointer; + c = get_symbol_end(); + p = input_line_pointer; + symbolP = symbol_find_or_make (name); + *p = c; + SKIP_WHITESPACE(); + if ( * input_line_pointer != ',' ) { + as_warn("Expected comma after name"); + ignore_rest_of_line(); + return; + } + input_line_pointer ++; + if ( (temp = get_absolute_expression ()) < 0 ) { + as_warn("Bad GDB symbol file offset (%d.) <0! Ignored.", temp); + ignore_rest_of_line(); + return; + } + if (flagseen ['G']) + gdb_symbols_fixup (symbolP, (long int)temp); + demand_empty_rest_of_line (); +} + +void +s_gdbline() +{ + int file_number, + lineno; + + if(get_absolute_expression_and_terminator(&file_number) != ',') { + as_warn("expected comman after filenum in .gdbline"); + ignore_rest_of_line(); + return; + } + lineno=get_absolute_expression(); + if(flagseen['G']) + gdb_line(file_number,lineno); + demand_empty_rest_of_line(); +} + + +void +s_gdblinetab() +{ + int file_number, + offset; + + if(get_absolute_expression_and_terminator(&file_number) != ',') { + as_warn("expected comman after filenum in .gdblinetab"); + ignore_rest_of_line(); + return; + } + offset=get_absolute_expression(); + if(flagseen['G']) + gdb_line_tab(file_number,offset); + demand_empty_rest_of_line(); +} +#endif + +void +s_globl() +{ + register char *name; + register int c; + register symbolS * symbolP; + + do { + name = input_line_pointer; + c = get_symbol_end(); + symbolP = symbol_find_or_make (name); + * input_line_pointer = c; + SKIP_WHITESPACE(); + symbolP -> sy_type |= N_EXT; + if(c==',') { + input_line_pointer++; + SKIP_WHITESPACE(); + if(*input_line_pointer=='\n') + c='\n'; + } + } while(c==','); + demand_empty_rest_of_line(); +} + +void +s_lcomm() +{ + register char *name; + register char c; + register char *p; + register int temp; + register symbolS * symbolP; + + name = input_line_pointer; + c = get_symbol_end(); + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE(); + if ( * input_line_pointer != ',' ) { + as_warn("Expected comma after name"); + ignore_rest_of_line(); + return; + } + input_line_pointer ++; + if ( (temp = get_absolute_expression ()) < 0 ) { + as_warn("BSS length (%d.) <0! Ignored.", temp); + ignore_rest_of_line(); + return; + } + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; + if ( symbolP -> sy_other == 0 + && symbolP -> sy_desc == 0 + && ( ( symbolP -> sy_type == N_BSS + && symbolP -> sy_value == local_bss_counter) + || ( (symbolP -> sy_type & N_TYPE) == N_UNDF + && symbolP -> sy_value == 0))) { + symbolP -> sy_value = local_bss_counter; + symbolP -> sy_type = N_BSS; + symbolP -> sy_frag = & bss_address_frag; + local_bss_counter += temp; + } else + as_warn( "Ignoring attempt to re-define symbol from %d. to %d.", + symbolP -> sy_value, local_bss_counter ); + demand_empty_rest_of_line(); +} + +void +s_line() +{ + /* Assume delimiter is part of expression. */ + /* BSD4.2 as fails with delightful bug, so we */ + /* are not being incompatible here. */ + new_logical_line ((char *)NULL, (int)(get_absolute_expression ())); + demand_empty_rest_of_line(); +} + +void +s_long() +{ + cons(4); +} + +void +s_int() +{ + cons(4); +} + +void +s_lsym() +{ + register char *name; + register char c; + register char *p; + register segT segment; + expressionS exp; + register symbolS *symbolP; + + /* we permit ANY expression: BSD4.2 demands constants */ + name = input_line_pointer; + c = get_symbol_end(); + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE(); + if ( * input_line_pointer != ',' ) { + *p = 0; + as_warn("Expected comma after name \"%s\"", name); + *p = c; + ignore_rest_of_line(); + return; + } + input_line_pointer ++; + segment = expression (& exp); + if ( segment != SEG_ABSOLUTE && segment != SEG_DATA && + segment != SEG_TEXT && segment != SEG_BSS) { + as_bad("Bad expression: %s", seg_name [(int)segment]); + ignore_rest_of_line(); + return; + } + know( segment == SEG_ABSOLUTE || segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS ); + *p = 0; + symbolP = symbol_new (name,(unsigned char)(seg_N_TYPE [(int) segment]), + 0, 0, (valueT)(exp . X_add_number), & zero_address_frag); + *p = c; + demand_empty_rest_of_line(); +} + +void +s_org() +{ + register segT segment; + expressionS exp; + register long int temp_fill; + register char *p; +/* + * Don't believe the documentation of BSD 4.2 AS. + * There is no such thing as a sub-segment-relative origin. + * Any absolute origin is given a warning, then assumed to be segment-relative. + * Any segmented origin expression ("foo+42") had better be in the right + * segment or the .org is ignored. + * + * BSD 4.2 AS warns if you try to .org backwards. We cannot because we + * never know sub-segment sizes when we are reading code. + * BSD will crash trying to emit -ve numbers of filler bytes in certain + * .orgs. We don't crash, but see as-write for that code. + */ +/* + * Don't make frag if need_pass_2==TRUE. + */ + segment = get_known_segmented_expression(& exp); + if ( *input_line_pointer == ',' ) { + input_line_pointer ++; + temp_fill = get_absolute_expression (); + } else + temp_fill = 0; + if ( ! need_pass_2 ) { + if (segment != now_seg && segment != SEG_ABSOLUTE) + as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.", + seg_name [(int) segment], seg_name [(int) now_seg]); + p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp . X_add_symbol, + exp . X_add_number, (char *)0); + * p = temp_fill; + } /* if (ok to make frag) */ + demand_empty_rest_of_line(); +} + +void +s_set() +{ + register char *name; + register char delim; + register char *end_name; + register symbolS *symbolP; + + /* + * Especial apologies for the random logic: + * this just grew, and could be parsed much more simply! + * Dean in haste. + */ + name = input_line_pointer; + delim = get_symbol_end(); + end_name = input_line_pointer; + *end_name = delim; + SKIP_WHITESPACE(); + if ( * input_line_pointer != ',' ) { + *end_name = 0; + as_warn("Expected comma after name \"%s\"", name); + *end_name = delim; + ignore_rest_of_line(); + return; + } + input_line_pointer ++; + *end_name = 0; + if(name[0]=='.' && name[1]=='\0') { + /* Turn '. = mumble' into a .org mumble */ + register segT segment; + expressionS exp; + register char *ptr; + + segment = get_known_segmented_expression(& exp); + if ( ! need_pass_2 ) { + if (segment != now_seg && segment != SEG_ABSOLUTE) + as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.", + seg_name [(int) segment], seg_name [(int) now_seg]); + ptr = frag_var (rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol, + exp.X_add_number, (char *)0); + *ptr= 0; + } /* if (ok to make frag) */ + *end_name = delim; + return; + } + symbolP = symbol_find_or_make (name); + *end_name = delim; + pseudo_set (symbolP); + demand_empty_rest_of_line (); +} + +void +s_space() +{ + long int temp_repeat; + register long int temp_fill; + register char *p; + + /* Just like .fill, but temp_size = 1 */ + if ( get_absolute_expression_and_terminator( & temp_repeat) == ',' ) { + temp_fill = get_absolute_expression (); + } else { + input_line_pointer --; /* Backup over what was not a ','. */ + temp_fill = 0; + } + if ( temp_repeat <= 0 ) { + as_warn("Repeat < 0, .space ignored"); + ignore_rest_of_line(); + return; + } + if ( ! need_pass_2 ) { + p = frag_var (rs_fill, 1, 1, (relax_substateT)0, (symbolS *)0, + temp_repeat, (char *)0); + * p = temp_fill; + } + demand_empty_rest_of_line(); +} + +void +s_text() +{ + register int temp; + + temp = get_absolute_expression (); + subseg_new (SEG_TEXT, (subsegT)temp); + demand_empty_rest_of_line(); +} + + +/*( JF was static, but can't be if machine dependent pseudo-ops are to use it */ + +void +demand_empty_rest_of_line() +{ + SKIP_WHITESPACE(); + if ( is_end_of_line [* input_line_pointer] ) + { + input_line_pointer ++; + } + else + { + ignore_rest_of_line(); + } + /* Return having already swallowed end-of-line. */ +} /* Return pointing just after end-of-line. */ + + +void +ignore_rest_of_line() /* For suspect lines: gives warning. */ +{ + if ( ! is_end_of_line [* input_line_pointer]) + { + as_warn("Rest of line ignored. 1st junk character valued %d (%c)." + , * input_line_pointer, *input_line_pointer); + while ( input_line_pointer < buffer_limit + && ! is_end_of_line [* input_line_pointer] ) + { + input_line_pointer ++; + } + } + input_line_pointer ++; /* Return pointing just after end-of-line. */ + know( is_end_of_line [input_line_pointer [-1]] ); +} + +/* + * stab() + * + * Handle .stabX directives, which used to be open-coded. + * So much creeping featurism overloaded the semantics that we decided + * to put all .stabX thinking in one place. Here. + * + * We try to make any .stabX directive legal. Other people's AS will often + * do assembly-time consistency checks: eg assigning meaning to n_type bits + * and "protecting" you from setting them to certain values. (They also zero + * certain bits before emitting symbols. Tut tut.) + * + * If an expression is not absolute we either gripe or use the relocation + * information. Other people's assemblers silently forget information they + * don't need and invent information they need that you didn't supply. + * + * .stabX directives always make a symbol table entry. It may be junk if + * the rest of your .stabX directive is malformed. + */ +static void +stab (what) +int what; +{ + register symbolS * symbolP; + register char * string; + int saved_type; + int length; + int goof; /* TRUE if we have aborted. */ + long int longint; + +/* + * Enter with input_line_pointer pointing past .stabX and any following + * whitespace. + */ + goof = FALSE; /* JF who forgot this?? */ + if (what == 's') { + string = demand_copy_C_string (& length); + SKIP_WHITESPACE(); + if (* input_line_pointer == ',') + input_line_pointer ++; + else { + as_warn( "I need a comma after symbol's name" ); + goof = TRUE; + } + } else + string = ""; + +/* + * Input_line_pointer->after ','. String -> symbol name. + */ + if (! goof) { + symbolP = symbol_new (string, 0,0,0,0,(struct frag *)0); + switch (what) { + case 'd': + symbolP->sy_name = NULL; /* .stabd feature. */ + symbolP->sy_value = obstack_next_free(& frags) - frag_now->fr_literal; + symbolP->sy_frag = frag_now; + break; + + case 'n': + symbolP->sy_frag = &zero_address_frag; + break; + + case 's': + symbolP->sy_frag = & zero_address_frag; + break; + + default: + BAD_CASE( what ); + break; + } + if (get_absolute_expression_and_terminator (& longint) == ',') + symbolP->sy_type = saved_type = longint; + else { + as_warn( "I want a comma after the n_type expression" ); + goof = TRUE; + input_line_pointer --; /* Backup over a non-',' char. */ + } + } + if (! goof) { + if (get_absolute_expression_and_terminator (& longint) == ',') + symbolP->sy_other = longint; + else { + as_warn( "I want a comma after the n_other expression" ); + goof = TRUE; + input_line_pointer --; /* Backup over a non-',' char. */ + } + } + if (! goof) { + symbolP->sy_desc = get_absolute_expression (); + if (what == 's' || what == 'n') { + if (* input_line_pointer != ',') { + as_warn( "I want a comma after the n_desc expression" ); + goof = TRUE; + } else { + input_line_pointer ++; + } + } + } + if ((! goof) && (what=='s' || what=='n')) { + pseudo_set (symbolP); + symbolP->sy_type = saved_type; + } + if (goof) + ignore_rest_of_line (); + else + demand_empty_rest_of_line (); +} + +/* + * pseudo_set() + * + * In: Pointer to a symbol. + * Input_line_pointer -> expression. + * + * Out: Input_line_pointer -> just after any whitespace after expression. + * Tried to set symbol to value of expression. + * Will change sy_type, sy_value, sy_frag; + * May set need_pass_2 == TRUE. + */ +static void +pseudo_set (symbolP) + symbolS * symbolP; +{ + expressionS exp; + register segT segment; + int ext; + + know( symbolP ); /* NULL pointer is logic error. */ + ext=(symbolP->sy_type&N_EXT); + if ((segment = expression( & exp )) == SEG_NONE) + { + as_warn( "Missing expression: absolute 0 assumed" ); + exp . X_seg = SEG_ABSOLUTE; + exp . X_add_number = 0; + } + switch (segment) + { + case SEG_BIG: + as_warn( "%s number illegal. Absolute 0 assumed.", + exp . X_add_number > 0 ? "Bignum" : "Floating-Point" ); + symbolP -> sy_type = N_ABS | ext; + symbolP -> sy_value = 0; + symbolP -> sy_frag = & zero_address_frag; + break; + + case SEG_NONE: + as_warn("No expression: Using absolute 0"); + symbolP -> sy_type = N_ABS | ext; + symbolP -> sy_value = 0; + symbolP -> sy_frag = & zero_address_frag; + break; + + case SEG_DIFFERENCE: + if (exp.X_add_symbol && exp.X_subtract_symbol + && (exp.X_add_symbol->sy_type & N_TYPE) + == (exp.X_subtract_symbol->sy_type & N_TYPE)) { + if(exp.X_add_symbol->sy_frag != exp.X_subtract_symbol->sy_frag) { + as_bad("Unknown expression: symbols %s and %s are in different frags.",exp.X_add_symbol->sy_name, exp.X_subtract_symbol->sy_name); + need_pass_2++; + } + exp.X_add_number+=exp.X_add_symbol->sy_value - exp.X_subtract_symbol->sy_value; + } else + as_warn( "Complex expression. Absolute segment assumed." ); + case SEG_ABSOLUTE: + symbolP -> sy_type = N_ABS | ext; + symbolP -> sy_value = exp . X_add_number; + symbolP -> sy_frag = & zero_address_frag; + break; + + case SEG_DATA: + case SEG_TEXT: + case SEG_BSS: + symbolP -> sy_type = seg_N_TYPE [(int) segment] | ext; + symbolP -> sy_value= exp . X_add_number + exp . X_add_symbol -> sy_value; + symbolP -> sy_frag = exp . X_add_symbol -> sy_frag; + break; + + case SEG_PASS1: /* Not an error. Just try another pass. */ + symbolP->sy_forward=exp.X_add_symbol; + as_warn("Unknown expression"); + know( need_pass_2 == TRUE ); + break; + + case SEG_UNKNOWN: + symbolP->sy_forward=exp.X_add_symbol; + /* as_warn("unknown symbol"); */ + /* need_pass_2 = TRUE; */ + break; + + default: + BAD_CASE( segment ); + break; + } +} + +/* + * stabs(file), stabf(func) and stabd(line) -- for the purpose of + * source file debugging of assembly files, generate file, + * function and line number stabs, respectively. + * These functions have corresponding functions named + * filestab(), funcstab() and linestab() in input-scrub.c, + * where logical files and logical line numbers are handled. + */ + +#include <stab.h> + +stabs(file) + char *file; +{ + /* .stabs "file",100,0,0,. */ + (void) symbol_new(file, + N_SO, + 0, + 0, + obstack_next_free(& frags) - frag_now->fr_literal, + frag_now); +} + +stabf(func) + char *func; +{ + symbolS *symbolP; + static int void_undefined = 1; + + /* crudely filter uninteresting labels: require an initial '_' */ + if (*func++ != '_') + return; + + /* assembly functions are assumed to have void type */ + if (void_undefined) + { + /* .stabs "void:t15=15",128,0,0,0 */ + (void) symbol_new("void:t1=1", + N_LSYM, + 0, + 0, + 0, + &zero_address_frag); + void_undefined = 0; + } + + /* .stabs "func:F1",36,0,0,. */ + symbolP = symbol_new((char *) 0, + N_FUN, + 0, + 0, + obstack_next_free(& frags) - frag_now->fr_literal, + frag_now); + obstack_grow(¬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; +{ + /* .stabd 68,0,line */ + (void) symbol_new((char *)0, + N_SLINE, + 0, + line, + obstack_next_free(& frags) - frag_now->fr_literal, + frag_now); +} + +/* + * cons() + * + * CONStruct more frag of .bytes, or .words etc. + * Should need_pass_2 be TRUE then emit no frag(s). + * This understands EXPRESSIONS, as opposed to big_cons(). + * + * Bug (?) + * + * This has a split personality. We use expression() to read the + * value. We can detect if the value won't fit in a byte or word. + * But we can't detect if expression() discarded significant digits + * in the case of a long. Not worth the crocks required to fix it. + */ +void +cons(nbytes) /* worker to do .byte etc statements */ + /* clobbers input_line_pointer, checks */ + /* end-of-line. */ + register int nbytes; /* 1=.byte, 2=.word, 4=.long */ +{ + register char c; + register long int mask; /* High-order bits we will left-truncate, */ + /* but includes sign bit also. */ + register long int get; /* what we get */ + register long int use; /* get after truncation. */ + register long int unmask; /* what bits we will store */ + register char * p; + register segT segment; + expressionS exp; +#ifdef NS32K + void fix_new_ns32k(); +#else + void fix_new(); +#endif + + /* + * Input_line_pointer -> 1st char after pseudo-op-code and could legally + * be a end-of-line. (Or, less legally an eof - which we cope with.) + */ + /* JF << of >= number of bits in the object is undefined. In particular + SPARC (Sun 4) has problems */ + if(nbytes>=sizeof(long int)) + mask = 0; + else + mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */ + unmask = ~ mask; /* Do store these bits. */ +#ifdef NEVER + "Do this mod if you want every overflow check to assume SIGNED 2's complement data."; + mask = ~ (unmask >> 1); /* Includes sign bit now. */ +#endif + /* + * The following awkward logic is to parse ZERO or more expressions, + * comma seperated. Recall an expression includes its leading & + * trailing blanks. We fake a leading ',' if there is (supposed to + * be) a 1st expression, and keep demanding 1 expression for each ','. + */ + if (is_it_end_of_statement()) + { + c = 0; /* Skip loop. */ + input_line_pointer ++; /* Matches end-of-loop 'correction'. */ + } + else + c = ','; /* Do loop. */ + while ( c == ',' ) + { + segment = expression( &exp ); /* At least scan over the expression. */ + if ( ! need_pass_2 ) + { /* Still worthwhile making frags. */ + + /* Don't call this if we are going to junk this pass anyway! */ + know( segment != SEG_PASS1 ); + + if ( segment == SEG_DIFFERENCE && exp . X_add_symbol == NULL ) + { + as_warn( "Subtracting symbol \"%s\"(segment\"%s\") is too hard. Absolute segment assumed.", + exp . X_subtract_symbol -> sy_name, + seg_name [(int) N_TYPE_seg [exp . X_subtract_symbol -> sy_type & N_TYPE]]); + segment = SEG_ABSOLUTE; + /* Leave exp . X_add_number alone. */ + } + p = frag_more (nbytes); + switch (segment) + { + case SEG_BIG: + as_warn( "%s number illegal. Absolute 0 assumed.", + exp . X_add_number > 0 ? "Bignum" : "Floating-Point"); + md_number_to_chars (p, (long)0, nbytes); + break; + + case SEG_NONE: + as_warn( "0 assumed for missing expression" ); + exp . X_add_number = 0; + know( exp . X_add_symbol == NULL ); + /* fall into SEG_ABSOLUTE */ + case SEG_ABSOLUTE: + get = exp . X_add_number; + use = get & unmask; + if ( (get & mask) && (get & mask) != mask ) + { /* Leading bits contain both 0s & 1s. */ + as_warn("Value x%x truncated to x%x.", get, use); + } + md_number_to_chars (p, use, nbytes); /* put bytes in right order. */ + break; + + case SEG_DIFFERENCE: +#ifndef WORKING_DOT_WORD + if(nbytes==2) { + struct broken_word *x; + + x=(struct broken_word *)xmalloc(sizeof(struct broken_word)); + x->next_broken_word=broken_words; + broken_words=x; + x->frag=frag_now; + x->word_goes_here=p; + x->dispfrag=0; + x->add=exp.X_add_symbol; + x->sub=exp.X_subtract_symbol; + x->addnum=exp.X_add_number; + x->added=0; + new_broken_words++; + break; + } + /* Else Fall through into. . . */ +#endif + case SEG_BSS: + case SEG_UNKNOWN: + case SEG_TEXT: + case SEG_DATA: +#if defined(SPARC) || defined(I860) + fix_new (frag_now, p - frag_now -> fr_literal, nbytes, + exp . X_add_symbol, exp . X_subtract_symbol, + exp . X_add_number, 0, RELOC_32); +#endif +#ifdef NS32K + fix_new_ns32k (frag_now, p - frag_now -> fr_literal, nbytes, + exp . X_add_symbol, exp . X_subtract_symbol, + exp . X_add_number, 0, 0, 2, 0, 0); +#endif +#if !defined(SPARC) && !defined(NS32K) && !defined(I860) + fix_new (frag_now, p - frag_now -> fr_literal, nbytes, + exp . X_add_symbol, exp . X_subtract_symbol, + exp . X_add_number, 0); +#endif + break; + + default: + BAD_CASE( segment ); + break; + } /* switch(segment) */ + } /* if(!need_pass_2) */ + c = * input_line_pointer ++; + } /* while(c==',') */ + input_line_pointer --; /* Put terminator back into stream. */ + demand_empty_rest_of_line(); +} /* cons() */ + +/* + * big_cons() + * + * CONStruct more frag(s) of .quads, or .octa etc. + * Makes 0 or more new frags. + * If need_pass_2 == TRUE, generate no frag. + * This understands only bignums, not expressions. Cons() understands + * expressions. + * + * Constants recognised are '0...'(octal) '0x...'(hex) '...'(decimal). + * + * This creates objects with struct obstack_control objs, destroying + * any context objs held about a partially completed object. Beware! + * + * + * I think it sucks to have 2 different types of integers, with 2 + * routines to read them, store them etc. + * It would be nicer to permit bignums in expressions and only + * complain if the result overflowed. However, due to "efficiency"... + */ +void +big_cons(nbytes) /* worker to do .quad etc statements */ + /* clobbers input_line_pointer, checks */ + /* end-of-line. */ + register int nbytes; /* 8=.quad 16=.octa ... */ +{ + register char c; /* input_line_pointer -> c. */ + register int radix; + register long int length; /* Number of chars in an object. */ + register int digit; /* Value of 1 digit. */ + register int carry; /* For multi-precision arithmetic. */ + register int work; /* For multi-precision arithmetic. */ + register char * p; /* For multi-precision arithmetic. */ + + extern char hex_value[]; /* In hex_value.c. */ + + /* + * The following awkward logic is to parse ZERO or more strings, + * comma seperated. Recall an expression includes its leading & + * trailing blanks. We fake a leading ',' if there is (supposed to + * be) a 1st expression, and keep demanding 1 expression for each ','. + */ + if (is_it_end_of_statement()) + { + c = 0; /* Skip loop. */ + } + else + { + c = ','; /* Do loop. */ + -- input_line_pointer; + } + while (c == ',') + { + ++ input_line_pointer; + SKIP_WHITESPACE(); + c = * input_line_pointer; + /* C contains 1st non-blank character of what we hope is a number. */ + if (c == '0') + { + c = * ++ input_line_pointer; + if (c == 'x' || c=='X') + { + c = * ++ input_line_pointer; + radix = 16; + } + else + { + radix = 8; + } + } + else + { + radix = 10; + } + /* + * This feature (?) is here to stop people worrying about + * mysterious zero constants: which is what they get when + * they completely omit digits. + */ + if (hex_value[c] >= radix) + { + as_warn( "Missing digits. 0 assumed." ); + } + bignum_high = bignum_low - 1; /* Start constant with 0 chars. */ + for( ; (digit = hex_value [c]) < radix; c = * ++ input_line_pointer) + { + /* Multiply existing number by radix, then add digit. */ + carry = digit; + for (p=bignum_low; p <= bignum_high; p++) + { + work = (*p & MASK_CHAR) * radix + carry; + *p = work & MASK_CHAR; + carry = work >> BITS_PER_CHAR; + } + if (carry) + { + grow_bignum(); + * bignum_high = carry & MASK_CHAR; + know( (carry & ~ MASK_CHAR) == 0); + } + } + length = bignum_high - bignum_low + 1; + if (length > nbytes) + { + as_warn( "Most significant bits truncated in integer constant." ); + } + else + { + register long int leading_zeroes; + + for(leading_zeroes = nbytes - length; + leading_zeroes; + leading_zeroes --) + { + grow_bignum(); + * bignum_high = 0; + } + } + if (! need_pass_2) + { + p = frag_more (nbytes); + bcopy (bignum_low, p, (int)nbytes); + } + /* C contains character after number. */ + SKIP_WHITESPACE(); + c = * input_line_pointer; + /* C contains 1st non-blank character after number. */ + } + demand_empty_rest_of_line(); +} /* big_cons() */ + +static void +grow_bignum() /* Extend bignum by 1 char. */ +{ + register long int length; + + bignum_high ++; + if (bignum_high >= bignum_limit) + { + length = bignum_limit - bignum_low; + bignum_low = xrealloc (bignum_low, length + length); + bignum_high = bignum_low + length; + bignum_limit = bignum_low + length + length; + } +} /* grow_bignum(); */ + +/* + * float_cons() + * + * CONStruct some more frag chars of .floats .ffloats etc. + * Makes 0 or more new frags. + * If need_pass_2 == TRUE, no frags are emitted. + * This understands only floating literals, not expressions. Sorry. + * + * A floating constant is defined by atof_generic(), except it is preceded + * by 0d 0f 0g or 0h. After observing the STRANGE way my BSD AS does its + * reading, I decided to be incompatible. This always tries to give you + * rounded bits to the precision of the pseudo-op. Former AS did premature + * truncatation, restored noisy bits instead of trailing 0s AND gave you + * a choice of 2 flavours of noise according to which of 2 floating-point + * scanners you directed AS to use. + * + * In: input_line_pointer -> whitespace before, or '0' of flonum. + * + */ + +void /* JF was static, but can't be if VAX.C is goning to use it */ +float_cons(float_type) /* Worker to do .float etc statements. */ + /* Clobbers input_line-pointer, checks end-of-line. */ + register float_type; /* 'f':.ffloat ... 'F':.float ... */ +{ + register char * p; + register char c; + int length; /* Number of chars in an object. */ + register char * err; /* Error from scanning floating literal. */ + char temp [MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT]; + + /* + * The following awkward logic is to parse ZERO or more strings, + * comma seperated. Recall an expression includes its leading & + * trailing blanks. We fake a leading ',' if there is (supposed to + * be) a 1st expression, and keep demanding 1 expression for each ','. + */ + if (is_it_end_of_statement()) + { + c = 0; /* Skip loop. */ + ++ input_line_pointer; /* -> past termintor. */ + } + else + { + c = ','; /* Do loop. */ + } + while (c == ',') + { + /* input_line_pointer -> 1st char of a flonum (we hope!). */ + SKIP_WHITESPACE(); + /* Skip any 0{letter} that may be present. Don't even check if the + * letter is legal. Someone may invent a "z" format and this routine + * has no use for such information. Lusers beware: you get + * diagnostics if your input is ill-conditioned. + */ + + if(input_line_pointer[0]=='0' && isalpha(input_line_pointer[1])) + input_line_pointer+=2; + + err = md_atof (float_type, temp, &length); + know( length <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT); + know( length > 0 ); + if (* err) + { + as_warn( "Bad floating literal: %s", err); + ignore_rest_of_line(); + /* Input_line_pointer -> just after end-of-line. */ + c = 0; /* Break out of loop. */ + } + else + { + if ( ! need_pass_2) + { + p = frag_more (length); + bcopy (temp, p, length); + } + SKIP_WHITESPACE(); + c = * input_line_pointer ++; + /* C contains 1st non-white character after number. */ + /* input_line_pointer -> just after terminator (c). */ + } + } + -- input_line_pointer; /* -> terminator (is not ','). */ + demand_empty_rest_of_line(); +} /* float_cons() */ + +/* + * stringer() + * + * We read 0 or more ',' seperated, double-quoted strings. + * + * Caller should have checked need_pass_2 is FALSE because we don't check it. + */ +static void +stringer(append_zero) /* Worker to do .ascii etc statements. */ + /* Checks end-of-line. */ + register int append_zero; /* 0: don't append '\0', else 1 */ +{ + /* register char * p; JF unused */ + /* register int length; JF unused */ /* Length of string we read, excluding */ + /* trailing '\0' implied by closing quote. */ + /* register char * where; JF unused */ + /* register fragS * fragP; JF unused */ + register int c; + + /* + * The following awkward logic is to parse ZERO or more strings, + * comma seperated. Recall a string expression includes spaces + * before the opening '\"' and spaces after the closing '\"'. + * We fake a leading ',' if there is (supposed to be) + * a 1st, expression. We keep demanding expressions for each + * ','. + */ + if (is_it_end_of_statement()) + { + c = 0; /* Skip loop. */ + ++ input_line_pointer; /* Compensate for end of loop. */ + } + else + { + c = ','; /* Do loop. */ + } + for ( ; c == ','; c = *input_line_pointer ++) + { + SKIP_WHITESPACE(); + if (* input_line_pointer == '\"') + { + ++ input_line_pointer; /* -> 1st char of string. */ + while ( (c = next_char_of_string()) >= 0) + { + FRAG_APPEND_1_CHAR( c ); + } + if (append_zero) + { + FRAG_APPEND_1_CHAR( 0 ); + } + know( input_line_pointer [-1] == '\"' ); + } + else + { + as_warn( "Expected \"-ed string" ); + } + SKIP_WHITESPACE(); + } + -- input_line_pointer; + demand_empty_rest_of_line(); +} /* stringer() */ + +static int +next_char_of_string () +{ + register int c; + + c = * input_line_pointer ++; + switch (c) + { + case '\"': + c = -1; + break; + + case '\\': + switch (c = * input_line_pointer ++) + { + case 'b': + c = '\b'; + break; + + case 'f': + c = '\f'; + break; + + case 'n': + c = '\n'; + break; + + case 'r': + c = '\r'; + break; + + case 't': + c = '\t'; + break; + + case '\\': + case '"': + break; /* As itself. */ + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + long int number; + + for (number = 0; isdigit(c); c = * input_line_pointer ++) + { + number = number * 8 + c - '0'; + } + c = number; + } + -- input_line_pointer; + break; + + case '\n': +/* as_fatal( "Unterminated string - use app!" ); */ +/* To be compatible with BSD 4.2 as: give the luser a linefeed!! */ + c = '\n'; + break; + + default: + as_warn( "Bad escaped character in string, '?' assumed" ); + c = '?'; + break; + } + break; + + default: + break; + } + return (c); +} + +static segT +get_segmented_expression ( expP ) + register expressionS * expP; +{ + register segT retval; + + if ( (retval = expression( expP )) == SEG_PASS1 || retval == SEG_NONE || retval == SEG_BIG ) + { + as_warn("Expected address expression: absolute 0 assumed"); + retval = expP -> X_seg = SEG_ABSOLUTE; + expP -> X_add_number = 0; + expP -> X_add_symbol = expP -> X_subtract_symbol = 0; + } + return (retval); /* SEG_ ABSOLUTE,UNKNOWN,DATA,TEXT,BSS */ +} + +static segT +get_known_segmented_expression ( expP ) + register expressionS * expP; +{ + register segT retval; + register char * name1; + register char * name2; + + if ( (retval = get_segmented_expression (expP)) == SEG_UNKNOWN + ) + { + name1 = expP -> X_add_symbol ? expP -> X_add_symbol -> sy_name : ""; + name2 = expP -> X_subtract_symbol ? expP -> X_subtract_symbol -> sy_name : ""; + if ( name1 && name2 ) + { + as_warn("Symbols \"%s\" \"%s\" are undefined: absolute 0 assumed.", + name1, name2); + } + else + { + as_warn("Symbol \"%s\" undefined: absolute 0 assumed.", + name1 ? name1 : name2); + } + retval = expP -> X_seg = SEG_ABSOLUTE; + expP -> X_add_number = 0; + expP -> X_add_symbol = expP -> X_subtract_symbol = NULL; + } + know( retval == SEG_ABSOLUTE || retval == SEG_DATA || retval == SEG_TEXT || retval == SEG_BSS || retval == SEG_DIFFERENCE ); + return (retval); +} /* get_known_segmented_expression() */ + + + +/* static */ long int /* JF was static, but can't be if the MD pseudos are to use it */ +get_absolute_expression () +{ + expressionS exp; + register segT s; + + if ( (s = expression(& exp)) != SEG_ABSOLUTE ) + { + if ( s != SEG_NONE ) + { + as_warn( "Bad Absolute Expression, absolute 0 assumed."); + } + exp . X_add_number = 0; + } + return (exp . X_add_number); +} + +static char /* return terminator */ +get_absolute_expression_and_terminator( val_pointer) + long int * val_pointer; /* return value of expression */ +{ + * val_pointer = get_absolute_expression (); + return ( * input_line_pointer ++ ); +} + +/* + * demand_copy_C_string() + * + * Like demand_copy_string, but return NULL if the string contains any '\0's. + * Give a warning if that happens. + */ +static char * +demand_copy_C_string (len_pointer) + int * len_pointer; +{ + register char * s; + + if (s = demand_copy_string (len_pointer)) + { + register int len; + + for (len = * len_pointer; + len > 0; + len--) + { + if (* s == 0) + { + s = 0; + len = 1; + * len_pointer = 0; + as_warn( "This string may not contain \'\\0\'" ); + } + } + } + return (s); +} + +/* + * demand_copy_string() + * + * Demand string, but return a safe (=private) copy of the string. + * Return NULL if we can't read a string here. + */ +static char * +demand_copy_string (lenP) + int * lenP; +{ + register int c; + register int len; + char * retval; + + len = 0; + SKIP_WHITESPACE(); + if (* input_line_pointer == '\"') + { + input_line_pointer ++; /* Skip opening quote. */ + while ( (c = next_char_of_string()) >= 0 ) { + obstack_1grow ( ¬es, c ); + len ++; + } + /* JF this next line is so demand_copy_C_string will return a null + termanated string. */ + obstack_1grow(¬es,'\0'); + retval=obstack_finish( ¬es); + } else { + as_warn( "Missing string" ); + retval = NULL; + ignore_rest_of_line (); + } + * lenP = len; + return (retval); +} + +/* + * is_it_end_of_statement() + * + * In: Input_line_pointer -> next character. + * + * Do: Skip input_line_pointer over all whitespace. + * + * Out: TRUE if input_line_pointer -> end-of-line. + */ +static int +is_it_end_of_statement() +{ + SKIP_WHITESPACE(); + return (is_end_of_line [* input_line_pointer]); +} + +void +equals(sym_name) +char *sym_name; +{ + register struct symbol * symbolP; /* symbol we are working with */ + + input_line_pointer++; + if(*input_line_pointer=='=') + input_line_pointer++; + + while(*input_line_pointer==' ' || *input_line_pointer=='\t') + input_line_pointer++; + + if(sym_name[0]=='.' && sym_name[1]=='\0') { + /* Turn '. = mumble' into a .org mumble */ + register segT segment; + expressionS exp; + register char *p; + + segment = get_known_segmented_expression(& exp); + if ( ! need_pass_2 ) { + if (segment != now_seg && segment != SEG_ABSOLUTE) + as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.", + seg_name [(int) segment], seg_name [(int) now_seg]); + p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol, + exp.X_add_number, (char *)0); + * p = 0; + } /* if (ok to make frag) */ + } else { + symbolP=symbol_find_or_make(sym_name); + pseudo_set(symbolP); + } +} + +/* end: read.c */ diff --git a/gnu/usr.bin/as/read.h b/gnu/usr.bin/as/read.h new file mode 100644 index 0000000..6b46e8f --- /dev/null +++ b/gnu/usr.bin/as/read.h @@ -0,0 +1,47 @@ +/* read.h - of read.c + Copyright (C) 1986 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern char * input_line_pointer; /* -> char we are parsing now. */ + +#define PERMIT_WHITESPACE /* Define to make whitespace be allowed in */ + /* many syntactically unnecessary places. */ + /* Normally undefined. For compatibility */ + /* with ancient GNU cc. */ +#undef PERMIT_WHITESPACE + +#ifdef PERMIT_WHITESPACE +#define SKIP_WHITESPACE() {if (* input_line_pointer == ' ') ++ input_line_pointer;} +#else +#define SKIP_WHITESPACE() ASSERT( * input_line_pointer != ' ' ) +#endif + + +#define LEX_NAME (1) /* may continue a name */ +#define LEX_BEGIN_NAME (2) /* may begin a name */ + +#define is_name_beginner(c) ( lex_type[c] & LEX_BEGIN_NAME ) +#define is_part_of_name(c) ( lex_type[c] & LEX_NAME ) + +extern const char lex_type[]; + +void read_begin(); +void read_end(); +void read_a_source_file(); + +/* end: read.h */ diff --git a/gnu/usr.bin/as/struc-symbol.h b/gnu/usr.bin/as/struc-symbol.h new file mode 100644 index 0000000..11eab6b --- /dev/null +++ b/gnu/usr.bin/as/struc-symbol.h @@ -0,0 +1,72 @@ +/* struct_symbol.h - Internal symbol structure + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef VMS +#include "a.out.gnu.h" /* Needed to define struct nlist. Sigh. */ +#else +#include "a_out.h" +#endif + +struct symbol /* our version of an nlist node */ +{ + struct nlist sy_nlist; /* what we write in .o file (if permitted) */ + long unsigned sy_name_offset; /* 4-origin position of sy_name in symbols */ + /* part of object file. */ + /* 0 for (nameless) .stabd symbols. */ + /* Not used until write_object_file() time. */ + long int sy_number; /* 24 bit symbol number. */ + /* Symbol numbers start at 0 and are */ + /* unsigned. */ + struct symbol * sy_next; /* forward chain, or NULL */ + struct frag * sy_frag; /* NULL or -> frag this symbol attaches to. */ + struct symbol *sy_forward; /* value is really that of this other symbol */ +}; + +typedef struct symbol symbolS; + +#define sy_name sy_nlist .n_un. n_name + /* Name field always points to a string. */ + /* 0 means .stabd-like anonymous symbol. */ +#define sy_type sy_nlist. n_type +#define sy_other sy_nlist. n_other +#define sy_desc sy_nlist. n_desc +#define sy_value sy_nlist. n_value + /* Value of symbol is this value + object */ + /* file address of sy_frag. */ + +typedef unsigned valueT; /* The type of n_value. Helps casting. */ + +/* end: struct_symbol.h */ +#ifndef WORKING_DOT_WORD +struct broken_word { + struct broken_word *next_broken_word;/* One of these strucs per .word x-y */ + fragS *frag; /* Which frag its in */ + char *word_goes_here;/* Where in the frag it is */ + fragS *dispfrag; /* where to add the break */ + symbolS *add; /* symbol_x */ + symbolS *sub; /* - symbol_y */ + long addnum; /* + addnum */ + int added; /* nasty thing happend yet? */ + /* 1: added and has a long-jump */ + /* 2: added but uses someone elses long-jump */ + struct broken_word *use_jump; /* points to broken_word with a similar + long-jump */ +}; +extern struct broken_word *broken_words; +#endif diff --git a/gnu/usr.bin/as/subsegs.c b/gnu/usr.bin/as/subsegs.c new file mode 100644 index 0000000..c9eea3d --- /dev/null +++ b/gnu/usr.bin/as/subsegs.c @@ -0,0 +1,292 @@ +/* subsegs.c - subsegments - + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Segments & sub-segments. + */ + +#include "as.h" +#include "subsegs.h" +#include "obstack.h" +#include "frags.h" +#include "struc-symbol.h" +#include "write.h" + +frchainS* frchain_root, + * frchain_now, /* Commented in "subsegs.h". */ + * data0_frchainP; + + +const int /* in: segT out: N_TYPE bits */ +seg_N_TYPE[] = { + N_ABS, + N_TEXT, + N_DATA, + N_BSS, + N_UNDF, + N_UNDF, + N_UNDF, + N_UNDF, + N_UNDF, + N_UNDF +}; + + +char * const /* in: segT out: char* */ +seg_name[] = { + "absolute", + "text", + "data", + "bss", + "unknown", + "absent", + "pass1", + "ASSEMBLER-INTERNAL-LOGIC-ERROR!", + "bignum/flonum", + "difference", + "" + }; /* Used by error reporters, dumpers etc. */ + +const segT N_TYPE_seg [N_TYPE+2] = /* N_TYPE == 0x1E = 32-2 */ +{ + SEG_UNKNOWN, /* N_UNDF == 0 */ + SEG_GOOF, + SEG_ABSOLUTE, /* N_ABS == 2 */ + SEG_GOOF, + SEG_TEXT, /* N_TEXT == 4 */ + SEG_GOOF, + SEG_DATA, /* N_DATA == 6 */ + SEG_GOOF, + SEG_BSS, /* N_BSS == 8 */ + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF +}; + +void +subsegs_begin() +{ + /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */ + know( SEG_ABSOLUTE ==0 ); + know( SEG_TEXT ==1 ); + know( SEG_DATA ==2 ); + know( SEG_BSS ==3 ); + know( SEG_UNKNOWN ==4 ); + know( SEG_NONE ==5 ); + know( SEG_PASS1 ==6 ); + know( SEG_GOOF ==7 ); + know( SEG_BIG ==8 ); + know( SEG_DIFFERENCE ==9 ); + know( SEG_MAXIMUM_ORDINAL == SEG_DIFFERENCE ); + know( seg_name [(int) SEG_MAXIMUM_ORDINAL + 1] [0] == 0 ); + + obstack_begin( &frags, 5000); + frchain_root = NULL; + frchain_now = NULL; /* Warn new_subseg() that we are booting. */ + /* Fake up 1st frag. */ + /* It won't be used=> is ok if obstack... */ + /* pads the end of it for alignment. */ + frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG); + /* obstack_1blank( &frags, SIZEOF_STRUCT_FRAG, & frag_now ); */ + /* This 1st frag will not be in any frchain. */ + /* We simply give subseg_new somewhere to scribble. */ + now_subseg = 42; /* Lie for 1st call to subseg_new. */ + subseg_new (SEG_DATA, 0); /* .data 0 */ + data0_frchainP = frchain_now; +} + +/* + * subseg_change() + * + * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the + * subsegment. If we are already in the correct subsegment, change nothing. + * This is used eg as a worker for subseg_new [which does make a new frag_now] + * and for changing segments after we have read the source. We construct eg + * fixSs even after the source file is read, so we do have to keep the + * segment context correct. + */ +void +subseg_change (seg, subseg) + register segT seg; + register int subseg; +{ + now_seg = seg; + now_subseg = subseg; + if (seg == SEG_DATA) + { + seg_fix_rootP = & data_fix_root; + } + else + { + know (seg == SEG_TEXT); + seg_fix_rootP = & text_fix_root; + } +} + +/* + * subseg_new() + * + * If you attempt to change to the current subsegment, nothing happens. + * + * In: segT, subsegT code for new subsegment. + * frag_now -> incomplete frag for current subsegment. + * If frag_now==NULL, then there is no old, incomplete frag, so + * the old frag is not closed off. + * + * Out: now_subseg, now_seg updated. + * Frchain_now points to the (possibly new) struct frchain for this + * sub-segment. + * Frchain_root updated if needed. + */ + +void +subseg_new (seg, subseg) /* begin assembly for a new sub-segment */ + register segT seg; /* SEG_DATA or SEG_TEXT */ + register subsegT subseg; +{ + long tmp; /* JF for obstack alignment hacking */ + + know( seg == SEG_DATA || seg == SEG_TEXT ); + + if (seg != now_seg || subseg != now_subseg) + { /* we just changed sub-segments */ + register frchainS * frcP; /* crawl frchain chain */ + register frchainS** lastPP; /* address of last pointer */ + frchainS * newP; /* address of new frchain */ + register fragS * former_last_fragP; + register fragS * new_fragP; + + if (frag_now) /* If not bootstrapping. */ + { + frag_now -> fr_fix = obstack_next_free(& frags) - frag_now -> fr_literal; + frag_wane(frag_now); /* Close off any frag in old subseg. */ + } +/* + * It would be nice to keep an obstack for each subsegment, if we swap + * subsegments a lot. Hence we would have much fewer frag_wanes(). + */ + { + + obstack_finish( &frags); + /* + * If we don't do the above, the next object we put on obstack frags + * will appear to start at the fr_literal of the current frag. + * Also, above ensures that the next object will begin on a + * address that is aligned correctly for the engine that runs + * this program. + */ + } + subseg_change (seg, (int)subseg); + /* + * Attempt to find or make a frchain for that sub seg. + * Crawl along chain of frchainSs, begins @ frchain_root. + * If we need to make a frchainS, link it into correct + * position of chain rooted in frchain_root. + */ + for (frcP = * (lastPP = & frchain_root); + frcP + && (int)(frcP -> frch_seg) <= (int)seg; + frcP = * ( lastPP = & frcP -> frch_next) + ) + { + if ( (int)(frcP -> frch_seg) == (int)seg + && frcP -> frch_subseg >= subseg) + { + break; + } + } + /* + * frcP: Address of the 1st frchainS in correct segment with + * frch_subseg >= subseg. + * We want to either use this frchainS, or we want + * to insert a new frchainS just before it. + * + * If frcP==NULL, then we are at the end of the chain + * of frchainS-s. A NULL frcP means we fell off the end + * of the chain looking for a + * frch_subseg >= subseg, so we + * must make a new frchainS. + * + * If we ever maintain a pointer to + * the last frchainS in the chain, we change that pointer + * ONLY when frcP==NULL. + * + * lastPP: Address of the pointer with value frcP; + * Never NULL. + * May point to frchain_root. + * + */ + if ( ! frcP + || ( (int)(frcP -> frch_seg) > (int)seg + || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */ + { + /* + * This should be the only code that creates a frchainS. + */ + newP=(frchainS *)obstack_alloc(&frags,sizeof(frchainS)); + /* obstack_1blank( &frags, sizeof(frchainS), &newP); */ + /* This begines on a good boundary */ + /* because a obstack_done() preceeded it. */ + /* It implies an obstack_done(), so we */ + /* expect the next object allocated to */ + /* begin on a correct boundary. */ + *lastPP = newP; + newP -> frch_next = frcP; /* perhaps NULL */ + (frcP = newP) -> frch_subseg = subseg; + newP -> frch_seg = seg; + newP -> frch_last = NULL; + } + /* + * Here with frcP ->ing to the frchainS for subseg. + */ + frchain_now = frcP; + /* + * Make a fresh frag for the subsegment. + */ + /* We expect this to happen on a correct */ + /* boundary since it was proceeded by a */ + /* obstack_done(). */ + tmp=obstack_alignment_mask(&frags); /* JF disable alignment */ + obstack_alignment_mask(&frags)=0; + frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG); + obstack_alignment_mask(&frags)=tmp; + /* know( frags . obstack_c_next_free == frag_now -> fr_literal ); */ + /* But we want any more chars to come */ + /* immediately after the structure we just made. */ + new_fragP = frag_now; + new_fragP -> fr_next = NULL; + /* + * Append new frag to current frchain. + */ + former_last_fragP = frcP -> frch_last; + if (former_last_fragP) + { + know( former_last_fragP -> fr_next == NULL ); + know( frchain_now -> frch_root ); + former_last_fragP -> fr_next = new_fragP; + } + else + { + frcP -> frch_root = new_fragP; + } + frcP -> frch_last = new_fragP; + } /* if (changing subsegments) */ +} /* subseg_new() */ + +/* end: subsegs.c */ diff --git a/gnu/usr.bin/as/subsegs.h b/gnu/usr.bin/as/subsegs.h new file mode 100644 index 0000000..b8dbaf7 --- /dev/null +++ b/gnu/usr.bin/as/subsegs.h @@ -0,0 +1,65 @@ +/* subsegs.h -> subsegs.c + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * For every sub-segment the user mentions in the ASsembler program, + * we make one struct frchain. Each sub-segment has exactly one struct frchain + * and vice versa. + * + * Struct frchain's are forward chained (in ascending order of sub-segment + * code number). The chain runs through frch_next of each subsegment. + * This makes it hard to find a subsegment's frags + * if programmer uses a lot of them. Most programs only use text0 and + * data0, so they don't suffer. At least this way: + * (1) There are no "arbitrary" restrictions on how many subsegments + * can be programmed; + * (2) Subsegments' frchain-s are (later) chained together in the order in + * which they are emitted for object file viz text then data. + * + * From each struct frchain dangles a chain of struct frags. The frags + * represent code fragments, for that sub-segment, forward chained. + */ + +struct frchain /* control building of a frag chain */ +{ /* FRCH = FRagment CHain control */ + struct frag * frch_root; /* 1st struct frag in chain, or NULL */ + struct frag * frch_last; /* last struct frag in chain, or NULL */ + struct frchain * frch_next; /* next in chain of struct frchain-s */ + segT frch_seg; /* SEG_TEXT or SEG_DATA. */ + subsegT frch_subseg; /* subsegment number of this chain */ +}; + +typedef struct frchain frchainS; + +extern frchainS * frchain_root; /* NULL means no frchains yet. */ + /* all subsegments' chains hang off here */ + +extern frchainS * frchain_now; + /* Frchain we are assembling into now */ + /* That is, the current segment's frag */ + /* chain, even if it contains no (complete) */ + /* frags. */ + +extern frchainS * data0_frchainP; + /* Sentinel for frchain crawling. */ + /* Points to the 1st data-segment frchain. */ + /* (Which is pointed to by the last text- */ + /* segment frchain.) */ + +/* end: subsegs.h */ diff --git a/gnu/usr.bin/as/symbols.c b/gnu/usr.bin/as/symbols.c new file mode 100644 index 0000000..ce7197a --- /dev/null +++ b/gnu/usr.bin/as/symbols.c @@ -0,0 +1,438 @@ +/* symbols.c -symbol table- + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "as.h" +#include "hash.h" +#include "obstack.h" /* For "symbols.h" */ +#include "struc-symbol.h" +#include "symbols.h" +#include "frags.h" + +#ifndef WORKING_DOT_WORD +extern int new_broken_words; +#endif +#ifdef VMS +extern char const_flag; +#endif + +static +struct hash_control * +sy_hash; /* symbol-name => struct symbol pointer */ + + /* Below are commented in "symbols.h". */ +unsigned int local_bss_counter; +symbolS * symbol_rootP; +symbolS * symbol_lastP; +symbolS abs_symbol; +struct obstack notes; + + + +symbolS * symbol_find(); /* Keep C compiler happy. */ + +/* + * Un*x idea of local labels. They are made by "n:" where n + * is any decimal digit. Refer to them with + * "nb" for previous (backward) n: + * or "nf" for next (forward) n:. + * + * Like Un*x AS, we have one set of local label counters for entire assembly, + * not one set per (sub)segment like in most assemblers. This implies that + * one can refer to a label in another segment, and indeed some crufty + * compilers have done just that. + * + * I document the symbol names here to save duplicating words elsewhere. + * The mth occurence of label n: is turned into the symbol "Ln^Am" where + * n is a digit and m is a decimal number. "L" makes it a label discarded + * unless debugging and "^A"('\1') ensures no ordinary symbol SHOULD get the + * same name as a local label symbol. The first "4:" is "L4^A1" - the m + * numbers begin at 1. + */ + +typedef short unsigned int +local_label_countT; + +static local_label_countT +local_label_counter[10]; + +static /* Returned to caller, then copied. */ + char symbol_name_build[12]; /* used for created names ("4f") */ + +#ifdef SUN_ASM_SYNTAX +int local_label_defined[10]; +#endif + + +void +symbol_begin() +{ + symbol_lastP = NULL; + symbol_rootP = NULL; /* In case we have 0 symbols (!!) */ + sy_hash = hash_new(); + bzero ((char *)(& abs_symbol), sizeof(abs_symbol)); + abs_symbol . sy_type = N_ABS; /* Can't initialise a union. Sigh. */ + bzero ((char *)(local_label_counter), sizeof(local_label_counter) ); + local_bss_counter = 0; +} + +/* + * local_label_name() + * + * Caller must copy returned name: we re-use the area for the next name. + */ + +char * /* Return local label name. */ +local_label_name(n, augend) + register int n; /* we just saw "n:", "nf" or "nb" : n a digit */ + register int augend; /* 0 for nb, 1 for n:, nf */ +{ + register char * p; + register char * q; + char symbol_name_temporary[10]; /* build up a number, BACKWARDS */ + + know( n >= 0 ); + know( augend == 0 || augend == 1 ); + p = symbol_name_build; + * p ++ = 'L'; + * p ++ = n + '0'; /* Make into ASCII */ + * p ++ = 1; /* ^A */ + n = local_label_counter [ n ] + augend; + /* version number of this local label */ + /* + * Next code just does sprintf( {}, "%d", n); + * It is more elegant to do the next part recursively, but a procedure + * call for each digit emitted is considered too costly. + */ + q = symbol_name_temporary; + for (*q++=0; n; q++) /* emits NOTHING if n starts as 0 */ + { + know(n>0); /* We expect n > 0 always */ + *q = n % 10 + '0'; + n /= 10; + } + while ( * p ++ = * -- q ) + { + } + /* The label, as a '\0' ended string, starts at symbol_name_build. */ + return (symbol_name_build); +} + + +void +local_colon (n) + int n; /* just saw "n:" */ +{ + local_label_counter [n] ++; +#ifdef SUN_ASM_SYNTAX + local_label_defined[n]=1; +#endif + colon (local_label_name (n, 0)); +} + +/* + * symbol_new() + * + * Return a pointer to a new symbol. + * Die if we can't make a new symbol. + * Fill in the symbol's values. + * Add symbol to end of symbol chain. + * + * + * Please always call this to create a new symbol. + * + * Changes since 1985: Symbol names may not contain '\0'. Sigh. + */ + +symbolS * +symbol_new (name, type, other, desc, value, frag) + char * name; /* We copy this: OK to alter your copy. */ + unsigned char type; /* As in <a.out.h>. */ + char other; /* As in <a.out.h>. */ + short int desc; /* As in <a.out.h>. */ + valueT value; /* As in <a.out.h>, often an address. */ + /* Often used as offset from frag address. */ + struct frag * frag; /* For sy_frag. */ +{ + register symbolS * symbolP; + register char * preserved_copy_of_name; + register unsigned int name_length; + char * p; + + name_length = strlen(name) + 1; + obstack_grow(¬es,name,name_length); + p=obstack_finish(¬es); + /* obstack_1done( ¬es, name, name_length, &p ); */ + preserved_copy_of_name = p; + p=obstack_alloc(¬es,sizeof(struct symbol)); + /* obstack_1blank( ¬es, sizeof(struct symbol), &p ); */ + symbolP = (symbolS *) p; + symbolP -> sy_name = preserved_copy_of_name; + symbolP -> sy_type = type; + symbolP -> sy_other = other; + symbolP -> sy_desc = desc; + symbolP -> sy_value = value; + symbolP -> sy_frag = frag; + symbolP -> sy_next = NULL; /* End of chain. */ + symbolP -> sy_forward = NULL; /* JF */ +#ifdef SUSPECT + symbolP -> sy_name_offset = ~ 0; /* Impossible offset catches errors. */ + symbolP -> sy_number = ~ 0; /* Ditto. */ +#endif + /* + * Link to end of symbol chain. + */ + if (symbol_lastP) + { + symbol_lastP -> sy_next = symbolP; + } + else + { + symbol_rootP = symbolP; + } + symbol_lastP = symbolP; + + return (symbolP); +} + +/* + * colon() + * + * We have just seen "<name>:". + * Creates a struct symbol unless it already exists. + * + * Gripes if we are redefining a symbol incompatibly (and ignores it). + * + */ +void +colon (sym_name) /* just seen "x:" - rattle symbols & frags */ + register char * sym_name; /* symbol name, as a cannonical string */ + /* We copy this string: OK to alter later. */ +{ + register struct symbol * symbolP; /* symbol we are working with */ + +#ifdef SUN_ASM_SYNTAX + /* Sun local labes go out of scope whenever a non-local symbol is + defined. */ + + if(*sym_name !='L') + bzero((void *)local_label_defined,sizeof(local_label_defined)); +#endif + +#ifndef WORKING_DOT_WORD + if(new_broken_words) { + struct broken_word *a; + int possible_bytes; + fragS *frag_tmp; + char *frag_opcode; + extern md_short_jump_size; + extern md_long_jump_size; + + possible_bytes=md_short_jump_size+new_broken_words*md_long_jump_size; + frag_tmp=frag_now; + frag_opcode=frag_var(rs_broken_word,possible_bytes,possible_bytes,(relax_substateT)0,(symbolS *)broken_words,(long int)0,(char *)0); + + /* We want to store the pointer to where to insert the jump table in the + fr_opcode of the rs_broken_word frag. This requires a little hackery */ + while(frag_tmp && (frag_tmp->fr_type!=rs_broken_word || frag_tmp->fr_opcode)) + frag_tmp=frag_tmp->fr_next; + know(frag_tmp); + frag_tmp->fr_opcode=frag_opcode; + new_broken_words = 0; + + for(a=broken_words;a && a->dispfrag==0;a=a->next_broken_word) + a->dispfrag=frag_tmp; + } +#endif + if (symbolP = symbol_table_lookup( sym_name )) + { +#ifdef VMS + /* + * If the new symbol is .comm AND it has a size of zero, + * we ignore it (i.e. the old symbol overrides it) + */ + if ((seg_N_TYPE [(int) now_seg] == (N_UNDF | N_EXT)) && + ((obstack_next_free(& frags) - frag_now -> fr_literal) == 0)) + return; + /* + * If the old symbol is .comm and it has a size of zero, + * we override it with the new symbol value. + */ + if ((symbolP -> sy_type == (N_UNDF | N_EXT)) && + (symbolP->sy_value == 0)) { + symbolP -> sy_frag = frag_now; + symbolP -> sy_other = const_flag; + symbolP -> sy_value = obstack_next_free(& frags) - frag_now -> fr_literal; + symbolP -> sy_type |= seg_N_TYPE [(int) now_seg]; /* keep N_EXT bit */ + return; + } +#endif /* VMS */ + /* + * Now check for undefined symbols + */ + if ((symbolP -> sy_type & N_TYPE) == N_UNDF) + { + if( symbolP -> sy_other == 0 + && symbolP -> sy_desc == 0 + && symbolP -> sy_value == 0) + { + symbolP -> sy_frag = frag_now; +#ifdef VMS + symbolP -> sy_other = const_flag; +#endif + symbolP -> sy_value = obstack_next_free(& frags) - frag_now -> fr_literal; + know( N_UNDF == 0 ); + symbolP -> sy_type |= seg_N_TYPE [(int) now_seg]; /* keep N_EXT bit */ + } + else + { +#ifdef VMS + /* + * There are still several cases to check: + * A .comm/.lcomm symbol being redefined as + * initialized data is OK + * A .comm/.lcomm symbol being redefined with + * a larger size is also OK + */ + char New_Type = seg_N_TYPE [(int) now_seg]; + if (((symbolP->sy_type == (N_UNDF | N_EXT)) || + (symbolP->sy_type == N_BSS)) && + (((New_Type & ~N_EXT) == N_DATA) || + (New_Type == symbolP->sy_type))) { + /* + * Select which of the 2 cases this is + */ + if (New_Type == symbolP->sy_type) { + /* + * If the new size is larger we just + * change its value. If the new size + * is smaller, we ignore this symbol + */ + if (symbolP->sy_value < + (obstack_next_free(& frags) - + frag_now -> fr_literal)) { + symbolP -> sy_value = + obstack_next_free(& frags) - + frag_now -> fr_literal; + } + } else { + /* + * It is a .comm/.lcomm being converted + * to initialized data. + */ + symbolP -> sy_frag = frag_now; + symbolP -> sy_other = const_flag; + symbolP -> sy_value = obstack_next_free(& frags) - frag_now -> fr_literal; + symbolP -> sy_type |= seg_N_TYPE [(int) now_seg]; /* keep N_EXT bit */ + } + } else { +#endif /* VMS */ + as_fatal( "Symbol \"%s\" is already defined as \"%s\"/%d.%d.%d.", + sym_name, + seg_name [(int) N_TYPE_seg [symbolP -> sy_type & N_TYPE]], + symbolP -> sy_other, symbolP -> sy_desc, + symbolP -> sy_value); +#ifdef VMS + } +#endif /* VMS */ + } + } + else + { + as_fatal("Symbol %s already defined.",sym_name); + } + } + else + { + symbolP = symbol_new (sym_name, + (unsigned char)(seg_N_TYPE [(int) now_seg]), +#ifdef VMS + const_flag, +#else + 0, +#endif + 0, + (valueT)(obstack_next_free(&frags)-frag_now->fr_literal), + frag_now); + symbol_table_insert (symbolP); + } +} + + +/* + * symbol_table_insert() + * + * Die if we can't insert the symbol. + * + */ + +void +symbol_table_insert (symbolP) + struct symbol * symbolP; +{ + register char * error_string; + + know( symbolP ); + know( symbolP -> sy_name ); + if ( * (error_string = hash_jam (sy_hash, symbolP -> sy_name, (char *)symbolP))) + { + as_fatal( "Inserting \"%s\" into symbol table failed: %s", + symbolP -> sy_name, error_string); + } +} + +/* + * symbol_find_or_make() + * + * If a symbol name does not exist, create it as undefined, and insert + * it into the symbol table. Return a pointer to it. + */ +symbolS * +symbol_find_or_make (name) + char * name; +{ + register symbolS * symbolP; + + symbolP = symbol_table_lookup (name); + if (symbolP == NULL) + { + symbolP = symbol_new (name, N_UNDF, 0, 0, 0, & zero_address_frag); + symbol_table_insert (symbolP); + } + return (symbolP); +} + +/* + * symbol_find() + * + * Implement symbol table lookup. + * In: A symbol's name as a string: '\0' can't be part of a symbol name. + * Out: NULL if the name was not in the symbol table, else the address + * of a struct symbol associated with that name. + */ + +symbolS * +symbol_find (name) + char * name; +{ + return ( (symbolS *) hash_find( sy_hash, name )); +} + + +/* end: symbols.c */ diff --git a/gnu/usr.bin/as/symbols.h b/gnu/usr.bin/as/symbols.h new file mode 100644 index 0000000..5a52790 --- /dev/null +++ b/gnu/usr.bin/as/symbols.h @@ -0,0 +1,42 @@ +/* symbols.h - + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern struct obstack notes; /* eg FixS live here. */ + +#define symbol_table_lookup(name) ((symbolS *)(symbol_find (name))) + +extern unsigned int local_bss_counter; /* Zeroed before a pass. */ + /* Only used by .lcomm directive. */ + + +extern symbolS * symbol_rootP; /* all the symbol nodes */ +extern symbolS * symbol_lastP; /* last struct symbol we made, or NULL */ + +extern symbolS abs_symbol; + +symbolS * symbol_find(); +void symbol_begin(); +char * local_label_name(); +void local_colon(); +symbolS * symbol_new(); +void colon(); +void symbol_table_insert(); +symbolS * symbol_find_or_make(); + +/* end: symbols.h */ diff --git a/gnu/usr.bin/as/version.c b/gnu/usr.bin/as/version.c new file mode 100644 index 0000000..f94d3f4 --- /dev/null +++ b/gnu/usr.bin/as/version.c @@ -0,0 +1,23 @@ +#if defined(__STDC__) || defined(const) +const +#endif +char version_string[] = "GNU assembler version 1.38\n"; + +/* DO NOT PUT COMMENTS ABOUT CHANGES IN THIS FILE. + + This file exists only to define `version_string'. + + Log changes in ChangeLog. The easiest way to do this is with + the Emacs command `add-change-log-entry'. If you don't use Emacs, + add entries of the form: + +Thu Jan 1 00:00:00 1970 Dennis Ritchie (dmr at alice) + + * universe.c (temporal_reality): Began Time. +*/ + +#ifdef VMS +dummy3() +{ +} +#endif diff --git a/gnu/usr.bin/as/write.c b/gnu/usr.bin/as/write.c new file mode 100644 index 0000000..a850555 --- /dev/null +++ b/gnu/usr.bin/as/write.c @@ -0,0 +1,1259 @@ +/* write.c - emit .o file - Copyright(C)1986 Free Software Foundation, Inc. + Copyright (C) 1986,1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + + Umm, with real good luck, this thing should be set up to do byteordering + correctly, but I may have managed to miss a place or two. Treat a.out + very carefully until you're SURE that it works. . . + + In order to cross-assemble the target machine must have an a.out header + similar to the one in a.out.h on THIS machine. Byteorder doesn't matter; + we take special care of it, but the numbers must be the same SIZE (# of + bytes) and in the same PLACE. If this is not true, you will have some + trouble. + */ + +#include "as.h" +#include "md.h" +#include "subsegs.h" +#include "obstack.h" +#include "struc-symbol.h" +#include "write.h" +#include "symbols.h" + +#ifdef SPARC +#include "sparc.h" +#endif +#ifdef I860 +#include "i860.h" +#endif + +void append(); + +#ifdef hpux +#define EXEC_MACHINE_TYPE HP9000S200_ID +#endif + +#ifdef DOT_LABEL_PREFIX +#define LOCAL_LABEL(name) (name[0] =='.' \ + && ( name [1] == 'L' || name [1] == '.' )) +#else /* not defined DOT_LABEL_PREFIX */ +#define LOCAL_LABEL(name) (name [0] == 'L' ) +#endif /* not defined DOT_LABEL_PREFIX */ + +/* + * In: length of relocation (or of address) in chars: 1, 2 or 4. + * Out: GNU LD relocation length code: 0, 1, or 2. + */ + +static unsigned char + +nbytes_r_length [] = { + 42, 0, 1, 42, 2 + }; + + +static struct frag * text_frag_root; +static struct frag * data_frag_root; + +static struct frag * text_last_frag; /* Last frag in segment. */ +static struct frag * data_last_frag; /* Last frag in segment. */ + +static struct exec the_exec; + +static long int string_byte_count; + +static char * the_object_file; + +#if !defined(SPARC) && !defined(I860) +static +#endif +char * next_object_file_charP; /* Tracks object file bytes. */ + +static long int size_of_the_object_file; /* # bytes in object file. */ + +/* static long int length; JF unused */ /* String length, including trailing '\0'. */ + +static void relax_segment(); +void emit_segment(); +static relax_addressT relax_align(); +static long int fixup_segment(); +#if !defined(SPARC) && !defined(I860) +static void emit_relocations(); +#endif +/* + * fix_new() + * + * Create a fixS in obstack 'notes'. + */ +void +#if defined(SPARC) || defined(I860) +fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type) +#else +fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel) +#endif + fragS * frag; /* Which frag? */ + int where; /* Where in that frag? */ + short int size; /* 1, 2 or 4 usually. */ + symbolS * add_symbol; /* X_add_symbol. */ + symbolS * sub_symbol; /* X_subtract_symbol. */ + long int offset; /* X_add_number. */ + int pcrel; /* TRUE if PC-relative relocation. */ +#if defined(SPARC) || defined(I860) + int r_type; +#endif +{ + register fixS * fixP; + + fixP = (fixS *)obstack_alloc(¬es,sizeof(fixS)); + + fixP -> fx_frag = frag; + fixP -> fx_where = where; + fixP -> fx_size = size; + fixP -> fx_addsy = add_symbol; + fixP -> fx_subsy = sub_symbol; + fixP -> fx_offset = offset; + fixP -> fx_pcrel = pcrel; + fixP -> fx_next = * seg_fix_rootP; + + /* JF these 'cuz of the NS32K stuff */ + fixP -> fx_im_disp = 0; + fixP -> fx_pcrel_adjust = 0; + fixP -> fx_bsr = 0; + fixP ->fx_bit_fixP = 0; + +#if defined(SPARC) || defined(I860) + fixP->fx_r_type = r_type; +#endif + + * seg_fix_rootP = fixP; +} + +void +write_object_file() +{ + register struct frchain * frchainP; /* Track along all frchains. */ + register fragS * fragP; /* Track along all frags. */ + register struct frchain * next_frchainP; + register fragS * * prev_fragPP; + register char * name; + register symbolS * symbolP; + register symbolS ** symbolPP; + /* register fixS * fixP; JF unused */ + unsigned + text_siz, + data_siz, + syms_siz, + tr_siz, + dr_siz; + void output_file_create(); + void output_file_append(); + void output_file_close(); +#ifdef DONTDEF + void gdb_emit(); + void gdb_end(); +#endif + extern long omagic; /* JF magic # to write out. Is different for + Suns and Vaxen and other boxes */ + +#ifdef VMS + /* + * Under VMS we try to be compatible with VAX-11 "C". Thus, we + * call a routine to check for the definition of the procedure + * "_main", and if so -- fix it up so that it can be program + * entry point. + */ + VMS_Check_For_Main(); +#endif /* VMS */ + /* + * After every sub-segment, we fake an ".align ...". This conforms to BSD4.2 + * brane-damage. We then fake ".fill 0" because that is the kind of frag + * that requires least thought. ".align" frags like to have a following + * frag since that makes calculating their intended length trivial. + */ +#define SUB_SEGMENT_ALIGN (2) + for ( frchainP=frchain_root; frchainP; frchainP=frchainP->frch_next ) + { +#ifdef VMS + /* + * Under VAX/VMS, the linker (and PSECT specifications) + * take care of correctly aligning the segments. + * Doing the alignment here (on initialized data) can + * mess up the calculation of global data PSECT sizes. + */ +#undef SUB_SEGMENT_ALIGN +#define SUB_SEGMENT_ALIGN ((frchainP->frch_seg != SEG_DATA) ? 2 : 0) +#endif /* VMS */ + subseg_new (frchainP -> frch_seg, frchainP -> frch_subseg); + frag_align (SUB_SEGMENT_ALIGN, 0); + /* frag_align will have left a new frag. */ + /* Use this last frag for an empty ".fill". */ + /* + * For this segment ... + * Create a last frag. Do not leave a "being filled in frag". + */ + frag_wane (frag_now); + frag_now -> fr_fix = 0; + know( frag_now -> fr_next == NULL ); + /* know( frags . obstack_c_base == frags . obstack_c_next_free ); */ + /* Above shows we haven't left a half-completed object on obstack. */ + } + + /* + * From now on, we don't care about sub-segments. + * Build one frag chain for each segment. Linked thru fr_next. + * We know that there is at least 1 text frchain & at least 1 data frchain. + */ + prev_fragPP = &text_frag_root; + for ( frchainP=frchain_root; frchainP; frchainP=next_frchainP ) + { + know( frchainP -> frch_root ); + * prev_fragPP = frchainP -> frch_root; + prev_fragPP = & frchainP -> frch_last -> fr_next; + if ( ((next_frchainP = frchainP->frch_next) == NULL) + || next_frchainP == data0_frchainP) + { + prev_fragPP = & data_frag_root; + if ( next_frchainP ) + { + text_last_frag = frchainP -> frch_last; + } + else + { + data_last_frag = frchainP -> frch_last; + } + } + } /* for(each struct frchain) */ + + /* + * We have two segments. If user gave -R flag, then we must put the + * data frags into the text segment. Do this before relaxing so + * we know to take advantage of -R and make shorter addresses. + */ + if ( flagseen [ 'R' ] ) + { + fixS *tmp; + + text_last_frag -> fr_next = data_frag_root; + text_last_frag = data_last_frag; + data_last_frag = NULL; + data_frag_root = NULL; + if(text_fix_root) { + for(tmp=text_fix_root;tmp->fx_next;tmp=tmp->fx_next) + ; + tmp->fx_next=data_fix_root; + } else + text_fix_root=data_fix_root; + data_fix_root=NULL; + } + + relax_segment (text_frag_root, SEG_TEXT); + relax_segment (data_frag_root, SEG_DATA); + /* + * Now the addresses of frags are correct within the segment. + */ + + know( text_last_frag -> fr_type == rs_fill && text_last_frag -> fr_offset == 0 ); + text_siz=text_last_frag->fr_address; +#ifdef SPARC + text_siz= (text_siz+7)&(~7); + text_last_frag->fr_address=text_siz; +#endif + md_number_to_chars((char *)&the_exec.a_text,text_siz, sizeof(the_exec.a_text)); + /* the_exec . a_text = text_last_frag -> fr_address; */ + + /* + * Join the 2 segments into 1 huge segment. + * To do this, re-compute every rn_address in the SEG_DATA frags. + * Then join the data frags after the text frags. + * + * Determine a_data [length of data segment]. + */ + if (data_frag_root) + { + register relax_addressT slide; + + know( text_last_frag -> fr_type == rs_fill && text_last_frag -> fr_offset == 0 ); + data_siz=data_last_frag->fr_address; +#ifdef SPARC + data_siz += (8 - (data_siz % 8)) % 8; + data_last_frag->fr_address = data_siz; +#endif + md_number_to_chars((char *)&the_exec.a_data,data_siz,sizeof(the_exec.a_data)); + /* the_exec . a_data = data_last_frag -> fr_address; */ + slide = text_siz; /* Address in file of the data segment. */ + for (fragP = data_frag_root; + fragP; + fragP = fragP -> fr_next) + { + fragP -> fr_address += slide; + } + know( text_last_frag ); + text_last_frag -> fr_next = data_frag_root; + } + else { + md_number_to_chars((char *)&the_exec.a_data,0,sizeof(the_exec.a_data)); + data_siz = 0; + } + + bss_address_frag . fr_address = text_siz + data_siz; +#ifdef SPARC + local_bss_counter=(local_bss_counter+7)&(~7); +#endif + md_number_to_chars((char *)&the_exec.a_bss,local_bss_counter,sizeof(the_exec.a_bss)); + + + /* + * + * Crawl the symbol chain. + * + * For each symbol whose value depends on a frag, take the address of + * that frag and subsume it into the value of the symbol. + * After this, there is just one way to lookup a symbol value. + * Values are left in their final state for object file emission. + * We adjust the values of 'L' local symbols, even if we do + * not intend to emit them to the object file, because their values + * are needed for fix-ups. + * + * Unless we saw a -L flag, remove all symbols that begin with 'L' + * from the symbol chain. + * + * Count the (length of the nlists of the) (remaining) symbols. + * Assign a symbol number to each symbol. + * Count the number of string-table chars we will emit. + * + */ + know( zero_address_frag . fr_address == 0 ); + string_byte_count = sizeof( string_byte_count ); + + /* JF deal with forward references first. . . */ + for(symbolP=symbol_rootP;symbolP;symbolP=symbolP->sy_next) { + if(symbolP->sy_forward) { + symbolP->sy_value+=symbolP->sy_forward->sy_value+symbolP->sy_forward->sy_frag->fr_address; + symbolP->sy_forward=0; + } + } + symbolPP = & symbol_rootP; /* -> last symbol chain link. */ + { + register long int symbol_number; + + symbol_number = 0; + while (symbolP = * symbolPP) + { + name = symbolP -> sy_name; + if(flagseen['R'] && (symbolP->sy_nlist.n_type&N_DATA)) { + symbolP->sy_nlist.n_type&= ~N_DATA; + symbolP->sy_nlist.n_type|= N_TEXT; + } + /* if(symbolP->sy_forward) { + symbolP->sy_value += symbolP->sy_forward->sy_value + symbolP->sy_forward->sy_frag->fr_address; + } */ + + symbolP -> sy_value += symbolP -> sy_frag -> fr_address; + /* JF the 128 bit is a hack so stabs like + "LET_STMT:23. . ." don't go away */ + /* CPH: 128 bit hack is moby loser. N_SO for file "Lower.c" + fell through the cracks. I think that N_STAB should be + used instead of 128. */ + /* JF the \001 bit is to make sure that local labels + ( 1: - 9: don't make it into the symtable either */ +#ifndef VMS /* Under VMS we need to keep local symbols */ + if ( !name || (symbolP->sy_nlist.n_type&N_STAB) + || (name[2]!='\001' && (flagseen ['L'] || ! LOCAL_LABEL(name) ))) +#endif /* not VMS */ + { + symbolP -> sy_number = symbol_number ++; +#ifndef VMS + if (name) + { /* Ordinary case. */ + symbolP -> sy_name_offset = string_byte_count; + string_byte_count += strlen (symbolP -> sy_name) + 1; + } + else /* .Stabd case. */ +#endif /* not VMS */ + symbolP -> sy_name_offset = 0; + symbolPP = & (symbolP -> sy_next); + } +#ifndef VMS + else + * symbolPP = symbolP -> sy_next; +#endif /* not VMS */ + } /* for each symbol */ + + syms_siz = sizeof( struct nlist) * symbol_number; + md_number_to_chars((char *)&the_exec.a_syms,syms_siz,sizeof(the_exec.a_syms)); + /* the_exec . a_syms = sizeof( struct nlist) * symbol_number; */ + } + + /* + * Addresses of frags now reflect addresses we use in the object file. + * Symbol values are correct. + * Scan the frags, converting any ".org"s and ".align"s to ".fill"s. + * Also converting any machine-dependent frags using md_convert_frag(); + */ + subseg_change( SEG_TEXT, 0); + + for (fragP = text_frag_root; fragP; fragP = fragP -> fr_next) + { + switch (fragP -> fr_type) + { + case rs_align: + case rs_org: + fragP -> fr_type = rs_fill; + know( fragP -> fr_var == 1 ); + know( fragP -> fr_next ); + fragP -> fr_offset + = fragP -> fr_next -> fr_address + - fragP -> fr_address + - fragP -> fr_fix; + break; + + case rs_fill: + break; + + case rs_machine_dependent: + md_convert_frag (fragP); + /* + * After md_convert_frag, we make the frag into a ".space 0". + * Md_convert_frag() should set up any fixSs and constants + * required. + */ + frag_wane (fragP); + break; + +#ifndef WORKING_DOT_WORD + case rs_broken_word: + { + struct broken_word *lie; + extern md_short_jump_size; + extern md_long_jump_size; + + if(fragP->fr_subtype) { + fragP->fr_fix+=md_short_jump_size; + for(lie=(struct broken_word *)(fragP->fr_symbol);lie && lie->dispfrag==fragP;lie=lie->next_broken_word) + if(lie->added==1) + fragP->fr_fix+=md_long_jump_size; + } + frag_wane(fragP); + } + break; +#endif + + default: + BAD_CASE( fragP -> fr_type ); + break; + } /* switch (fr_type) */ + } /* for each frag. */ + +#ifndef WORKING_DOT_WORD + { + struct broken_word *lie; + struct broken_word **prevP; + + prevP= &broken_words; + for(lie=broken_words; lie; lie=lie->next_broken_word) + if(!lie->added) { +#if defined(SPARC) || defined(I860) + fix_new( lie->frag, lie->word_goes_here - lie->frag->fr_literal, + 2, lie->add, + lie->sub, lie->addnum, + 0, NO_RELOC); +#endif +#ifdef NS32K + fix_new_ns32k(lie->frag, + lie->word_goes_here - lie->frag->fr_literal, + 2, + lie->add, + lie->sub, + lie->addnum, + 0, 0, 2, 0, 0); +#endif +#if !defined(SPARC) && !defined(NS32K) && !defined(I860) + fix_new( lie->frag, lie->word_goes_here - lie->frag->fr_literal, + 2, lie->add, + lie->sub, lie->addnum, + 0); +#endif + /* md_number_to_chars(lie->word_goes_here, + lie->add->sy_value + + lie->addnum + - (lie->sub->sy_value), + 2); */ + *prevP=lie->next_broken_word; + } else + prevP= &(lie->next_broken_word); + + for(lie=broken_words;lie;) { + struct broken_word *untruth; + char *table_ptr; + long table_addr; + long from_addr, + to_addr; + int n, + m; + + extern md_short_jump_size; + extern md_long_jump_size; + void md_create_short_jump(); + void md_create_long_jump(); + + + + fragP=lie->dispfrag; + + /* Find out how many broken_words go here */ + n=0; + for(untruth=lie;untruth && untruth->dispfrag==fragP;untruth=untruth->next_broken_word) + if(untruth->added==1) + n++; + + table_ptr=lie->dispfrag->fr_opcode; + table_addr=lie->dispfrag->fr_address+(table_ptr - lie->dispfrag->fr_literal); + /* Create the jump around the long jumps */ + /* This is a short jump from table_ptr+0 to table_ptr+n*long_jump_size */ + from_addr=table_addr; + to_addr = table_addr + md_short_jump_size + n * md_long_jump_size; + md_create_short_jump(table_ptr,from_addr,to_addr,lie->dispfrag,lie->add); + table_ptr+=md_short_jump_size; + table_addr+=md_short_jump_size; + + for(m=0;lie && lie->dispfrag==fragP;m++,lie=lie->next_broken_word) { + if(lie->added==2) + continue; + /* Patch the jump table */ + /* This is the offset from ??? to table_ptr+0 */ + to_addr = table_addr + - (lie->sub->sy_value); + md_number_to_chars(lie->word_goes_here,to_addr,2); + for(untruth=lie->next_broken_word;untruth && untruth->dispfrag==fragP;untruth=untruth->next_broken_word) { + if(untruth->use_jump==lie) + md_number_to_chars(untruth->word_goes_here,to_addr,2); + } + + /* Install the long jump */ + /* this is a long jump from table_ptr+0 to the final target */ + from_addr=table_addr; + to_addr=lie->add->sy_value+lie->addnum; + md_create_long_jump(table_ptr,from_addr,to_addr,lie->dispfrag,lie->add); + table_ptr+=md_long_jump_size; + table_addr+=md_long_jump_size; + } + } + } +#endif +#ifndef VMS + /* + * Scan every FixS performing fixups. We had to wait until now to do + * this because md_convert_frag() may have made some fixSs. + */ + /* the_exec . a_trsize + = sizeof(struct relocation_info) * fixup_segment (text_fix_root, N_TEXT); + the_exec . a_drsize + = sizeof(struct relocation_info) * fixup_segment (data_fix_root, N_DATA); */ + + tr_siz=sizeof(struct relocation_info) * fixup_segment (text_fix_root, N_TEXT); + md_number_to_chars((char *)&the_exec.a_trsize, tr_siz ,sizeof(the_exec.a_trsize)); + dr_siz=sizeof(struct relocation_info) * fixup_segment (data_fix_root, N_DATA); + md_number_to_chars((char *)&the_exec.a_drsize, dr_siz, sizeof(the_exec.a_drsize)); + md_number_to_chars((char *)&the_exec.a_info,omagic,sizeof(the_exec.a_info)); + md_number_to_chars((char *)&the_exec.a_entry,0,sizeof(the_exec.a_entry)); + +#ifdef EXEC_MACHINE_TYPE + md_number_to_chars((char *)&the_exec.a_machtype, EXEC_MACHINE_TYPE, sizeof(the_exec.a_machtype)); +#endif +#ifdef EXEC_VERSION + md_number_to_chars((char *)&the_exec.a_version,EXEC_VERSION,sizeof(the_exec.a_version)); +#endif + + /* the_exec . a_entry = 0; */ + + size_of_the_object_file = + sizeof( the_exec ) + + text_siz + + data_siz + + syms_siz + + tr_siz + + dr_siz + + string_byte_count; + + next_object_file_charP + = the_object_file + = xmalloc ( size_of_the_object_file ); + + output_file_create (out_file_name); + + append (& next_object_file_charP, (char *)(&the_exec), (unsigned long)sizeof(the_exec)); + + /* + * Emit code. + */ + for (fragP = text_frag_root; fragP; fragP = fragP -> fr_next) + { + register long int count; + register char * fill_literal; + register long int fill_size; + + know( fragP -> fr_type == rs_fill ); + append (& next_object_file_charP, fragP -> fr_literal, (unsigned long)fragP -> fr_fix); + fill_literal= fragP -> fr_literal + fragP -> fr_fix; + fill_size = fragP -> fr_var; + know( fragP -> fr_offset >= 0 ); + for (count = fragP -> fr_offset; count; count --) + append (& next_object_file_charP, fill_literal, (unsigned long)fill_size); + } /* for each code frag. */ + + /* + * Emit relocations. + */ + emit_relocations (text_fix_root, (relax_addressT)0); + emit_relocations (data_fix_root, text_last_frag -> fr_address); + /* + * Emit all symbols left in the symbol chain. + * Any symbol still undefined is made N_EXT. + */ + for ( symbolP = symbol_rootP; symbolP; symbolP = symbolP -> sy_next ) + { + register char * temp; + + temp = symbolP -> sy_nlist . n_un . n_name; + /* JF fix the numbers up. Call by value RULES! */ + md_number_to_chars((char *)&(symbolP -> sy_nlist . n_un . n_strx ),symbolP -> sy_name_offset,sizeof(symbolP -> sy_nlist . n_un . n_strx )); + md_number_to_chars((char *)&(symbolP->sy_nlist.n_desc),symbolP->sy_nlist.n_desc,sizeof(symbolP -> sy_nlist . n_desc)); + md_number_to_chars((char *)&(symbolP->sy_nlist.n_value),symbolP->sy_nlist.n_value,sizeof(symbolP->sy_nlist.n_value)); + /* symbolP -> sy_nlist . n_un . n_strx = symbolP -> sy_name_offset; JF replaced by md above */ + if (symbolP -> sy_type == N_UNDF) + symbolP -> sy_type |= N_EXT; /* Any undefined symbols become N_EXT. */ + append (& next_object_file_charP, (char *)(& symbolP -> sy_nlist), + (unsigned long)sizeof(struct nlist)); + symbolP -> sy_nlist . n_un . n_name = temp; + } /* for each symbol */ + + /* + * next_object_file_charP -> slot for next object byte. + * Emit strings. + * Find strings by crawling along symbol table chain. + */ +/* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */ + md_number_to_chars((char *)&string_byte_count, string_byte_count, sizeof(string_byte_count)); + + append (& next_object_file_charP, (char *)&string_byte_count, (unsigned long)sizeof(string_byte_count)); + for ( symbolP = symbol_rootP; symbolP; symbolP = symbolP -> sy_next ) + { + if (symbolP -> sy_name) + { /* Ordinary case: not .stabd. */ + append (& next_object_file_charP, symbolP -> sy_name, + (unsigned long)(strlen (symbolP -> sy_name) + 1)); + } + } /* for each symbol */ + + know( next_object_file_charP == the_object_file + size_of_the_object_file ); + + output_file_append (the_object_file, size_of_the_object_file, out_file_name); + +#ifdef DONTDEF + if (flagseen['G']) /* GDB symbol file to be appended? */ + { + gdb_emit (out_file_name); + gdb_end (); + } +#endif + + output_file_close (out_file_name); +#else /* VMS */ + /* + * Now do the VMS-dependent part of writing the object file + */ + VMS_write_object_file(text_siz, data_siz, text_frag_root, data_frag_root); +#endif /* VMS */ +} /* write_object_file() */ + +/* + * relax_segment() + * + * Now we have a segment, not a crowd of sub-segments, we can make fr_address + * values. + * + * Relax the frags. + * + * After this, all frags in this segment have addresses that are correct + * within the segment. Since segments live in different file addresses, + * these frag addresses may not be the same as final object-file addresses. + */ +#ifndef VMS +static +#endif /* not VMS */ +void +relax_segment (segment_frag_root, segment_type) + struct frag * segment_frag_root; + segT segment_type; /* N_DATA or N_TEXT */ +{ + register struct frag * fragP; + register relax_addressT address; + /* register relax_addressT old_address; JF unused */ + /* register relax_addressT new_address; JF unused */ + + know( segment_type == SEG_DATA || segment_type == SEG_TEXT ); + + /* In case md_estimate_size_before_relax() wants to make fixSs. */ + subseg_change (segment_type, 0); + + /* + * For each frag in segment: count and store (a 1st guess of) fr_address. + */ + address = 0; + for ( fragP = segment_frag_root; fragP; fragP = fragP -> fr_next ) + { + fragP -> fr_address = address; + address += fragP -> fr_fix; + switch (fragP -> fr_type) + { + case rs_fill: + address += fragP -> fr_offset * fragP -> fr_var; + break; + + case rs_align: + address += relax_align (address, fragP -> fr_offset); + break; + + case rs_org: + /* + * Assume .org is nugatory. It will grow with 1st relax. + */ + break; + + case rs_machine_dependent: + address += md_estimate_size_before_relax + (fragP, seg_N_TYPE [(int) segment_type]); + break; + +#ifndef WORKING_DOT_WORD + /* Broken words don't concern us yet */ + case rs_broken_word: + break; +#endif + + default: + BAD_CASE( fragP -> fr_type ); + break; + } /* switch(fr_type) */ + } /* for each frag in the segment */ + + /* + * Do relax(). + */ + { + register long int stretch; /* May be any size, 0 or negative. */ + /* Cumulative number of addresses we have */ + /* relaxed this pass. */ + /* We may have relaxed more than one address. */ + register long int stretched; /* Have we stretched on this pass? */ + /* This is 'cuz stretch may be zero, when, + in fact some piece of code grew, and + another shrank. If a branch instruction + doesn't fit anymore, we could be scrod */ + + do + { + stretch = stretched = 0; + for (fragP = segment_frag_root; fragP; fragP = fragP -> fr_next) + { + register long int growth; + register long int was_address; + /* register long int var; */ + register long int offset; + register symbolS * symbolP; + register long int target; + register long int after; + register long int aim; + + was_address = fragP -> fr_address; + address = fragP -> fr_address += stretch; + symbolP = fragP -> fr_symbol; + offset = fragP -> fr_offset; + /* var = fragP -> fr_var; */ + switch (fragP -> fr_type) + { + case rs_fill: /* .fill never relaxes. */ + growth = 0; + break; + +#ifndef WORKING_DOT_WORD + /* JF: This is RMS's idea. I do *NOT* want to be blamed + for it I do not want to write it. I do not want to have + anything to do with it. This is not the proper way to + implement this misfeature. */ + case rs_broken_word: + { + struct broken_word *lie; + struct broken_word *untruth; + extern int md_short_jump_size; + extern int md_long_jump_size; + + /* Yes this is ugly (storing the broken_word pointer + in the symbol slot). Still, this whole chunk of + code is ugly, and I don't feel like doing anything + about it. Think of it as stubbornness in action */ + growth=0; + for(lie=(struct broken_word *)(fragP->fr_symbol); + lie && lie->dispfrag==fragP; + lie=lie->next_broken_word) { + + if(lie->added) + continue; + offset= lie->add->sy_frag->fr_address+lie->add->sy_value + lie->addnum - + (lie->sub->sy_frag->fr_address+lie->sub->sy_value); + if(offset<=-32768 || offset>=32767) { + if(flagseen['k']) + as_warn(".word %s-%s+%ld didn't fit",lie->add->sy_name,lie->sub->sy_name,lie->addnum); + lie->added=1; + if(fragP->fr_subtype==0) { + fragP->fr_subtype++; + growth+=md_short_jump_size; + } + for(untruth=lie->next_broken_word;untruth && untruth->dispfrag==lie->dispfrag;untruth=untruth->next_broken_word) + if(untruth->add->sy_frag==lie->add->sy_frag && untruth->add->sy_value==lie->add->sy_value) { + untruth->added=2; + untruth->use_jump=lie; + } + growth+=md_long_jump_size; + } + } + } + break; +#endif + case rs_align: + growth = relax_align ((relax_addressT)(address + fragP -> fr_fix), offset) + - relax_align ((relax_addressT)(was_address + fragP -> fr_fix), offset); + break; + + case rs_org: + target = offset; + if (symbolP) + { + know( ((symbolP -> sy_type & N_TYPE) == N_ABS) || ((symbolP -> sy_type & N_TYPE) == N_DATA) || ((symbolP -> sy_type & N_TYPE) == N_TEXT)); + know( symbolP -> sy_frag ); + know( (symbolP->sy_type&N_TYPE)!=N_ABS || symbolP->sy_frag==&zero_address_frag ); + target += + symbolP -> sy_value + + symbolP -> sy_frag -> fr_address; + } + know( fragP -> fr_next ); + after = fragP -> fr_next -> fr_address; + growth = ((target - after ) > 0) ? (target - after) : 0; + /* Growth may be -ve, but variable part */ + /* of frag cannot have < 0 chars. */ + /* That is, we can't .org backwards. */ + + growth -= stretch; /* This is an absolute growth factor */ + break; + + case rs_machine_dependent: + { + register const relax_typeS * this_type; + register const relax_typeS * start_type; + register relax_substateT next_state; + register relax_substateT this_state; + + start_type = this_type + = md_relax_table + (this_state = fragP -> fr_subtype); + target = offset; + if (symbolP) + { + know( ((symbolP -> sy_type & N_TYPE) == N_ABS) || ((symbolP -> sy_type & + N_TYPE) == N_DATA) || ((symbolP -> sy_type & N_TYPE) == N_TEXT)); + know( symbolP -> sy_frag ); + know( (symbolP->sy_type&N_TYPE)!=N_ABS || symbolP->sy_frag==&zero_address_frag ); + target += + symbolP -> sy_value + + symbolP -> sy_frag -> fr_address; + + /* If frag has yet to be reached on this pass, + assume it will move by STRETCH just as we did. + If this is not so, it will be because some frag + between grows, and that will force another pass. */ + + /* JF was just address */ + /* JF also added is_dnrange hack */ + /* There's gotta be a better/faster/etc way + to do this. . . */ + /* gnu@cygnus.com: I changed this from > to >= + because I ran into a zero-length frag (fr_fix=0) + which was created when the obstack needed a new + chunk JUST AFTER the opcode of a branch. Since + fr_fix is zero, fr_address of this frag is the same + as fr_address of the next frag. This + zero-length frag was variable and jumped to .+2 + (in the next frag), but since the > comparison + below failed (the two were =, not >), "stretch" + was not added to the target. Stretch was 178, so + the offset appeared to be .-176 instead, which did + not fit into a byte branch, so the assembler + relaxed the branch to a word. This didn't compare + with what happened when the same source file was + assembled on other machines, which is how I found it. + You might want to think about what other places have + trouble with zero length frags... */ + + if (symbolP->sy_frag->fr_address >= was_address && is_dnrange(fragP,symbolP->sy_frag)) + target += stretch; + + } + aim = target - address - fragP -> fr_fix; + /* The displacement is affected by the instruction size + * for the 32k architecture. I think we ought to be able + * to add fragP->fr_pcrel_adjust in all cases (it should be + * zero if not used), but just in case it breaks something + * else we'll put this inside #ifdef NS32K ... #endif + */ +#ifdef NS32K + aim += fragP->fr_pcrel_adjust; +#endif + + if (aim < 0) + { + /* Look backwards. */ + for (next_state = this_type -> rlx_more; next_state; ) + { + if (aim >= this_type -> rlx_backward) + next_state = 0; + else + { /* Grow to next state. */ + this_type = md_relax_table + (this_state = next_state); + next_state = this_type -> rlx_more; + } + } + } + else + { +#ifdef DONTDEF +/* JF these next few lines of code are for the mc68020 which can't handle short + offsets of zero in branch instructions. What a kludge! */ + if(aim==0 && this_state==(1<<2+0)) { /* FOO hard encoded from m.c */ + aim=this_type->rlx_forward+1; /* Force relaxation into word mode */ + } +#endif +/* JF end of 68020 code */ + /* Look forwards. */ + for (next_state = this_type -> rlx_more; next_state; ) + { + if (aim <= this_type -> rlx_forward) + next_state = 0; + else + { /* Grow to next state. */ + this_type = md_relax_table + (this_state = next_state); + next_state = this_type -> rlx_more; + } + } + } + if (growth = this_type -> rlx_length - start_type -> rlx_length) + fragP -> fr_subtype = this_state; + } + break; + + default: + BAD_CASE( fragP -> fr_type ); + break; + } + if(growth) { + stretch += growth; + stretched++; + } + } /* For each frag in the segment. */ + } while (stretched); /* Until nothing further to relax. */ + } + + /* + * We now have valid fr_address'es for each frag. + */ + + /* + * All fr_address's are correct, relative to their own segment. + * We have made all the fixS we will ever make. + */ +} /* relax_segment() */ + +/* + * Relax_align. Advance location counter to next address that has 'alignment' + * lowest order bits all 0s. + */ + +static relax_addressT /* How many addresses does the .align take? */ +relax_align (address, alignment) + register relax_addressT address; /* Address now. */ + register long int alignment; /* Alignment (binary). */ +{ + relax_addressT mask; + relax_addressT new_address; + + mask = ~ ( (~0) << alignment ); + new_address = (address + mask) & (~ mask); + return (new_address - address); +} + +/* + * fixup_segment() + */ +static long int +fixup_segment (fixP, this_segment_type) + register fixS * fixP; + int this_segment_type; /* N_TYPE bits for segment. */ +{ + register long int seg_reloc_count; + /* JF these all used to be local to the for loop, but GDB doesn't seem to be able to deal with them there, so I moved them here for a bit. */ + register symbolS * add_symbolP; + register symbolS * sub_symbolP; + register long int add_number; + register int size; + register char * place; + register long int where; + register char pcrel; + register fragS * fragP; + register int add_symbol_N_TYPE; + + + seg_reloc_count = 0; + for ( ; fixP; fixP = fixP -> fx_next) + { + fragP = fixP -> fx_frag; + know( fragP ); + where = fixP -> fx_where; + place = fragP -> fr_literal + where; + size = fixP -> fx_size; + add_symbolP = fixP -> fx_addsy; + sub_symbolP = fixP -> fx_subsy; + add_number = fixP -> fx_offset; + pcrel = fixP -> fx_pcrel; + if(add_symbolP) + add_symbol_N_TYPE = add_symbolP -> sy_type & N_TYPE; + if (sub_symbolP) + { + if(!add_symbolP) /* Its just -sym */ + { + if(sub_symbolP->sy_type!=N_ABS) + as_warn("Negative of non-absolute symbol %s", sub_symbolP->sy_name); + add_number-=sub_symbolP->sy_value; + } + else if ( ((sub_symbolP -> sy_type ^ add_symbol_N_TYPE) & N_TYPE) == 0 + && ( add_symbol_N_TYPE == N_DATA + || add_symbol_N_TYPE == N_TEXT + || add_symbol_N_TYPE == N_BSS + || add_symbol_N_TYPE == N_ABS)) + { + /* Difference of 2 symbols from same segment. */ + /* Can't make difference of 2 undefineds: 'value' means */ + /* something different for N_UNDF. */ + add_number += add_symbolP -> sy_value - sub_symbolP -> sy_value; + add_symbolP = NULL; + fixP -> fx_addsy = NULL; + } + else + { + /* Different segments in subtraction. */ + know( sub_symbolP -> sy_type != (N_ABS | N_EXT)) + if (sub_symbolP -> sy_type == N_ABS) + add_number -= sub_symbolP -> sy_value; + else + { + as_warn("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %d.", + seg_name[(int)N_TYPE_seg[sub_symbolP->sy_type&N_TYPE]], + sub_symbolP -> sy_name, fragP -> fr_address + where); + } + } + } + if (add_symbolP) + { + if (add_symbol_N_TYPE == this_segment_type && pcrel) + { + /* + * This fixup was made when the symbol's segment was + * SEG_UNKNOWN, but it is now in the local segment. + * So we know how to do the address without relocation. + */ + add_number += add_symbolP -> sy_value; + add_number -= +#ifndef NS32K + size + +#endif + where + fragP -> fr_address; +#if defined(NS32K) && defined(SEQUENT_COMPATABILITY) + if (fragP->fr_bsr) + add_number -= 0x12; /* FOO Kludge alert! */ +#endif + /* Kenny thinks this needs * + /* add_number +=size-2; */ + pcrel = 0; /* Lie. Don't want further pcrel processing. */ + fixP -> fx_addsy = NULL; /* No relocations please. */ + /* + * It would be nice to check that the address does not overflow. + * I didn't do this check because: + * + It is machine dependent in the general case (eg 32032) + * + Compiler output will never need this checking, so why + * slow down the usual case? + */ + } + else + { + switch (add_symbol_N_TYPE) + { + case N_ABS: + add_number += add_symbolP -> sy_value; + fixP -> fx_addsy = NULL; + add_symbolP = NULL; + break; + + case N_BSS: + case N_DATA: + case N_TEXT: + seg_reloc_count ++; + add_number += add_symbolP -> sy_value; + break; + + case N_UNDF: + seg_reloc_count ++; + break; + + default: + BAD_CASE( add_symbol_N_TYPE ); + break; + } /* switch on symbol seg */ + } /* if not in local seg */ + } /* if there was a + symbol */ + if (pcrel) + { + add_number -= +#ifndef NS32K + size + +#endif + where + fragP -> fr_address; + if (add_symbolP == 0) + { + fixP -> fx_addsy = & abs_symbol; + seg_reloc_count ++; + } + } + /* OVE added fx_im_disp for ns32k and others */ + if (!fixP->fx_bit_fixP) { + /* JF I hope this works . . . */ + if((size==1 && (add_number& ~0xFF) && (add_number&~0xFF!=(-1&~0xFF))) || + (size==2 && (add_number& ~0xFFFF) && (add_number&~0xFFFF!=(-1&~0xFFFF)))) + as_warn("Fixup of %d too large for field width of %d",add_number, size); + + switch (fixP->fx_im_disp) { + case 0: +#if defined(SPARC) || defined(I860) + fixP->fx_addnumber = add_number; + md_number_to_imm(place, add_number, size, fixP, this_segment_type); +#else + md_number_to_imm (place, add_number, size); + /* OVE: the immediates, like disps, have lsb at lowest address */ +#endif + break; + case 1: + md_number_to_disp (place, + fixP->fx_pcrel ? add_number+fixP->fx_pcrel_adjust:add_number, + size); + break; + case 2: /* fix requested for .long .word etc */ + md_number_to_chars (place, add_number, size); + break; + default: + as_fatal("Internal error in write.c in fixup_segment"); + } /* OVE: maybe one ought to put _imm _disp _chars in one md-func */ + } else { + md_number_to_field (place, add_number, fixP->fx_bit_fixP); + } + } /* For each fixS in this segment. */ + return (seg_reloc_count); +} /* fixup_segment() */ + + +/* The sparc needs its own emit_relocations() */ +#if !defined(SPARC) && !defined(I860) +/* + * emit_relocations() + * + * Crawl along a fixS chain. Emit the segment's relocations. + */ +static void +emit_relocations (fixP, segment_address_in_file) + register fixS * fixP; /* Fixup chain for this segment. */ + relax_addressT segment_address_in_file; +{ + struct relocation_info ri; + register symbolS * symbolP; + + /* JF this is for paranoia */ + bzero((char *)&ri,sizeof(ri)); + for ( ; fixP; fixP = fixP -> fx_next) + { + if (symbolP = fixP -> fx_addsy) + { + +#ifdef NS32K + /* These two 'cuz of NS32K */ + ri . r_bsr = fixP -> fx_bsr; + ri . r_disp = fixP -> fx_im_disp; +#endif + + ri . r_length = nbytes_r_length [fixP -> fx_size]; + ri . r_pcrel = fixP -> fx_pcrel; + ri . r_address = fixP -> fx_frag -> fr_address + + fixP -> fx_where + - segment_address_in_file; + if ((symbolP -> sy_type & N_TYPE) == N_UNDF) + { + ri . r_extern = 1; + ri . r_symbolnum = symbolP -> sy_number; + } + else + { + ri . r_extern = 0; + ri . r_symbolnum = symbolP -> sy_type & N_TYPE; + } + + /* + The 68k machines assign bit-fields from higher bits to + lower bits ("left-to-right") within the int. VAXen assign + bit-fields from lower bits to higher bits ("right-to-left"). + Both handle multi-byte numbers in their usual fashion + (Big-endian and little-endian stuff). + Thus we need a machine dependent routine to make + sure the structure is written out correctly. FUN! + */ + md_ri_to_chars((char *) &ri, ri); + append (&next_object_file_charP, (char *)& ri, (unsigned long)sizeof(ri)); + } + } + +} +#endif + +int +is_dnrange(f1,f2) +struct frag *f1,*f2; +{ + while(f1) { + if(f1->fr_next==f2) + return 1; + f1=f1->fr_next; + } + return 0; +} +/* End: as-write.c */ diff --git a/gnu/usr.bin/as/write.h b/gnu/usr.bin/as/write.h new file mode 100644 index 0000000..7327690 --- /dev/null +++ b/gnu/usr.bin/as/write.h @@ -0,0 +1,77 @@ +/* write.h -> write.c + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* The bit_fix was implemented to support machines that need variables + to be inserted in bitfields other than 1, 2 and 4 bytes. + Furthermore it gives us a possibillity to mask in bits in the symbol + when it's fixed in the objectcode and check the symbols limits. + + The or-mask is used to set the huffman bits in displacements for the + ns32k port. + The acbi, addqi, movqi, cmpqi instruction requires an assembler that + can handle bitfields. Ie handle an expression, evaluate it and insert + the result in an some bitfield. ( ex: 5 bits in a short field of a opcode) + */ + + +struct bit_fix { + int fx_bit_size; /* Length of bitfield */ + int fx_bit_offset; /* Bit offset to bitfield */ + long fx_bit_base; /* Where do we apply the bitfix. + If this is zero, default is assumed. */ + long fx_bit_base_adj;/* Adjustment of base */ + long fx_bit_max; /* Signextended max for bitfield */ + long fx_bit_min; /* Signextended min for bitfield */ + long fx_bit_add; /* Or mask, used for huffman prefix */ +}; +typedef struct bit_fix bit_fixS; +/* + * FixSs may be built up in any order. + */ + +struct fix +{ + fragS * fx_frag; /* Which frag? */ + long int fx_where; /* Where is the 1st byte to fix up? */ + symbolS * fx_addsy; /* NULL or Symbol whose value we add in. */ + symbolS * fx_subsy; /* NULL or Symbol whose value we subtract. */ + long int fx_offset; /* Absolute number we add in. */ + struct fix * fx_next; /* NULL or -> next fixS. */ + short int fx_size; /* How many bytes are involved? */ + char fx_pcrel; /* TRUE: pc-relative. */ + char fx_pcrel_adjust;/* pc-relative offset adjust */ + char fx_im_disp; /* TRUE: value is a displacement */ + bit_fixS * fx_bit_fixP; /* IF NULL no bitfix's to do */ + char fx_bsr; /* sequent-hack */ +#if defined(SPARC) || defined(I860) + char fx_r_type; /* Sparc hacks */ + long fx_addnumber; +#endif +}; + +typedef struct fix fixS; + + +COMMON fixS * text_fix_root; /* Chains fixSs. */ +COMMON fixS * data_fix_root; /* Chains fixSs. */ +COMMON fixS ** seg_fix_rootP; /* -> one of above. */ + +bit_fixS *bit_fix_new(); +/* end: write.h */ + diff --git a/gnu/usr.bin/as/xmalloc.c b/gnu/usr.bin/as/xmalloc.c new file mode 100644 index 0000000..78c8c7f --- /dev/null +++ b/gnu/usr.bin/as/xmalloc.c @@ -0,0 +1,60 @@ +/* xmalloc.c - get memory or bust + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* +NAME + xmalloc() - get memory or bust +INDEX + xmalloc() uses malloc() + +SYNOPSIS + char * my_memory; + + my_memory = xmalloc(42); / * my_memory gets address of 42 chars * / + +DESCRIPTION + + Use xmalloc() as an "error-free" malloc(). It does almost the same job. + When it cannot honour your request for memory it BOMBS your program + with a "virtual memory exceeded" message. Malloc() returns NULL and + does not bomb your program. + +SEE ALSO + malloc() + +*/ +#ifdef USG +#include <malloc.h> +#endif + +char * xmalloc(n) + long n; +{ + char * retval; + char * malloc(); + void error(); + + if ( ! (retval = malloc ((unsigned)n)) ) + { + error("virtual memory exceeded"); + } + return (retval); +} + +/* end: xmalloc.c */ diff --git a/gnu/usr.bin/as/xrealloc.c b/gnu/usr.bin/as/xrealloc.c new file mode 100644 index 0000000..a5010bc --- /dev/null +++ b/gnu/usr.bin/as/xrealloc.c @@ -0,0 +1,61 @@ +/* xrealloc.c -new memory or bust- + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* + +NAME + xrealloc () - get more memory or bust +INDEX + xrealloc () uses realloc () +SYNOPSIS + char *my_memory; + + my_memory = xrealloc (my_memory, 42); + / * my_memory gets (perhaps new) address of 42 chars * / + +DESCRIPTION + + Use xrealloc () as an "error-free" realloc ().It does almost the same + job. When it cannot honour your request for memory it BOMBS your + program with a "virtual memory exceeded" message. Realloc() returns + NULL and does not bomb your program. + +SEE ALSO + realloc () +*/ + +#ifdef USG +#include <malloc.h> +#endif + +char * +xrealloc (ptr, n) +register char *ptr; +long n; +{ + char *realloc (); + void error(); + + if ((ptr = realloc (ptr, (unsigned)n)) == 0) + error ("virtual memory exceeded"); + return (ptr); +} + +/* end: xrealloc.c */ |