This commit was manufactured by cvs2svn to create branch 'binutils'.
Cherrypick from master 1991-04-04 18:19:53 UTC K. Richard Pixley <rich@cygnus> 'Initial revision': gas/COPYING gas/ChangeLog gas/Makefile.in gas/README gas/app.c gas/as.c gas/as.h gas/atof-generic.c gas/bignum-copy.c gas/bignum.h gas/cond.c gas/config/atof-ieee.c gas/config/atof-vax.c gas/config/obj-aout.c gas/config/obj-aout.h gas/config/obj-bout.c gas/config/obj-bout.h gas/config/obj-coff.c gas/config/obj-coff.h gas/config/tc-a29k.c gas/config/tc-a29k.h gas/config/tc-generic.c gas/config/tc-generic.h gas/config/tc-i386.c gas/config/tc-i386.h gas/config/tc-i860.c gas/config/tc-i860.h gas/config/tc-i960.c gas/config/tc-i960.h gas/config/tc-m68851.h gas/config/tc-m68k.c gas/config/tc-m68k.h gas/config/tc-ns32k.c gas/config/tc-ns32k.h gas/config/tc-sparc.c gas/config/tc-sparc.h gas/config/tc-vax.c gas/config/tc-vax.h gas/config/te-generic.h gas/config/te-ic960.h gas/config/te-sun3.h gas/config/vax-inst.h gas/configure gas/configure.in gas/debug.c gas/expr.c gas/expr.h gas/flonum-copy.c gas/flonum-mult.c gas/flonum.h gas/frags.c gas/frags.h gas/hash.c gas/hash.h gas/input-file.c gas/input-file.h gas/input-scrub.c gas/messages.c gas/obj.h gas/output-file.c gas/output-file.h gas/read.c gas/read.h gas/struc-symbol.h gas/subsegs.c gas/subsegs.h gas/symbols.c gas/symbols.h gas/tc.h gas/write.c gas/write.h ld/ld.h ld/ldexp.c ld/ldfile.c ld/ldfile.h ld/ldlang.h ld/ldlex.h ld/ldmain.h ld/ldmisc.h ld/ldwrite.h Cherrypick from master 1991-03-21 21:29:06 UTC David Henkel-Wallace <gumby@cygnus> 'Initial revision': ld/ldexp.h ld/ldgram.y ld/ldlang.c ld/ldlex.l ld/ldmain.c ld/ldmisc.c ld/ldwrite.c Cherrypick from master 1991-01-17 15:34:55 UTC Roland Pesch <pesch@cygnus> 'Initial revision': gas/doc/as.texinfo
This commit is contained in:
parent
b37af01c89
commit
3a69b3aca6
88 changed files with 47908 additions and 0 deletions
249
gas/COPYING
Normal file
249
gas/COPYING
Normal file
|
@ -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!
|
1196
gas/ChangeLog
Normal file
1196
gas/ChangeLog
Normal file
File diff suppressed because it is too large
Load diff
584
gas/Makefile.in
Normal file
584
gas/Makefile.in
Normal file
|
@ -0,0 +1,584 @@
|
|||
# Makefile for GNU Assembler
|
||||
# Copyright (C) 1987, 1988, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
#This file is part of GNU GAS.
|
||||
|
||||
#GNU GAS is free software; you can redistribute it and/or modify
|
||||
#it under the terms of the GNU General Public License as published by
|
||||
#the Free Software Foundation; either version 1, or (at your option)
|
||||
#any later version.
|
||||
|
||||
#GNU GAS is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU General Public License for more details.
|
||||
|
||||
#You should have received a copy of the GNU General Public License
|
||||
#along with GNU GAS; see the file COPYING. If not, write to
|
||||
#the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
# $Id$
|
||||
|
||||
# The targets for external use include:
|
||||
# all, doc, proto, install, uninstall, includes, TAGS,
|
||||
# clean, cleanconfig, realclean, stage1, stage2, stage3, stage4.
|
||||
|
||||
# Variables that exist for you to override.
|
||||
# See below for how to change them for certain systems.
|
||||
|
||||
ALLOCA =
|
||||
CFLAGS = -g $(XCFLAGS) # -I$(srcdir)/../include
|
||||
INTERNAL_CFLAGS = $(CROSS)
|
||||
OLDCC = cc
|
||||
BISON = bison
|
||||
BISONFLAGS = -v
|
||||
AR = ar
|
||||
OLDAR_FLAGS = qc
|
||||
AR_FLAGS = rc
|
||||
SHELL = /bin/sh
|
||||
# on sysV, define this as cp.
|
||||
INSTALL = install -c
|
||||
# These permit overriding just for certain files.
|
||||
INSTALL_PROGRAM = $(INSTALL)
|
||||
INSTALL_FILE = $(INSTALL)
|
||||
|
||||
# Define this as & to perform parallel make on a Sequent.
|
||||
# Note that this has some bugs, and it seems currently necessary
|
||||
# to compile all the gen* files first by hand to avoid erroneous results.
|
||||
P =
|
||||
|
||||
# How to invoke ranlib.
|
||||
RANLIB = ranlib
|
||||
# Test to use to see whether ranlib exists on the system.
|
||||
RANLIB_TEST = [ -f /usr/bin/ranlib -o -f /bin/ranlib ]
|
||||
|
||||
# CFLAGS for use with OLDCC, for compiling gnulib.
|
||||
# NOTE: -O does not work on some Unix systems!
|
||||
CCLIBFLAGS = -O
|
||||
|
||||
# Version of ar to use when compiling gnulib.
|
||||
OLDAR = ar
|
||||
|
||||
version=`./gcc -dumpversion`
|
||||
|
||||
# Directory where sources are, from where we are.
|
||||
srcdir = .
|
||||
# Common prefix for installation directories.
|
||||
# NOTE: This directory must exist when you start installation.
|
||||
prefix = /usr/local
|
||||
# Directory in which to put the executable for the command `gcc'
|
||||
bindir = $(prefix)/bin
|
||||
# Directory in which to put the directories used by the compiler.
|
||||
libdir = $(prefix)/lib
|
||||
# Directory in which the compiler finds executables, libraries, etc.
|
||||
libsubdir = $(libdir)/gcc/$(target)/$(version)
|
||||
# Number to put in man-page filename.
|
||||
manext = 1
|
||||
# Directory in which to put man pages.
|
||||
mandir = $(prefix)/man/man$(manext)
|
||||
|
||||
# Additional system libraries to link with.
|
||||
CLIB=
|
||||
|
||||
# Change this to a null string if obstacks are installed in the
|
||||
# system library.
|
||||
OBSTACK=obstack.o
|
||||
|
||||
# Specify the rule for actually making gnulib.
|
||||
GNULIB = gnulib.portable
|
||||
|
||||
# Specify the rule for actually making gnulib2.
|
||||
GNULIB2 = gnulib2.portable
|
||||
|
||||
# List of extra C and assembler files to add to gnulib.
|
||||
# Assembler files should have names ending in `.asm'.
|
||||
LIBFUNCS_EXTRA =
|
||||
|
||||
# Program to convert libraries.
|
||||
LIBCONVERT =
|
||||
|
||||
# Control whether header files are installed.
|
||||
INSTALL_HEADERS=install-headers
|
||||
|
||||
# Change this to empty to prevent installing limits.h
|
||||
LIMITS_H = limits.h
|
||||
|
||||
# Directory to link to, when using the target `maketest'.
|
||||
DIR = ../gcc
|
||||
|
||||
# For better debugging under COFF, define SEPARATE_AUX_OUTPUT in config.h
|
||||
# and define the following variable as `aux-output2.c' in make-...
|
||||
AUX_OUTPUT2 =
|
||||
|
||||
# Flags to use when cross-building GCC.
|
||||
# Prefix to apply to names of object files when using them
|
||||
# to run on the machine we are compiling on.
|
||||
HOST_PREFIX=
|
||||
# Prefix to apply to names of object files when compiling them
|
||||
# to run on the machine we are compiling on.
|
||||
# The default for this variable is chosen to keep these rules
|
||||
# out of the way of the other rules for compiling the same source files.
|
||||
HOST_PREFIX_1=loser-
|
||||
HOST_CC=$(CC)
|
||||
HOST_CFLAGS=$(ALL_CFLAGS)
|
||||
HOST_LDFLAGS=$(LDFLAGS)
|
||||
HOST_CPPFLAGS=$(CPPFLAGS)
|
||||
|
||||
# Choose the real default target.
|
||||
ALL=gas
|
||||
|
||||
# End of variables for you to override.
|
||||
|
||||
# Lists of files for various purposes.
|
||||
|
||||
REAL_SOURCES = \
|
||||
$(srcdir)/app.c \
|
||||
$(srcdir)/as.c \
|
||||
$(srcdir)/atof-generic.c \
|
||||
$(srcdir)/bignum-copy.c \
|
||||
$(srcdir)/cond.c \
|
||||
$(srcdir)/expr.c \
|
||||
$(srcdir)/flonum-const.c \
|
||||
$(srcdir)/flonum-copy.c \
|
||||
$(srcdir)/flonum-mult.c \
|
||||
$(srcdir)/frags.c \
|
||||
$(srcdir)/hash.c \
|
||||
$(srcdir)/hex-value.c \
|
||||
$(srcdir)/input-file.c \
|
||||
$(srcdir)/input-scrub.c \
|
||||
$(srcdir)/messages.c \
|
||||
$(srcdir)/output-file.c \
|
||||
$(srcdir)/read.c \
|
||||
$(srcdir)/strstr.c \
|
||||
$(srcdir)/subsegs.c \
|
||||
$(srcdir)/symbols.c \
|
||||
$(srcdir)/version.c \
|
||||
$(srcdir)/write.c \
|
||||
$(srcdir)/xmalloc.c \
|
||||
$(srcdir)/xrealloc.c
|
||||
|
||||
# in an expedient order
|
||||
LINKED_SOURCES = \
|
||||
targ-cpu.c \
|
||||
obj-format.c \
|
||||
atof-targ.c
|
||||
|
||||
SOURCES = $(LINKED_SOURCES) $(REAL_SOURCES)
|
||||
|
||||
REAL_HEADERS = \
|
||||
$(srcdir)/as.h \
|
||||
$(srcdir)/bignum.h \
|
||||
$(srcdir)/expr.h \
|
||||
$(srcdir)/flonum.h \
|
||||
$(srcdir)/frags.h \
|
||||
$(srcdir)/hash.h \
|
||||
$(srcdir)/input-file.h \
|
||||
$(srcdir)/tc.h \
|
||||
$(srcdir)/obj.h \
|
||||
$(srcdir)/read.h \
|
||||
$(srcdir)/reloc.h \
|
||||
$(srcdir)/struc-symbol.h \
|
||||
$(srcdir)/subsegs.h \
|
||||
$(srcdir)/symbols.h \
|
||||
$(srcdir)/syscalls.h \
|
||||
$(srcdir)/write.h
|
||||
|
||||
LINKED_HEADERS = \
|
||||
a.out.gnu.h \
|
||||
a.out.h \
|
||||
host.h \
|
||||
targ-env.h \
|
||||
targ-cpu.h \
|
||||
obj-format.h \
|
||||
atof-targ.h
|
||||
|
||||
HEADERS = $(LINKED_HEADERS) $(REAL_HEADERS)
|
||||
|
||||
OBJS = \
|
||||
targ-cpu.o \
|
||||
obj-format.o \
|
||||
atof-targ.o \
|
||||
app.o \
|
||||
as.o \
|
||||
atof-generic.o \
|
||||
bignum-copy.o \
|
||||
cond.o \
|
||||
expr.o \
|
||||
flonum-const.o \
|
||||
flonum-copy.o \
|
||||
flonum-mult.o \
|
||||
frags.o \
|
||||
hash.o \
|
||||
hex-value.o \
|
||||
input-file.o \
|
||||
input-scrub.o \
|
||||
messages.o \
|
||||
output-file.o \
|
||||
read.o \
|
||||
strstr.o \
|
||||
subsegs.o \
|
||||
symbols.o \
|
||||
version.o \
|
||||
write.o \
|
||||
xmalloc.o \
|
||||
xrealloc.o
|
||||
|
||||
# Definition of `all' is here so that new rules inserted by sed
|
||||
# do not specify the default target.
|
||||
# The real definition is under `all.internal'.
|
||||
|
||||
all: $(ALL)
|
||||
|
||||
# sed inserts variable overrides after the following line.
|
||||
####
|
||||
|
||||
# Now figure out from those variables how to compile and link.
|
||||
|
||||
# This is the variable actually used when we compile.
|
||||
ALL_CFLAGS = $(INTERNAL_CFLAGS) $(CFLAGS)
|
||||
|
||||
# Even if ALLOCA is set, don't use it if compiling with GCC.
|
||||
USE_ALLOCA= `if [ x"${CC}" = x"${OLDCC}" ] ; then echo ${ALLOCA}; else true; fi`
|
||||
USE_HOST_ALLOCA= `if [ x"${CC}" = x"${OLDCC}" ] ; then echo ${HOST_PREFIX}${ALLOCA}; else true; fi`
|
||||
|
||||
# Dependency on obstack, alloca, malloc or whatever library facilities
|
||||
# are not installed in the system libraries.
|
||||
# We don't use USE_ALLOCA because backquote expansion doesn't work in deps.
|
||||
LIBDEPS= $(OBSTACK) $(ALLOCA) $(MALLOC)
|
||||
|
||||
# Likewise, for use in the tools that must run on this machine
|
||||
# even if we are cross-building GCC.
|
||||
# We don't use USE_ALLOCA because backquote expansion doesn't work in deps.
|
||||
HOST_LIBDEPS= $(HOST_PREFIX)$(OBSTACK) $(HOST_PREFIX)$(ALLOCA) $(HOST_PREFIX)$(MALLOC)
|
||||
|
||||
# How to link with both our special library facilities
|
||||
# and the system's installed libraries.
|
||||
LIBS = $(OBSTACK) $(USE_ALLOCA) $(MALLOC) $(CLIB)
|
||||
|
||||
# Likewise, for use in the tools that must run on this machine
|
||||
# even if we are cross-building GCC.
|
||||
HOST_LIBS = $(HOST_PREFIX)$(OBSTACK) $(USE_HOST_ALLOCA) $(HOST_PREFIX)$(MALLOC) $(CLIB)
|
||||
|
||||
# Specify the directories to be searched for header files.
|
||||
# Both . and srcdir are used, in that order,
|
||||
# so that tm.h and config.h will be found in the compilation
|
||||
# subdirectory rather than in the source directory.
|
||||
INCLUDES = -I. -I$(srcdir) -I$(srcdir)/config
|
||||
SUBDIR_INCLUDES = -I.. -I../$(srcdir) -I../$(srcdir)/config
|
||||
|
||||
# Always use -I$(srcdir)/config when compiling.
|
||||
.c.o:
|
||||
$(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $<
|
||||
|
||||
# This tells GNU make version 3 not to export all the variables
|
||||
# defined in this file into the environment.
|
||||
.NOEXPORT:
|
||||
|
||||
# Files to be copied away after each stage in building.
|
||||
STAGE_GCC=gcc
|
||||
STAGESTUFF = *.o gas
|
||||
|
||||
# The files that "belong" in CONFIG_H are deliberately omitted
|
||||
# because having them there would not be useful in actual practice.
|
||||
# All they would do is cause complete recompilation every time
|
||||
# one of the machine description files is edited.
|
||||
# That may or may not be what one wants to do.
|
||||
# If it is, rm *.o is an easy way to do it.
|
||||
# CONFIG_H = config.h tm.h
|
||||
CONFIG_H =
|
||||
|
||||
gas: $(OBJS) $(LIBDEPS)
|
||||
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o gas $(OBJS) $(LIBS)
|
||||
|
||||
all.internal: native
|
||||
# This is what is made with the host's compiler if making a cross assembler.
|
||||
native: config.status gas
|
||||
|
||||
config.status:
|
||||
@echo You must configure gas. Look at the INSTALL file for details.
|
||||
@false
|
||||
|
||||
compilations: ${OBJS}
|
||||
|
||||
# Compiling object files from source files.
|
||||
|
||||
# Note that dependencies on obstack.h are not written
|
||||
# because that file is not part of GAS.
|
||||
|
||||
app.o : app.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
|
||||
as.o : as.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
|
||||
atof-generic.o : atof-generic.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
|
||||
bignum-copy.o : bignum-copy.c as.h host.h \
|
||||
targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
|
||||
cond.o : cond.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
|
||||
obstack.h
|
||||
debug.o : debug.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
|
||||
subsegs.h
|
||||
expr.o : expr.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
|
||||
obstack.h
|
||||
flonum-const.o : flonum-const.c flonum.h bignum.h
|
||||
flonum-copy.o : flonum-copy.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
|
||||
flonum-mult.o : flonum-mult.c flonum.h bignum.h
|
||||
frags.o : frags.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
|
||||
subsegs.h obstack.h
|
||||
hash.o : hash.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
|
||||
hex-value.o : hex-value.c
|
||||
input-file.o : input-file.c as.h host.h \
|
||||
targ-env.h obj-format.h targ-cpu.h \
|
||||
struc-symbol.h reloc.h write.h flonum.h bignum.h expr.h \
|
||||
frags.h hash.h read.h symbols.h tc.h obj.h input-file.h
|
||||
input-scrub.o : input-scrub.c /usr/include/errno.h /usr/include/sys/errno.h \
|
||||
as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
|
||||
input-file.h
|
||||
messages.o : messages.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
|
||||
obstack.o : obstack.c obstack.h
|
||||
output-file.o : output-file.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
|
||||
output-file.h
|
||||
read.o : read.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
|
||||
obstack.h
|
||||
strstr.o : strstr.c
|
||||
subsegs.o : subsegs.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
|
||||
subsegs.h obstack.h
|
||||
symbols.o : symbols.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
|
||||
obstack.h subsegs.h
|
||||
version.o : version.c
|
||||
write.o : write.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
|
||||
subsegs.h obstack.h output-file.h
|
||||
xmalloc.o : xmalloc.c
|
||||
xrealloc.o : xrealloc.c
|
||||
atof-targ.o : atof-targ.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
|
||||
symbols.h tc.h obj.h
|
||||
obj-format.o : obj-format.c as.h host.h targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
|
||||
symbols.h tc.h obj.h obstack.h
|
||||
targ-cpu.o : targ-cpu.c targ-env.h obj-format.h \
|
||||
targ-cpu.h struc-symbol.h reloc.h \
|
||||
write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
|
||||
symbols.h tc.h obj.h obstack.h
|
||||
|
||||
# Normally this target is not used; but it is used if you
|
||||
# define ALLOCA=alloca.o. In that case, you must get a suitable alloca.c
|
||||
# from the GNU Emacs distribution.
|
||||
# Note some machines won't allow $(CC) without -S on this source file.
|
||||
alloca.o: alloca.c
|
||||
$(CC) $(ALL_CFLAGS) $(CPPFLAGS) -S `echo $(srcdir)/alloca.c | sed 's,^\./,,'`
|
||||
as alloca.s -o alloca.o
|
||||
|
||||
# Compile the libraries to be used by gen*.
|
||||
# If we are not cross-building, gen* use the same .o's that cc1 will use,
|
||||
# and HOST_PREFIX_1 is `foobar', just to ensure these rules don't conflict
|
||||
# with the rules for rtl.o, alloca.o, etc.
|
||||
$(HOST_PREFIX_1)alloca.o: alloca.c
|
||||
rm -f $(HOST_PREFIX)alloca.c
|
||||
cp $(srcdir)/alloca.c $(HOST_PREFIX)alloca.c
|
||||
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)alloca.c
|
||||
|
||||
$(HOST_PREFIX_1)obstack.o: obstack.c
|
||||
rm -f $(HOST_PREFIX)obstack.c
|
||||
cp $(srcdir)/obstack.c $(HOST_PREFIX)obstack.c
|
||||
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)obstack.c
|
||||
|
||||
$(HOST_PREFIX_1)malloc.o: malloc.c
|
||||
rm -f $(HOST_PREFIX)malloc.c
|
||||
cp $(srcdir)/malloc.c $(HOST_PREFIX)malloc.c
|
||||
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)malloc.c
|
||||
|
||||
# Remake the info files.
|
||||
|
||||
doc: $(srcdir)/gas.info
|
||||
|
||||
$(srcdir)/gas.info: $(srcdir)/gas.texinfo
|
||||
makeinfo `echo $(srcdir)/gas.texinfo | sed 's,^\./,,'`
|
||||
|
||||
|
||||
# Deletion of files made during compilation.
|
||||
# There are three levels of this: `clean', `cleanconfig' and `realclean'.
|
||||
# `clean' deletes what you want to delete ordinarily to save space.
|
||||
# This is most, but not all, of the files made by compilation.
|
||||
# `cleanconfig' also deletes everything depending
|
||||
# on the choice of config files.
|
||||
# `realclean' also deletes everything that could be regenerated automatically.
|
||||
|
||||
clean:
|
||||
-rm -f $(STAGESTUFF)
|
||||
# Delete the temporary source copies for cross compilation.
|
||||
-rm -f $(HOST_PREFIX_1)alloca.c $(HOST_PREFIX_1)malloc.c
|
||||
-rm -f $(HOST_PREFIX_1)obstack.c
|
||||
# Delete the stamp files except stamp-gnulib2.
|
||||
-rm -f core
|
||||
|
||||
# Like clean but also delete the links made to configure gas.
|
||||
cleanconfig: clean
|
||||
-rm -f config.status Makefile host.h targ-env.h
|
||||
-rm -f targ-cpu.h targ-cpu.c
|
||||
-rm -f obj-format.h obj-format.c
|
||||
-rm -f atof-targ.c
|
||||
|
||||
# Get rid of every file that's generated from some other file (except INSTALL).
|
||||
realclean: cleanconfig
|
||||
-rm -f gas.aux gas.cps gas.fns gas.info gas.kys gas.pgs gas.tps gas.vrs
|
||||
-rm -f TAGS
|
||||
-rm -f gas.info* gas.?? gas.??s gas.log gas.toc gas.*aux
|
||||
-rm -f *.dvi
|
||||
|
||||
# Entry points `install', `includes' and `uninstall'.
|
||||
|
||||
# Copy the files into directories where they will be run.
|
||||
install:
|
||||
$(INSTALL_PROGRAM) gas $(bindir)/as
|
||||
|
||||
# Create the installation directory.
|
||||
install-dir:
|
||||
-mkdir $(libdir)
|
||||
-mkdir $(libdir)/gcc
|
||||
-mkdir $(libdir)/gcc/$(target)
|
||||
-mkdir $(libdir)/gcc/$(target)/$(version)
|
||||
|
||||
# Install the compiler executables built during cross compilation.
|
||||
install-cross: native install-dir
|
||||
-if [ -f cc1 ] ; then $(INSTALL_PROGRAM) cc1 $(libsubdir)/cc1; else true; fi
|
||||
-if [ -f cc1plus ] ; then $(INSTALL_PROGRAM) cc1plus $(libsubdir)/cc1plus; else true; fi
|
||||
$(INSTALL_PROGRAM) cpp $(libsubdir)/cpp
|
||||
./gcc -dumpspecs > $(libsubdir)/specs
|
||||
$(INSTALL_PROGRAM) gcc $(bindir)/gcc
|
||||
|
||||
# Install the man pages.
|
||||
install-man: install-dir $(srcdir)/gcc.1 protoize.1 unprotoize.1
|
||||
$(INSTALL_FILE) $(srcdir)/gcc.1 $(mandir)/gcc.$(manext)
|
||||
chmod a-x $(mandir)/gcc.$(manext)
|
||||
$(INSTALL_FILE) $(srcdir)/protoize.1 $(mandir)/protoize.$(manext)
|
||||
chmod a-x $(mandir)/protoize.$(manext)
|
||||
$(INSTALL_FILE) $(srcdir)/unprotoize.1 $(mandir)/unprotoize.$(manext)
|
||||
chmod a-x $(mandir)/unprotoize.$(manext)
|
||||
|
||||
# Cancel installation by deleting the installed files.
|
||||
uninstall:
|
||||
-rm -rf $(libsubdir)
|
||||
-rm -rf $(bindir)/gas
|
||||
-rm -rf $(mandir)/gas.$(manext)
|
||||
|
||||
|
||||
# These exist for maintenance purposes.
|
||||
|
||||
tags TAGS: force
|
||||
etags $(REAL_SOURCES) $(REAL_HEADERS) README Makefile config/*.[hc]
|
||||
|
||||
bootstrap: gas force
|
||||
$(MAKE) stage1
|
||||
$(MAKE) CC="$(CC)" CFLAGS="-O -Bstage1/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
|
||||
$(MAKE) stage2
|
||||
$(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
|
||||
for i in *.o; do cmp $$i stage2/$$i; done
|
||||
|
||||
bootstrap2: force
|
||||
$(MAKE) CC="$(CC)" CFLAGS="-O -Bstage1/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
|
||||
$(MAKE) stage2
|
||||
$(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
|
||||
for i in *.o; do cmp $$i stage2/$$i; done
|
||||
|
||||
bootstrap3: force
|
||||
$(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
|
||||
for i in *.o; do cmp $$i stage2/$$i; done
|
||||
|
||||
# Copy the object files from a particular stage into a subdirectory.
|
||||
stage1: force
|
||||
-mkdir stage1
|
||||
-mv $(STAGESTUFF) stage1
|
||||
-(cd stage1 ; ln -s gas as)
|
||||
|
||||
stage2: force
|
||||
-mkdir stage2
|
||||
-mv $(STAGESTUFF) stage2
|
||||
-(cd stage2 ; ln -s gas as)
|
||||
|
||||
|
||||
stage3: force
|
||||
-mkdir stage3
|
||||
-mv $(STAGESTUFF) $(STAGE_GCC) stage3
|
||||
-rm -f stage3/gnulib
|
||||
-cp gnulib stage3
|
||||
-if $(RANLIB_TEST) ; then $(RANLIB) stage3/gnulib; else true; fi
|
||||
|
||||
stage4: force
|
||||
-mkdir stage4
|
||||
-mv $(STAGESTUFF) $(STAGE_GCC) stage4
|
||||
-rm -f stage4/gnulib
|
||||
-cp gnulib stage4
|
||||
-if $(RANLIB_TEST) ; then $(RANLIB) stage4/gnulib; else true; fi
|
||||
|
||||
# Copy just the executable files from a particular stage into a subdirectory,
|
||||
# and delete the object files. Use this if you're just verifying a version
|
||||
# that is pretty sure to work, and you are short of disk space.
|
||||
risky-stage1: force
|
||||
-mkdir stage1
|
||||
-mv cc1 cpp cccp gcc stage1
|
||||
-rm -f stage1/gnulib
|
||||
-cp gnulib stage1 && $(RANLIB) stage1/gnulib
|
||||
-make clean
|
||||
|
||||
risky-stage2: force
|
||||
-mkdir stage2
|
||||
-mv cc1 cpp cccp gcc stage2
|
||||
-rm -f stage2/gnulib
|
||||
-cp gnulib stage2 && $(RANLIB) stage2/gnulib
|
||||
-make clean
|
||||
|
||||
risky-stage3: force
|
||||
-mkdir stage3
|
||||
-mv cc1 cpp cccp gcc stage3
|
||||
-rm -f stage3/gnulib
|
||||
-cp gnulib stage3 && $(RANLIB) stage3/gnulib
|
||||
-make clean
|
||||
|
||||
risky-stage4: force
|
||||
-mkdir stage4
|
||||
-mv cc1 cpp cccp gcc stage4
|
||||
-rm -f stage4/gnulib
|
||||
-cp gnulib stage4 && $(RANLIB) stage4/gnulib
|
||||
-make clean
|
||||
|
||||
#In GNU Make, ignore whether `stage*' exists.
|
||||
.PHONY: stage1 stage2 stage3 stage4 clean realclean TAGS bootstrap
|
||||
.PHONY: risky-stage1 risky-stage2 risky-stage3 risky-stage4
|
||||
|
||||
force:
|
||||
|
||||
Makefile: $(srcdir)/Makefile.in $(srcdir)/configure
|
||||
(cd $(srcdir) ; configure -host=$(host) $(target))
|
139
gas/README
Normal file
139
gas/README
Normal file
|
@ -0,0 +1,139 @@
|
|||
This is the beta-test version of the GNU assembler. (Probably
|
||||
around Version 1.38, but check version.c which gets updated more
|
||||
often than this readme.)
|
||||
|
||||
These files are currently set up to allow you to compile all of the
|
||||
versions of the assembler on the same machine. 'make all' compiles
|
||||
all of them. The resulting executable names are:
|
||||
|
||||
68020 a68
|
||||
Vax avax
|
||||
NS 32xxx a32k
|
||||
Intel 80386 a386
|
||||
SPARC asparc
|
||||
AMD 29000 asm29k
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
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.
|
508
gas/app.c
Normal file
508
gas/app.c
Normal file
|
@ -0,0 +1,508 @@
|
|||
/* Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
Modified by Allen Wirfs-Brock, Instantiations Inc 2/90
|
||||
*/
|
||||
/* This is the Assembler Pre-Processor
|
||||
Copyright (C) 1987 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* App, the assembler pre-processor. This pre-processor strips out excess
|
||||
spaces, turns single-quoted characters into a decimal constant, and turns
|
||||
# <number> <filename> <garbage> into a .line <number>\n.app-file <filename> pair.
|
||||
This needs better error-handling.
|
||||
*/
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "as.h" /* For BAD_CASE() only */
|
||||
|
||||
#if !defined(__STDC__) && !defined(const)
|
||||
#define const /* Nothing */
|
||||
#endif
|
||||
|
||||
static char lex [256];
|
||||
static char symbol_chars[] =
|
||||
"$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
/* These will go in BSS if not defined elsewhere, producing empty strings. */
|
||||
extern const char comment_chars[];
|
||||
extern const char line_comment_chars[];
|
||||
extern const char line_separator_chars[];
|
||||
|
||||
#define LEX_IS_SYMBOL_COMPONENT 1
|
||||
#define LEX_IS_WHITESPACE 2
|
||||
#define LEX_IS_LINE_SEPARATOR 3
|
||||
#define LEX_IS_COMMENT_START 4
|
||||
#define LEX_IS_LINE_COMMENT_START 5
|
||||
#define LEX_IS_TWOCHAR_COMMENT_1ST 6
|
||||
#define LEX_IS_TWOCHAR_COMMENT_2ND 7
|
||||
#define LEX_IS_STRINGQUOTE 8
|
||||
#define LEX_IS_COLON 9
|
||||
#define LEX_IS_NEWLINE 10
|
||||
#define LEX_IS_ONECHAR_QUOTE 11
|
||||
#define IS_SYMBOL_COMPONENT(c) (lex [c] == LEX_IS_SYMBOL_COMPONENT)
|
||||
#define IS_WHITESPACE(c) (lex [c] == LEX_IS_WHITESPACE)
|
||||
#define IS_LINE_SEPARATOR(c) (lex [c] == LEX_IS_LINE_SEPARATOR)
|
||||
#define IS_COMMENT(c) (lex [c] == LEX_IS_COMMENT_START)
|
||||
#define IS_LINE_COMMENT(c) (lex [c] == LEX_IS_LINE_COMMENT_START)
|
||||
#define IS_NEWLINE(c) (lex [c] == LEX_IS_NEWLINE)
|
||||
|
||||
void do_scrub_begin() {
|
||||
const char *p;
|
||||
|
||||
lex [' '] = LEX_IS_WHITESPACE;
|
||||
lex ['\t'] = LEX_IS_WHITESPACE;
|
||||
lex ['\n'] = LEX_IS_NEWLINE;
|
||||
lex [';'] = LEX_IS_LINE_SEPARATOR;
|
||||
lex ['"'] = LEX_IS_STRINGQUOTE;
|
||||
lex ['\''] = LEX_IS_ONECHAR_QUOTE;
|
||||
lex [':'] = LEX_IS_COLON;
|
||||
|
||||
/* Note that these override the previous defaults, e.g. if ';'
|
||||
is a comment char, then it isn't a line separator. */
|
||||
for (p =symbol_chars;*p;++p)
|
||||
lex[*p] = LEX_IS_SYMBOL_COMPONENT;
|
||||
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;
|
||||
for (p=line_separator_chars;*p;p++)
|
||||
lex[*p] = LEX_IS_LINE_SEPARATOR;
|
||||
|
||||
/* Only allow slash-star comments if slash is not in use */
|
||||
if (lex['/'] == 0) {
|
||||
lex ['/'] = LEX_IS_TWOCHAR_COMMENT_1ST;
|
||||
lex ['*'] = LEX_IS_TWOCHAR_COMMENT_2ND;
|
||||
}
|
||||
}
|
||||
|
||||
FILE *scrub_file;
|
||||
|
||||
int scrub_from_file() {
|
||||
return getc(scrub_file);
|
||||
}
|
||||
|
||||
void scrub_to_file(ch)
|
||||
int ch;
|
||||
{
|
||||
ungetc(ch,scrub_file);
|
||||
} /* scrub_to_file() */
|
||||
|
||||
char *scrub_string;
|
||||
char *scrub_last_string;
|
||||
|
||||
int scrub_from_string() {
|
||||
return scrub_string == scrub_last_string ? EOF : *scrub_string++;
|
||||
} /* scrub_from_string() */
|
||||
|
||||
void scrub_to_string(ch)
|
||||
int ch;
|
||||
{
|
||||
*--scrub_string=ch;
|
||||
} /* scrub_to_string() */
|
||||
|
||||
/* Saved state of the scrubber */
|
||||
static int state;
|
||||
static int old_state;
|
||||
static char *out_string;
|
||||
static char out_buf[20];
|
||||
static int add_newlines = 0;
|
||||
|
||||
/* Data structure for saving the state of app across #include's. Note that
|
||||
app is called asynchronously to the parsing of the .include's, so our
|
||||
state at the time .include is interpreted is completely unrelated.
|
||||
That's why we have to save it all. */
|
||||
|
||||
struct app_save {
|
||||
int state;
|
||||
int old_state;
|
||||
char *out_string;
|
||||
char out_buf[sizeof (out_buf)];
|
||||
int add_newlines;
|
||||
char *scrub_string;
|
||||
char *scrub_last_string;
|
||||
FILE *scrub_file;
|
||||
};
|
||||
|
||||
char *app_push() {
|
||||
register struct app_save *saved;
|
||||
|
||||
saved = (struct app_save *) xmalloc(sizeof (*saved));
|
||||
saved->state = state;
|
||||
saved->old_state = old_state;
|
||||
saved->out_string = out_string;
|
||||
bcopy(saved->out_buf, out_buf, sizeof(out_buf));
|
||||
saved->add_newlines = add_newlines;
|
||||
saved->scrub_string = scrub_string;
|
||||
saved->scrub_last_string = scrub_last_string;
|
||||
saved->scrub_file = scrub_file;
|
||||
|
||||
/* do_scrub_begin() is not useful, just wastes time. */
|
||||
return (char *)saved;
|
||||
}
|
||||
|
||||
void app_pop(arg)
|
||||
char *arg;
|
||||
{
|
||||
register struct app_save *saved = (struct app_save *)arg;
|
||||
|
||||
/* There is no do_scrub_end (). */
|
||||
state = saved->state;
|
||||
old_state = saved->old_state;
|
||||
out_string = saved->out_string;
|
||||
bcopy (out_buf, saved->out_buf, sizeof (out_buf));
|
||||
add_newlines = saved->add_newlines;
|
||||
scrub_string = saved->scrub_string;
|
||||
scrub_last_string = saved->scrub_last_string;
|
||||
scrub_file = saved->scrub_file;
|
||||
|
||||
free (arg);
|
||||
} /* app_pop() */
|
||||
|
||||
int do_scrub_next_char(get,unget)
|
||||
int (*get)();
|
||||
void (*unget)();
|
||||
{
|
||||
/*State 0: beginning of normal line
|
||||
1: After first whitespace on line (flush more white)
|
||||
2: After first non-white (opcode) on line (keep 1white)
|
||||
3: after second white on line (into operands) (flush white)
|
||||
4: after putting out a .line, put out digits
|
||||
5: parsing a string, then go to old-state
|
||||
6: putting out \ escape in a "d string.
|
||||
7: After putting out a .app-file, put out string.
|
||||
8: After putting out a .app-file string, flush until newline.
|
||||
-1: output string in out_string and go to the state in old_state
|
||||
-2: flush text until a '*' '/' is seen, then go to state old_state
|
||||
*/
|
||||
|
||||
register int ch, ch2;
|
||||
|
||||
switch (state) {
|
||||
case -1:
|
||||
ch= *out_string++;
|
||||
if(*out_string==0) {
|
||||
state=old_state;
|
||||
old_state=3;
|
||||
}
|
||||
return ch;
|
||||
|
||||
case -2:
|
||||
for(;;) {
|
||||
do {
|
||||
ch=(*get)();
|
||||
} while(ch!=EOF && ch!='\n' && ch!='*');
|
||||
if(ch=='\n' || ch==EOF)
|
||||
return ch;
|
||||
|
||||
/* At this point, ch must be a '*' */
|
||||
while ( (ch=(*get)()) == '*' ){
|
||||
;
|
||||
}
|
||||
if(ch==EOF || ch=='/')
|
||||
break;
|
||||
(*unget)(ch);
|
||||
}
|
||||
state=old_state;
|
||||
return ' ';
|
||||
|
||||
case 4:
|
||||
ch=(*get)();
|
||||
if(ch==EOF || (ch>='0' && ch<='9'))
|
||||
return ch;
|
||||
else {
|
||||
while(ch!=EOF && IS_WHITESPACE(ch))
|
||||
ch=(*get)();
|
||||
if(ch=='"') {
|
||||
(*unget)(ch);
|
||||
out_string="\n.app-file ";
|
||||
old_state=7;
|
||||
state= -1;
|
||||
return *out_string++;
|
||||
} else {
|
||||
while(ch!=EOF && ch!='\n')
|
||||
ch=(*get)();
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
case 5:
|
||||
ch=(*get)();
|
||||
if(ch=='"') {
|
||||
state=old_state;
|
||||
return '"';
|
||||
} else if(ch=='\\') {
|
||||
state=6;
|
||||
return ch;
|
||||
} else if(ch==EOF) {
|
||||
as_warn("End of file in string: inserted '\"'");
|
||||
state=old_state;
|
||||
(*unget)('\n');
|
||||
return '"';
|
||||
} else {
|
||||
return ch;
|
||||
}
|
||||
|
||||
case 6:
|
||||
state=5;
|
||||
ch=(*get)();
|
||||
switch(ch) {
|
||||
/* This is neet. Turn "string
|
||||
more string" into "string\n more string"
|
||||
*/
|
||||
case '\n':
|
||||
(*unget)('n');
|
||||
add_newlines++;
|
||||
return '\\';
|
||||
|
||||
case '"':
|
||||
case '\\':
|
||||
case 'b':
|
||||
case 'f':
|
||||
case 'n':
|
||||
case 'r':
|
||||
case 't':
|
||||
#ifdef BACKSLASH_V
|
||||
case 'v':
|
||||
#endif /* BACKSLASH_V */
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
break;
|
||||
|
||||
#ifdef ONLY_STANDARD_ESCAPES
|
||||
default:
|
||||
as_warn("Unknown escape '\\%c' in string: Ignored",ch);
|
||||
break;
|
||||
#else /* ONLY_STANDARD_ESCAPES */
|
||||
default:
|
||||
/* Accept \x as x for any x */
|
||||
break;
|
||||
#endif /* ONLY_STANDARD_ESCAPES */
|
||||
|
||||
case EOF:
|
||||
as_warn("End of file in string: '\"' inserted");
|
||||
return '"';
|
||||
}
|
||||
return ch;
|
||||
|
||||
case 7:
|
||||
ch=(*get)();
|
||||
state=5;
|
||||
old_state=8;
|
||||
return ch;
|
||||
|
||||
case 8:
|
||||
do ch= (*get)();
|
||||
while(ch!='\n');
|
||||
state=0;
|
||||
return ch;
|
||||
}
|
||||
|
||||
/* OK, we are somewhere in states 0 through 4 */
|
||||
|
||||
/* flushchar: */
|
||||
ch=(*get)();
|
||||
recycle:
|
||||
if (ch == EOF) {
|
||||
if (state != 0)
|
||||
as_warn("End of file not at end of a line: Newline inserted.");
|
||||
return ch;
|
||||
}
|
||||
|
||||
switch (lex[ch]) {
|
||||
case LEX_IS_WHITESPACE:
|
||||
do ch=(*get)();
|
||||
while(ch!=EOF && IS_WHITESPACE(ch));
|
||||
if(ch==EOF)
|
||||
return ch;
|
||||
if(IS_COMMENT(ch) || (state==0 && IS_LINE_COMMENT(ch)) || ch=='/' || IS_LINE_SEPARATOR(ch)) {
|
||||
goto recycle;
|
||||
}
|
||||
switch (state) {
|
||||
case 0: state++; goto recycle; /* Punted leading sp */
|
||||
case 1: BAD_CASE(state); /* We can't get here */
|
||||
case 2: state++; (*unget)(ch); return ' '; /* Sp after opco */
|
||||
case 3: goto recycle; /* Sp in operands */
|
||||
default: BAD_CASE(state);
|
||||
}
|
||||
break;
|
||||
|
||||
case LEX_IS_TWOCHAR_COMMENT_1ST:
|
||||
ch2=(*get)();
|
||||
if (ch2 != EOF && lex[ch2] == LEX_IS_TWOCHAR_COMMENT_2ND) {
|
||||
for(;;) {
|
||||
do {
|
||||
ch2=(*get)();
|
||||
if(ch2 != EOF && IS_NEWLINE(ch2))
|
||||
add_newlines++;
|
||||
} while(ch2!=EOF &&
|
||||
(lex[ch2] != LEX_IS_TWOCHAR_COMMENT_2ND));
|
||||
|
||||
while (ch2!=EOF &&
|
||||
(lex[ch2] == LEX_IS_TWOCHAR_COMMENT_2ND)){
|
||||
ch2=(*get)();
|
||||
}
|
||||
|
||||
if(ch2==EOF
|
||||
|| lex[ch2] == LEX_IS_TWOCHAR_COMMENT_1ST)
|
||||
break;
|
||||
(*unget)(ch);
|
||||
}
|
||||
if(ch2==EOF)
|
||||
as_warn("End of file in multiline comment");
|
||||
|
||||
ch = ' ';
|
||||
goto recycle;
|
||||
} else {
|
||||
if(ch2!=EOF)
|
||||
(*unget)(ch2);
|
||||
return ch;
|
||||
}
|
||||
break;
|
||||
|
||||
case LEX_IS_STRINGQUOTE:
|
||||
old_state=state;
|
||||
state=5;
|
||||
return ch;
|
||||
|
||||
case LEX_IS_ONECHAR_QUOTE:
|
||||
ch=(*get)();
|
||||
if(ch==EOF) {
|
||||
as_warn("End-of-file after a one-character quote; \000 inserted");
|
||||
ch=0;
|
||||
}
|
||||
sprintf(out_buf,"%d", (int)(unsigned char)ch);
|
||||
|
||||
/* None of these 'x constants for us. We want 'x'.
|
||||
*/
|
||||
if ( (ch=(*get)()) != '\'' ) {
|
||||
#ifdef REQUIRE_CHAR_CLOSE_QUOTE
|
||||
as_warn("Missing close quote: (assumed)");
|
||||
#else
|
||||
(*unget)(ch);
|
||||
#endif
|
||||
}
|
||||
|
||||
old_state=state;
|
||||
state= -1;
|
||||
out_string=out_buf;
|
||||
return *out_string++;
|
||||
|
||||
case LEX_IS_COLON:
|
||||
if(state!=3)
|
||||
state=0;
|
||||
return ch;
|
||||
|
||||
case LEX_IS_NEWLINE:
|
||||
/* Roll out a bunch of newlines from inside comments, etc. */
|
||||
if(add_newlines) {
|
||||
--add_newlines;
|
||||
(*unget)(ch);
|
||||
}
|
||||
/* fall thru into... */
|
||||
|
||||
case LEX_IS_LINE_SEPARATOR:
|
||||
state=0;
|
||||
return ch;
|
||||
|
||||
case LEX_IS_LINE_COMMENT_START:
|
||||
if (state != 0) /* Not at start of line, act normal */
|
||||
goto de_fault;
|
||||
do ch=(*get)();
|
||||
while(ch!=EOF && IS_WHITESPACE(ch));
|
||||
if(ch==EOF) {
|
||||
as_warn("EOF in comment: Newline inserted");
|
||||
return '\n';
|
||||
}
|
||||
if(ch<'0' || ch>'9') {
|
||||
/* Non-numerics: Eat whole comment line */
|
||||
while(ch!=EOF && !IS_NEWLINE(ch))
|
||||
ch=(*get)();
|
||||
if(ch==EOF)
|
||||
as_warn("EOF in Comment: Newline inserted");
|
||||
state=0;
|
||||
return '\n';
|
||||
}
|
||||
/* Numerics begin comment. Perhaps CPP `# 123 "filename"' */
|
||||
(*unget)(ch);
|
||||
old_state=4;
|
||||
state= -1;
|
||||
out_string=".line ";
|
||||
return *out_string++;
|
||||
|
||||
case LEX_IS_COMMENT_START:
|
||||
do ch=(*get)();
|
||||
while(ch!=EOF && !IS_NEWLINE(ch));
|
||||
if(ch==EOF)
|
||||
as_warn("EOF in comment: Newline inserted");
|
||||
state=0;
|
||||
return '\n';
|
||||
|
||||
default:
|
||||
de_fault:
|
||||
/* Some relatively `normal' character. */
|
||||
if(state==0) {
|
||||
state=2; /* Now seeing opcode */
|
||||
return ch;
|
||||
} else if(state==1) {
|
||||
state=2; /* Ditto */
|
||||
return ch;
|
||||
} else {
|
||||
return ch; /* Opcode or operands already */
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
char comment_chars[] = "|";
|
||||
char line_comment_chars[] = "#";
|
||||
|
||||
main()
|
||||
{
|
||||
int ch;
|
||||
|
||||
app_begin();
|
||||
while((ch=do_scrub_next_char(stdin))!=EOF)
|
||||
putc(ch,stdout);
|
||||
}
|
||||
|
||||
as_warn(str)
|
||||
char *str;
|
||||
{
|
||||
fputs(str,stderr);
|
||||
putc('\n',stderr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of app.c */
|
361
gas/as.c
Normal file
361
gas/as.c
Normal file
|
@ -0,0 +1,361 @@
|
|||
/* as.c - GAS main program.
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _POSIX_SOURCE
|
||||
#include <sys/types.h> /* For pid_t in signal.h */
|
||||
#endif
|
||||
#include <signal.h>
|
||||
|
||||
#define COMMON
|
||||
|
||||
#include "as.h"
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
/* This prototype for got_sig() is ansi. If you want
|
||||
anything else, then your compiler is lying to you when
|
||||
it says that it is __STDC__. If you want to change it,
|
||||
#ifdef protect it from those of us with real ansi
|
||||
compilers. */
|
||||
|
||||
#define SIGTY void
|
||||
|
||||
static void got_sig(int sig);
|
||||
static char *stralloc(char *str);
|
||||
static void perform_an_assembly_pass(int argc, char **argv);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
#ifndef SIGTY
|
||||
#define SIGTY int
|
||||
#endif
|
||||
|
||||
static SIGTY got_sig();
|
||||
static char *stralloc(); /* Make a (safe) copy of a string. */
|
||||
static void perform_an_assembly_pass();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#ifdef DONTDEF
|
||||
static char * gdb_symbol_file_name;
|
||||
long gdb_begin();
|
||||
#endif
|
||||
|
||||
char *myname; /* argv[0] */
|
||||
extern char version_string[];
|
||||
|
||||
int main(argc,argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int work_argc; /* variable copy of argc */
|
||||
char **work_argv; /* variable copy of argv */
|
||||
char *arg; /* an arg to program */
|
||||
char a; /* an arg flag (after -) */
|
||||
static const int sig[] = { SIGHUP, SIGINT, SIGPIPE, SIGTERM, 0};
|
||||
|
||||
for(a=0;sig[a]!=0;a++)
|
||||
if(signal(sig[a], SIG_IGN) != SIG_IGN)
|
||||
signal(sig[a], got_sig);
|
||||
|
||||
myname=argv[0];
|
||||
bzero (flagseen, sizeof(flagseen)); /* aint seen nothing yet */
|
||||
#ifndef OBJ_DEFAULT_OUTPUT_FILE_NAME
|
||||
#define OBJ_DEFAULT_OUTPUT_FILE_NAME "a.out"
|
||||
#endif /* OBJ_DEFAULT_OUTPUT_FILE_NAME */
|
||||
out_file_name = OBJ_DEFAULT_OUTPUT_FILE_NAME;
|
||||
|
||||
symbol_begin(); /* symbols.c */
|
||||
subsegs_begin(); /* subsegs.c */
|
||||
read_begin(); /* read.c */
|
||||
md_begin(); /* MACHINE.c */
|
||||
input_scrub_begin(); /* input_scrub.c */
|
||||
#ifdef DONTDEF
|
||||
gdb_symbol_file_name = 0;
|
||||
#endif
|
||||
/*
|
||||
* Parse arguments, but we are only interested in flags.
|
||||
* When we find a flag, we process it then make it's argv[] NULL.
|
||||
* This helps any future argv[] scanners avoid what we processed.
|
||||
* Since it is easy to do here we interpret the special arg "-"
|
||||
* to mean "use stdin" and we set that argv[] pointing to "".
|
||||
* After we have munged argv[], the only things left are source file
|
||||
* name(s) and ""(s) denoting stdin. These file names are used
|
||||
* (perhaps more than once) later.
|
||||
*/
|
||||
/* FIXME-SOMEDAY this should use getopt. */
|
||||
work_argc = argc-1; /* don't count argv[0] */
|
||||
work_argv = argv+1; /* skip argv[0] */
|
||||
for (;work_argc--;work_argv++) {
|
||||
arg = * work_argv; /* work_argv points to this argument */
|
||||
|
||||
if (*arg!='-') /* Filename. We need it later. */
|
||||
continue; /* Keep scanning args looking for flags. */
|
||||
if (arg[1] == '-' && arg[2] == 0) {
|
||||
/* "--" as an argument means read STDIN */
|
||||
/* on this scan, we don't want to think about filenames */
|
||||
* work_argv = ""; /* Code that means 'use stdin'. */
|
||||
continue;
|
||||
}
|
||||
/* This better be a switch. */
|
||||
arg ++; /*->letter. */
|
||||
|
||||
while ((a = * arg) != '\0') {/* scan all the 1-char flags */
|
||||
arg ++; /* arg->after letter. */
|
||||
a &= 0x7F; /* ascii only please */
|
||||
if (flagseen[a])
|
||||
as_tsktsk("%s: Flag option - %c has already been seen.", myname, a);
|
||||
flagseen[a] = 1;
|
||||
switch (a) {
|
||||
case 'f':
|
||||
break; /* -f means fast - no need for "app" preprocessor. */
|
||||
|
||||
case 'D':
|
||||
/* DEBUG is implemented: it debugs different */
|
||||
/* things to other people's assemblers. */
|
||||
break;
|
||||
|
||||
#ifdef DONTDEF
|
||||
case 'G': /* GNU AS switch: include gdbsyms. */
|
||||
if (*arg) /* Rest of argument is file-name. */
|
||||
gdb_symbol_file_name = stralloc (arg);
|
||||
else if (work_argc) { /* Next argument is file-name. */
|
||||
work_argc --;
|
||||
* work_argv = NULL; /* Not a source file-name. */
|
||||
gdb_symbol_file_name = * ++ work_argv;
|
||||
} else
|
||||
as_warn("%s: I expected a filename after -G", myname);
|
||||
arg = ""; /* Finished with this arg. */
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 'I': { /* Include file directory */
|
||||
|
||||
char *temp;
|
||||
if (*arg)
|
||||
temp = stralloc (arg);
|
||||
else if (work_argc) {
|
||||
* work_argv = NULL;
|
||||
work_argc--;
|
||||
temp = * ++ work_argv;
|
||||
} else
|
||||
as_warn("%s: I expected a filename after -I", myname);
|
||||
add_include_dir (temp);
|
||||
arg = ""; /* Finished with this arg. */
|
||||
break;
|
||||
}
|
||||
|
||||
#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 */
|
||||
case 'X':
|
||||
/* -X means treat warnings as errors */
|
||||
case 'Z':
|
||||
/* -Z means attempt to generate object file even after errors. */
|
||||
break;
|
||||
|
||||
default:
|
||||
--arg;
|
||||
if(md_parse_option(&arg,&work_argc,&work_argv)==0)
|
||||
as_warn("%s: I don't understand '%c' flag.", myname, a);
|
||||
if(arg && *arg)
|
||||
arg++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* We have just processed a "-..." arg, which was not a
|
||||
* file-name. Smash it so the
|
||||
* things that look for filenames won't ever see it.
|
||||
*
|
||||
* Whatever work_argv points to, it has already been used
|
||||
* as part of a flag, so DON'T re-use it as a filename.
|
||||
*/
|
||||
*work_argv = NULL; /* NULL means 'not a file-name' */
|
||||
}
|
||||
#ifdef DONTDEF
|
||||
if (gdb_begin(gdb_symbol_file_name) == 0)
|
||||
flagseen ['G'] = 0; /* Don't do any gdbsym stuff. */
|
||||
#endif
|
||||
/* Here with flags set up in flagseen[]. */
|
||||
perform_an_assembly_pass(argc,argv); /* Assemble it. */
|
||||
#ifdef TC_I960
|
||||
brtab_emit();
|
||||
#endif
|
||||
if (seen_at_least_1_file()
|
||||
&& !((had_warnings() && flagseen['Z'])
|
||||
|| had_errors() > 0)) {
|
||||
write_object_file(); /* relax() addresses then emit object file */
|
||||
} /* we also check in write_object_file() just before emit. */
|
||||
|
||||
input_scrub_end();
|
||||
md_end(); /* MACHINE.c */
|
||||
|
||||
#ifndef VMS
|
||||
return((had_warnings() && flagseen['Z'])
|
||||
|| had_errors() > 0); /* WIN */
|
||||
#else /* VMS */
|
||||
return(!((had_warnings() && flagseen['Z'])
|
||||
|| had_errors() > 0)); /* WIN */
|
||||
#endif /* VMS */
|
||||
|
||||
} /* main() */
|
||||
|
||||
|
||||
/* perform_an_assembly_pass()
|
||||
*
|
||||
* Here to attempt 1 pass over each input file.
|
||||
* We scan argv[*] looking for filenames or exactly "" which is
|
||||
* shorthand for stdin. Any argv that is NULL is not a file-name.
|
||||
* We set need_pass_2 TRUE if, after this, we still have unresolved
|
||||
* expressions of the form (unknown value)+-(unknown value).
|
||||
*
|
||||
* Note the un*x semantics: there is only 1 logical input file, but it
|
||||
* may be a catenation of many 'physical' input files.
|
||||
*/
|
||||
static void perform_an_assembly_pass(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int saw_a_file = 0;
|
||||
|
||||
text_fix_root = NULL;
|
||||
data_fix_root = NULL;
|
||||
need_pass_2 = 0;
|
||||
|
||||
subseg_new (SEG_TEXT, 0);
|
||||
|
||||
argv++; /* skip argv[0] */
|
||||
argc--; /* skip argv[0] */
|
||||
while (argc--) {
|
||||
if (*argv) { /* Is it a file-name argument? */
|
||||
saw_a_file++;
|
||||
/* argv->"" if stdin desired, else->filename */
|
||||
read_a_source_file(*argv);
|
||||
}
|
||||
argv++; /* completed that argv */
|
||||
}
|
||||
if(!saw_a_file)
|
||||
read_a_source_file("");
|
||||
} /* perform_an_assembly_pass() */
|
||||
|
||||
/*
|
||||
* stralloc()
|
||||
*
|
||||
* Allocate memory for a new copy of a string. Copy the string.
|
||||
* Return the address of the new string. Die if there is any error.
|
||||
*/
|
||||
|
||||
static char *
|
||||
stralloc (str)
|
||||
char * str;
|
||||
{
|
||||
register char * retval;
|
||||
register long len;
|
||||
|
||||
len = strlen (str) + 1;
|
||||
retval = xmalloc (len);
|
||||
(void) strcpy(retval, str);
|
||||
return(retval);
|
||||
}
|
||||
|
||||
#ifdef comment
|
||||
static void lose() {
|
||||
as_fatal("%s: 2nd pass not implemented - get your code from random(3)", myname);
|
||||
return;
|
||||
} /* lose() */
|
||||
#endif /* comment */
|
||||
|
||||
static SIGTY
|
||||
got_sig(sig)
|
||||
int sig;
|
||||
{
|
||||
static here_before = 0;
|
||||
|
||||
as_bad("Interrupted by signal %d", sig);
|
||||
if(here_before++)
|
||||
exit(1);
|
||||
return((SIGTY) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end: as.c */
|
397
gas/as.h
Normal file
397
gas/as.h
Normal file
|
@ -0,0 +1,397 @@
|
|||
/* as.h - global header file
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
#define GAS 1
|
||||
|
||||
#include "host.h"
|
||||
#include "flonum.h"
|
||||
|
||||
#ifndef __STDC__
|
||||
#define volatile /**/
|
||||
#ifndef const
|
||||
#define const /**/
|
||||
#endif /* const */
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define alloca __builtin_alloca
|
||||
#define register
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#ifndef __LINE__
|
||||
#define __LINE__ "unknown"
|
||||
#endif /* __LINE__ */
|
||||
|
||||
#ifndef __FILE__
|
||||
#define __FILE__ "unknown"
|
||||
#endif /* __FILE__ */
|
||||
|
||||
/*
|
||||
* I think this stuff is largely out of date. xoxorich.
|
||||
*
|
||||
* CAPITALISED names are #defined.
|
||||
* "lowercaseH" is #defined if "lowercase.h" has been #include-d.
|
||||
* "lowercaseT" is a typedef of "lowercase" objects.
|
||||
* "lowercaseP" is type "pointer to object of type 'lowercase'".
|
||||
* "lowercaseS" is typedef struct ... lowercaseS.
|
||||
*
|
||||
* #define DEBUG to enable all the "know" assertion tests.
|
||||
* #define SUSPECT when debugging.
|
||||
* #define COMMON as "extern" for all modules except one, where you #define
|
||||
* COMMON as "".
|
||||
* If TEST is #defined, then we are testing a module: #define COMMON as "".
|
||||
*/
|
||||
|
||||
/* These #defines are for parameters of entire assembler. */
|
||||
|
||||
/* #define SUSPECT JF remove for speed testing */
|
||||
/* These #includes are for type definitions etc. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define obstack_chunk_alloc xmalloc
|
||||
#define obstack_chunk_free xfree
|
||||
|
||||
#define BAD_CASE(value) \
|
||||
{ \
|
||||
as_fatal("Case value %d unexpected at line %d of file \"%s\"\n", \
|
||||
value, __LINE__, __FILE__); \
|
||||
}
|
||||
|
||||
|
||||
/* These are assembler-wide concepts */
|
||||
|
||||
|
||||
#ifndef COMMON
|
||||
#ifdef TEST
|
||||
#define COMMON /* declare our COMMONs storage here. */
|
||||
#else
|
||||
#define COMMON extern /* our commons live elswhere */
|
||||
#endif
|
||||
#endif
|
||||
/* COMMON now defined */
|
||||
#define DEBUG /* temporary */
|
||||
|
||||
#ifdef DEBUG
|
||||
#undef NDEBUG
|
||||
#define know(p) assert(p) /* Verify our assumptions! */
|
||||
#else
|
||||
#define know(p) /* know() checks are no-op.ed */
|
||||
#endif
|
||||
|
||||
|
||||
#define xfree free
|
||||
|
||||
/* input_scrub.c */
|
||||
|
||||
/*
|
||||
* Supplies sanitised buffers to read.c.
|
||||
* Also understands printing line-number part of error messages.
|
||||
*/
|
||||
|
||||
|
||||
/* subsegs.c Sub-segments. Also, segment(=expression type)s.*/
|
||||
|
||||
/*
|
||||
* This table describes the use of segments as EXPRESSION types.
|
||||
*
|
||||
* X_seg X_add_symbol X_subtract_symbol X_add_number
|
||||
* SEG_ABSENT no (legal) expression
|
||||
* SEG_PASS1 no (defined) "
|
||||
* SEG_BIG * > 32 bits const.
|
||||
* SEG_ABSOLUTE 0
|
||||
* SEG_DATA * 0
|
||||
* SEG_TEXT * 0
|
||||
* SEG_BSS * 0
|
||||
* SEG_UNKNOWN * 0
|
||||
* SEG_DIFFERENCE 0 * 0
|
||||
* SEG_REGISTER *
|
||||
*
|
||||
* The blank fields MUST be 0, and are nugatory.
|
||||
* The '0' fields MAY be 0. The '*' fields MAY NOT be 0.
|
||||
*
|
||||
* SEG_BIG: X_add_number is < 0 if the result is in
|
||||
* generic_floating_point_number. The value is -'c' where c is the
|
||||
* character that introduced the constant. e.g. "0f6.9" will have -'f'
|
||||
* as a X_add_number value.
|
||||
* X_add_number > 0 is a count of how many littlenums it took to
|
||||
* represent a bignum.
|
||||
* SEG_DIFFERENCE:
|
||||
* If segments of both symbols are known, they are the same segment.
|
||||
* X_add_symbol != X_sub_symbol (then we just cancel them, => SEG_ABSOLUTE).
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
SEG_ABSOLUTE = 0,
|
||||
SEG_TEXT,
|
||||
SEG_DATA,
|
||||
SEG_BSS,
|
||||
SEG_UNKNOWN,
|
||||
SEG_ABSENT, /* Mythical Segment (absent): NO expression seen. */
|
||||
SEG_PASS1, /* Mythical Segment: Need another pass. */
|
||||
SEG_GOOF, /* Only happens if AS has a logic error. */
|
||||
/* Invented so we don't crash printing */
|
||||
/* error message involving weird segment. */
|
||||
SEG_BIG, /* Bigger than 32 bits constant. */
|
||||
SEG_DIFFERENCE, /* Mythical Segment: absolute difference. */
|
||||
SEG_DEBUG, /* Debug segment */
|
||||
SEG_NTV, /* Transfert vector preload segment */
|
||||
SEG_PTV, /* Transfert vector postload segment */
|
||||
SEG_REGISTER, /* Mythical: a register-valued expression */
|
||||
} segT;
|
||||
|
||||
#define SEG_MAXIMUM_ORDINAL (SEG_REGISTER)
|
||||
|
||||
typedef int subsegT;
|
||||
|
||||
COMMON subsegT now_subseg;
|
||||
/* What subseg we are accreting now? */
|
||||
|
||||
|
||||
COMMON segT now_seg;
|
||||
/* Segment our instructions emit to. */
|
||||
/* Only OK values are SEG_TEXT or SEG_DATA. */
|
||||
|
||||
|
||||
extern char *const seg_name[];
|
||||
extern int section_alignment[];
|
||||
|
||||
|
||||
/* relax() */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
rs_fill, /* Variable chars to be repeated fr_offset */
|
||||
/* times. Fr_symbol unused. */
|
||||
/* Used with fr_offset == 0 for a constant */
|
||||
/* length frag. */
|
||||
|
||||
rs_align, /* Align: Fr_offset: power of 2. */
|
||||
/* 1 variable char: fill character. */
|
||||
rs_org, /* Org: Fr_offset, fr_symbol: address. */
|
||||
/* 1 variable char: fill character. */
|
||||
|
||||
rs_machine_dependent,
|
||||
#ifndef WORKING_DOT_WORD
|
||||
rs_broken_word, /* JF: gunpoint */
|
||||
#endif
|
||||
}
|
||||
relax_stateT;
|
||||
|
||||
/* typedef unsigned char relax_substateT; */
|
||||
/* JF this is more likely to leave the end of a struct frag on an align
|
||||
boundry. Be very careful with this. */
|
||||
typedef unsigned long relax_substateT;
|
||||
|
||||
typedef unsigned long relax_addressT;/* Enough bits for address. */
|
||||
/* Still an integer type. */
|
||||
|
||||
|
||||
/* frags.c */
|
||||
|
||||
/*
|
||||
* A code fragment (frag) is some known number of chars, followed by some
|
||||
* unknown number of chars. Typically the unknown number of chars is an
|
||||
* instruction address whose size is yet unknown. We always know the greatest
|
||||
* possible size the unknown number of chars may become, and reserve that
|
||||
* much room at the end of the frag.
|
||||
* Once created, frags do not change address during assembly.
|
||||
* We chain the frags in (a) forward-linked list(s). The object-file address
|
||||
* of the 1st char of a frag is generally not known until after relax().
|
||||
* Many things at assembly time describe an address by {object-file-address
|
||||
* of a particular frag}+offset.
|
||||
|
||||
BUG: it may be smarter to have a single pointer off to various different
|
||||
notes for different frag kinds. See how code pans
|
||||
*/
|
||||
struct frag /* a code fragment */
|
||||
{
|
||||
unsigned long fr_address; /* Object file address. */
|
||||
struct frag *fr_next; /* Chain forward; ascending address order. */
|
||||
/* Rooted in frch_root. */
|
||||
|
||||
long fr_fix; /* (Fixed) number of chars we know we have. */
|
||||
/* May be 0. */
|
||||
long fr_var; /* (Variable) number of chars after above. */
|
||||
/* May be 0. */
|
||||
struct symbol *fr_symbol; /* For variable-length tail. */
|
||||
long fr_offset; /* For variable-length tail. */
|
||||
char *fr_opcode; /*->opcode low addr byte,for relax()ation*/
|
||||
relax_stateT fr_type; /* What state is my tail in? */
|
||||
relax_substateT fr_subtype;
|
||||
/* These are needed only on the NS32K machines */
|
||||
char fr_pcrel_adjust;
|
||||
char fr_bsr;
|
||||
char fr_literal [1]; /* Chars begin here. */
|
||||
/* One day we will compile fr_literal[0]. */
|
||||
};
|
||||
#define SIZEOF_STRUCT_FRAG \
|
||||
((int)zero_address_frag.fr_literal-(int)&zero_address_frag)
|
||||
/* We want to say fr_literal[0] above. */
|
||||
|
||||
typedef struct frag fragS;
|
||||
|
||||
COMMON fragS * frag_now; /* -> current frag we are building. */
|
||||
/* This frag is incomplete. */
|
||||
/* It is, however, included in frchain_now. */
|
||||
/* Frag_now->fr_fix is bogus. Use: */
|
||||
/* Virtual frag_now->fr_fix==obstack_next_free(&frags)-frag_now->fr_literal.*/
|
||||
|
||||
COMMON fragS zero_address_frag; /* For foreign-segment symbol fixups. */
|
||||
COMMON fragS bss_address_frag; /* For local common (N_BSS segment) fixups. */
|
||||
|
||||
/* main program "as.c" (command arguments etc) */
|
||||
|
||||
COMMON char
|
||||
flagseen[128]; /* ['x'] TRUE if "-x" seen. */
|
||||
|
||||
COMMON char *
|
||||
out_file_name; /* name of emitted object file */
|
||||
|
||||
COMMON int need_pass_2; /* TRUE if we need a second pass. */
|
||||
|
||||
typedef struct {
|
||||
char * poc_name; /* assembler mnemonic, lower case, no '.' */
|
||||
void (*poc_handler)(); /* Do the work */
|
||||
int poc_val; /* Value to pass to handler */
|
||||
} pseudo_typeS;
|
||||
|
||||
#if defined(__STDC__) & !defined(NO_STDARG)
|
||||
|
||||
int had_errors(void);
|
||||
int had_warnings(void);
|
||||
void as_bad(const char *Format, ...);
|
||||
void as_fatal(const char *Format, ...);
|
||||
void as_tsktsk(const char *Format, ...);
|
||||
void as_warn(const char *Format, ...);
|
||||
|
||||
#else
|
||||
|
||||
int had_errors();
|
||||
int had_warnings();
|
||||
void as_bad();
|
||||
void as_fatal();
|
||||
void as_tsktsk();
|
||||
void as_warn();
|
||||
|
||||
#endif /* __STDC__ & !NO_STDARG */
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
char *app_push(void);
|
||||
char *atof_ieee(char *str, int what_kind, LITTLENUM_TYPE *words);
|
||||
char *input_scrub_include_file(char *filename, char *position);
|
||||
char *input_scrub_new_file(char *filename);
|
||||
char *input_scrub_next_buffer(char **bufp);
|
||||
char *strstr(const char *s, const char *wanted);
|
||||
char *xmalloc(int size);
|
||||
char *xrealloc(char *ptr, long n);
|
||||
int do_scrub_next_char(int (*get)(), void (*unget)());
|
||||
int gen_to_words(LITTLENUM_TYPE *words, int precision, long exponent_bits);
|
||||
int had_err(void);
|
||||
int had_errors(void);
|
||||
int had_warnings(void);
|
||||
int ignore_input(void);
|
||||
int scrub_from_file(void);
|
||||
int scrub_from_file(void);
|
||||
int scrub_from_string(void);
|
||||
int seen_at_least_1_file(void);
|
||||
void app_pop(char *arg);
|
||||
void as_howmuch(FILE *stream);
|
||||
void as_perror(char *gripe, char *filename);
|
||||
void as_where(void);
|
||||
void bump_line_counters(void);
|
||||
void do_scrub_begin(void);
|
||||
void input_scrub_begin(void);
|
||||
void input_scrub_close(void);
|
||||
void input_scrub_end(void);
|
||||
void int_to_gen(long x);
|
||||
void new_logical_line(char *fname, int line_number);
|
||||
void scrub_to_file(int ch);
|
||||
void scrub_to_string(int ch);
|
||||
void subseg_change(segT seg, int subseg);
|
||||
void subseg_new(segT seg, subsegT subseg);
|
||||
void subsegs_begin(void);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
char *app_push();
|
||||
char *atof_ieee();
|
||||
char *input_scrub_include_file();
|
||||
char *input_scrub_new_file();
|
||||
char *input_scrub_next_buffer();
|
||||
char *strstr();
|
||||
char *xmalloc();
|
||||
char *xrealloc();
|
||||
int do_scrub_next_char();
|
||||
int gen_to_words();
|
||||
int had_err();
|
||||
int had_errors();
|
||||
int had_warnings();
|
||||
int ignore_input();
|
||||
int scrub_from_file();
|
||||
int scrub_from_file();
|
||||
int scrub_from_string();
|
||||
int seen_at_least_1_file();
|
||||
void app_pop();
|
||||
void as_howmuch();
|
||||
void as_perror();
|
||||
void as_where();
|
||||
void bump_line_counters();
|
||||
void do_scrub_begin();
|
||||
void input_scrub_begin();
|
||||
void input_scrub_close();
|
||||
void input_scrub_end();
|
||||
void int_to_gen();
|
||||
void new_logical_line();
|
||||
void scrub_to_file();
|
||||
void scrub_to_string();
|
||||
void subseg_change();
|
||||
void subseg_new();
|
||||
void subsegs_begin();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
/* this one starts the chain of target dependant headers */
|
||||
#include "targ-env.h"
|
||||
|
||||
/* these define types needed by the interfaces */
|
||||
#include "struc-symbol.h"
|
||||
#include "reloc.h"
|
||||
#include "write.h"
|
||||
#include "expr.h"
|
||||
#include "frags.h"
|
||||
#include "hash.h"
|
||||
#include "read.h"
|
||||
#include "symbols.h"
|
||||
|
||||
#include "tc.h"
|
||||
#include "obj.h"
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end: as.h */
|
549
gas/atof-generic.c
Normal file
549
gas/atof-generic.c
Normal file
|
@ -0,0 +1,549 @@
|
|||
/* atof_generic.c - turn a string of digits into a Flonum
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "as.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)
|
||||
#endif
|
||||
|
||||
/* #define FALSE (0) */
|
||||
/* #define TRUE (1) */
|
||||
|
||||
/***********************************************************************\
|
||||
* *
|
||||
* Given a string of decimal digits , with optional decimal *
|
||||
* mark and optional decimal exponent (place value) of the *
|
||||
* lowest_order decimal digit: produce a floating point *
|
||||
* number. The number is 'generic' floating point: our *
|
||||
* caller will encode it for a specific machine architecture. *
|
||||
* *
|
||||
* Assumptions *
|
||||
* uses base (radix) 2 *
|
||||
* this machine uses 2's complement binary integers *
|
||||
* target flonums use " " " " *
|
||||
* target flonums exponents fit in a long *
|
||||
* *
|
||||
\***********************************************************************/
|
||||
|
||||
/*
|
||||
|
||||
Syntax:
|
||||
|
||||
<flonum> ::= <optional-sign> <decimal-number> <optional-exponent>
|
||||
<optional-sign> ::= '+' | '-' | {empty}
|
||||
<decimal-number> ::= <integer>
|
||||
| <integer> <radix-character>
|
||||
| <integer> <radix-character> <integer>
|
||||
| <radix-character> <integer>
|
||||
<optional-exponent> ::= {empty} | <exponent-character> <optional-sign> <integer>
|
||||
<integer> ::= <digit> | <digit> <integer>
|
||||
<digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
|
||||
<exponent-character> ::= {one character from "string_of_decimal_exponent_marks"}
|
||||
<radix-character> ::= {one character from "string_of_decimal_marks"}
|
||||
|
||||
*/
|
||||
|
||||
int /* 0 if OK */
|
||||
atof_generic (
|
||||
address_of_string_pointer, /* return pointer to just AFTER number we read. */
|
||||
string_of_decimal_marks, /* At most one per number. */
|
||||
string_of_decimal_exponent_marks,
|
||||
address_of_generic_floating_point_number)
|
||||
|
||||
char * * address_of_string_pointer;
|
||||
const char * string_of_decimal_marks;
|
||||
const char * string_of_decimal_exponent_marks;
|
||||
FLONUM_TYPE * address_of_generic_floating_point_number;
|
||||
|
||||
{
|
||||
|
||||
int return_value; /* 0 means OK. */
|
||||
char * first_digit;
|
||||
/* char * last_digit; JF unused */
|
||||
int number_of_digits_before_decimal;
|
||||
int number_of_digits_after_decimal;
|
||||
long decimal_exponent;
|
||||
int number_of_digits_available;
|
||||
char digits_sign_char;
|
||||
|
||||
{
|
||||
/*
|
||||
* Scan the input string, abstracting (1)digits (2)decimal mark (3) exponent.
|
||||
* It would be simpler to modify the string, but we don't; just to be nice
|
||||
* to caller.
|
||||
* We need to know how many digits we have, so we can allocate space for
|
||||
* the digits' value.
|
||||
*/
|
||||
|
||||
char * p;
|
||||
char c;
|
||||
int seen_significant_digit;
|
||||
|
||||
first_digit = * address_of_string_pointer;
|
||||
c= *first_digit;
|
||||
if (c=='-' || c=='+')
|
||||
{
|
||||
digits_sign_char = c;
|
||||
first_digit ++;
|
||||
}
|
||||
else
|
||||
digits_sign_char = '+';
|
||||
|
||||
if( (first_digit[0]=='n' || first_digit[0]=='N')
|
||||
&& (first_digit[1]=='a' || first_digit[1]=='A')
|
||||
&& (first_digit[2]=='n' || first_digit[2]=='N')) {
|
||||
address_of_generic_floating_point_number->sign=0;
|
||||
address_of_generic_floating_point_number->exponent=0;
|
||||
address_of_generic_floating_point_number->leader=address_of_generic_floating_point_number->low;
|
||||
(*address_of_string_pointer)=first_digit+3;
|
||||
return 0;
|
||||
}
|
||||
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 = 0;
|
||||
for (p = first_digit;
|
||||
((c = * p) != '\0')
|
||||
&& (!c || ! strchr (string_of_decimal_marks, c) )
|
||||
&& (!c || ! strchr (string_of_decimal_exponent_marks, c) );
|
||||
p ++)
|
||||
{
|
||||
if (isdigit(c))
|
||||
{
|
||||
if (seen_significant_digit || c > '0')
|
||||
{
|
||||
number_of_digits_before_decimal ++;
|
||||
seen_significant_digit = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_digit++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break; /* p -> char after pre-decimal digits. */
|
||||
}
|
||||
} /* For each digit before decimal mark. */
|
||||
|
||||
#ifndef OLD_FLOAT_READS
|
||||
/* Ignore trailing 0's after the decimal point. The original code here
|
||||
* (ifdef'd out) does not do this, and numbers like
|
||||
* 4.29496729600000000000e+09 (2**31)
|
||||
* come out inexact for some reason related to length of the digit
|
||||
* string.
|
||||
*/
|
||||
if ( c && strchr(string_of_decimal_marks,c) ){
|
||||
int zeros = 0; /* Length of current string of zeros */
|
||||
|
||||
for ( p++; (c = *p) && isdigit(c); p++ ){
|
||||
if ( c == '0'){
|
||||
zeros++;
|
||||
} else {
|
||||
number_of_digits_after_decimal += 1 + zeros;
|
||||
zeros = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (c && strchr (string_of_decimal_marks, c))
|
||||
{
|
||||
for (p ++;
|
||||
((c = * p) != '\0')
|
||||
&& (!c || ! strchr (string_of_decimal_exponent_marks, c) );
|
||||
p ++)
|
||||
{
|
||||
if (isdigit(c))
|
||||
{
|
||||
number_of_digits_after_decimal ++; /* This may be retracted below. */
|
||||
if (/* seen_significant_digit || */ c > '0')
|
||||
{
|
||||
seen_significant_digit = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ! seen_significant_digit)
|
||||
{
|
||||
number_of_digits_after_decimal = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} /* For each digit after decimal mark. */
|
||||
}
|
||||
while(number_of_digits_after_decimal && first_digit[number_of_digits_before_decimal+number_of_digits_after_decimal]=='0')
|
||||
--number_of_digits_after_decimal;
|
||||
/* last_digit = p; JF unused */
|
||||
#endif
|
||||
|
||||
if (c && strchr (string_of_decimal_exponent_marks, c) )
|
||||
{
|
||||
char digits_exponent_sign_char;
|
||||
|
||||
c = * ++ p;
|
||||
if (c && strchr ("+-",c))
|
||||
{
|
||||
digits_exponent_sign_char = c;
|
||||
c = * ++ p;
|
||||
}
|
||||
else
|
||||
{
|
||||
digits_exponent_sign_char = '+';
|
||||
}
|
||||
for (;
|
||||
(c);
|
||||
c = * ++ p)
|
||||
{
|
||||
if (isdigit(c))
|
||||
{
|
||||
decimal_exponent = decimal_exponent * 10 + c - '0';
|
||||
/*
|
||||
* BUG! If we overflow here, we lose!
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (digits_exponent_sign_char == '-')
|
||||
{
|
||||
decimal_exponent = - decimal_exponent;
|
||||
}
|
||||
}
|
||||
* address_of_string_pointer = p;
|
||||
}
|
||||
|
||||
number_of_digits_available =
|
||||
number_of_digits_before_decimal
|
||||
+ number_of_digits_after_decimal;
|
||||
return_value = 0;
|
||||
if (number_of_digits_available == 0)
|
||||
{
|
||||
address_of_generic_floating_point_number -> exponent = 0; /* Not strictly necessary */
|
||||
address_of_generic_floating_point_number -> leader
|
||||
= -1 + address_of_generic_floating_point_number -> low;
|
||||
address_of_generic_floating_point_number -> sign = digits_sign_char;
|
||||
/* We have just concocted (+/-)0.0E0 */
|
||||
}
|
||||
else
|
||||
{
|
||||
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 carry;
|
||||
LITTLENUM_TYPE * littlenum_pointer;
|
||||
LITTLENUM_TYPE * littlenum_limit;
|
||||
|
||||
littlenum_limit
|
||||
= digits_binary_low
|
||||
+ more_than_enough_littlenums_for_digits
|
||||
- 1;
|
||||
carry = c - '0'; /* char -> binary */
|
||||
for (littlenum_pointer = digits_binary_low;
|
||||
littlenum_pointer <= littlenum_limit;
|
||||
littlenum_pointer ++)
|
||||
{
|
||||
long work;
|
||||
|
||||
work = carry + 10 * (long)(*littlenum_pointer);
|
||||
* littlenum_pointer = work & LITTLENUM_MASK;
|
||||
carry = work >> LITTLENUM_NUMBER_OF_BITS;
|
||||
}
|
||||
if (carry != 0)
|
||||
{
|
||||
/*
|
||||
* We have a GROSS internal error.
|
||||
* This should never happen.
|
||||
*/
|
||||
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 */
|
77
gas/bignum-copy.c
Normal file
77
gas/bignum-copy.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* bignum_copy.c - copy a bignum
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
#include "as.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 */
|
47
gas/bignum.h
Normal file
47
gas/bignum.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* 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 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 */
|
128
gas/cond.c
Normal file
128
gas/cond.c
Normal file
|
@ -0,0 +1,128 @@
|
|||
/* cond.c - conditional assembly pseudo-ops, and .include
|
||||
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
#include "as.h"
|
||||
|
||||
#include "obstack.h"
|
||||
|
||||
void s_ifdef(arg)
|
||||
int arg;
|
||||
{
|
||||
/* register char c; */
|
||||
register char *name; /* points to name of symbol */
|
||||
register struct symbol * symbolP; /* Points to symbol */
|
||||
|
||||
SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */
|
||||
name = input_line_pointer;
|
||||
if (!is_name_beginner(*name)) {
|
||||
as_bad("invalid identifier for .ifdef");
|
||||
obstack_1grow (&cond_obstack, 0);
|
||||
} else {
|
||||
get_symbol_end();
|
||||
++input_line_pointer;
|
||||
symbolP = symbol_find(name);
|
||||
|
||||
/* ??? Should we try to optimize such that if we hit a .endif
|
||||
before a .else, we don't need to push state? */
|
||||
obstack_1grow(&cond_obstack, (symbolP != 0) ^ arg);
|
||||
}
|
||||
} /* s_ifdef() */
|
||||
|
||||
/* This is allocated to grow and shrink as .ifdef/.endif pairs
|
||||
are scanned. When the top element is nonzero, it means
|
||||
we should accept input. Otherwise, we should ignore input. */
|
||||
struct obstack cond_obstack;
|
||||
|
||||
void s_if(arg)
|
||||
int arg;
|
||||
{
|
||||
expressionS operand;
|
||||
|
||||
SKIP_WHITESPACE(); /* Leading whitespace is part of operand. */
|
||||
expr(0, &operand);
|
||||
|
||||
if (operand.X_add_symbol != NULL
|
||||
|| operand.X_subtract_symbol != NULL)
|
||||
as_bad("non-constant expression in .if statement");
|
||||
|
||||
/* If the above error is signaled, this will dispatch
|
||||
using an undefined result. No big deal. */
|
||||
obstack_1grow(&cond_obstack, (operand.X_add_number != 0) ^ arg);
|
||||
} /* s_if() */
|
||||
|
||||
void s_endif(arg)
|
||||
int arg;
|
||||
{
|
||||
char *base = obstack_base(&cond_obstack);
|
||||
char *ptr = obstack_next_free(&cond_obstack);
|
||||
|
||||
if (ptr-1 == base) {
|
||||
as_bad("unbalanced .endif");
|
||||
} else {
|
||||
obstack_free(&cond_obstack, ptr-1);
|
||||
cond_obstack.object_base = base;
|
||||
}
|
||||
} /* s_endif() */
|
||||
|
||||
void s_else(arg)
|
||||
int arg;
|
||||
{
|
||||
char *ptr = obstack_next_free(&cond_obstack);
|
||||
if (ptr-1 == obstack_base(&cond_obstack)) {
|
||||
as_bad(".else without matching .if");
|
||||
} else {
|
||||
ptr[-1] = !ptr[-1];
|
||||
}
|
||||
} /* s_else() */
|
||||
|
||||
void s_ifeqs(arg)
|
||||
int arg;
|
||||
{
|
||||
as_bad("ifeqs not implemented.");
|
||||
} /* s_ifeqs() */
|
||||
|
||||
void s_end(arg)
|
||||
int arg;
|
||||
{
|
||||
;
|
||||
} /* s_end() */
|
||||
|
||||
int ignore_input() {
|
||||
char *ptr = obstack_next_free (&cond_obstack);
|
||||
|
||||
/* We cannot ignore certain pseudo ops. */
|
||||
if (input_line_pointer[-1] == '.')
|
||||
{
|
||||
if (input_line_pointer[0] == 'i'
|
||||
&& (!strncmp (input_line_pointer, "if", 2)
|
||||
|| !strncmp (input_line_pointer, "ifdef", 5)
|
||||
|| !strncmp (input_line_pointer, "ifndef", 6)))
|
||||
return 0;
|
||||
if (input_line_pointer[0] == 'e'
|
||||
&& (!strncmp (input_line_pointer, "else", 4)
|
||||
|| !strncmp (input_line_pointer, "endif", 5)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (ptr[-1] == 0);
|
||||
} /* ignore_input() */
|
||||
|
||||
/* end of cond.c */
|
511
gas/config/atof-ieee.c
Normal file
511
gas/config/atof-ieee.c
Normal file
|
@ -0,0 +1,511 @@
|
|||
/* 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 "as.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. */
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL (0)
|
||||
#endif
|
||||
|
||||
extern char EXP_CHARS[];
|
||||
/* Precision in LittleNums. */
|
||||
#define MAX_PRECISION (6)
|
||||
#define F_PRECISION (2)
|
||||
#define D_PRECISION (4)
|
||||
#define X_PRECISION (6)
|
||||
#define P_PRECISION (6)
|
||||
|
||||
/* Length in LittleNums of guard bits. */
|
||||
#define GUARD (2)
|
||||
|
||||
static unsigned long mask [] = {
|
||||
0x00000000,
|
||||
0x00000001,
|
||||
0x00000003,
|
||||
0x00000007,
|
||||
0x0000000f,
|
||||
0x0000001f,
|
||||
0x0000003f,
|
||||
0x0000007f,
|
||||
0x000000ff,
|
||||
0x000001ff,
|
||||
0x000003ff,
|
||||
0x000007ff,
|
||||
0x00000fff,
|
||||
0x00001fff,
|
||||
0x00003fff,
|
||||
0x00007fff,
|
||||
0x0000ffff,
|
||||
0x0001ffff,
|
||||
0x0003ffff,
|
||||
0x0007ffff,
|
||||
0x000fffff,
|
||||
0x001fffff,
|
||||
0x003fffff,
|
||||
0x007fffff,
|
||||
0x00ffffff,
|
||||
0x01ffffff,
|
||||
0x03ffffff,
|
||||
0x07ffffff,
|
||||
0x0fffffff,
|
||||
0x1fffffff,
|
||||
0x3fffffff,
|
||||
0x7fffffff,
|
||||
0xffffffff
|
||||
};
|
||||
|
||||
|
||||
static int bits_left_in_littlenum;
|
||||
static int littlenums_left;
|
||||
static LITTLENUM_TYPE *littlenum_pointer;
|
||||
|
||||
static int
|
||||
next_bits (number_of_bits)
|
||||
int number_of_bits;
|
||||
{
|
||||
int return_value;
|
||||
|
||||
if(!littlenums_left)
|
||||
return 0;
|
||||
if (number_of_bits >= bits_left_in_littlenum)
|
||||
{
|
||||
return_value = mask [bits_left_in_littlenum] & *littlenum_pointer;
|
||||
number_of_bits -= bits_left_in_littlenum;
|
||||
return_value <<= number_of_bits;
|
||||
if(--littlenums_left) {
|
||||
bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits;
|
||||
littlenum_pointer --;
|
||||
return_value |= (*littlenum_pointer>>bits_left_in_littlenum) & mask[number_of_bits];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bits_left_in_littlenum -= number_of_bits;
|
||||
return_value = mask [number_of_bits] & (*littlenum_pointer>>bits_left_in_littlenum);
|
||||
}
|
||||
return (return_value);
|
||||
}
|
||||
|
||||
/* Num had better be less than LITTLENUM_NUMBER_OF_BITS */
|
||||
static void
|
||||
unget_bits(num)
|
||||
int num;
|
||||
{
|
||||
if(!littlenums_left) {
|
||||
++littlenum_pointer;
|
||||
++littlenums_left;
|
||||
bits_left_in_littlenum=num;
|
||||
} else if(bits_left_in_littlenum+num>LITTLENUM_NUMBER_OF_BITS) {
|
||||
bits_left_in_littlenum= num-(LITTLENUM_NUMBER_OF_BITS-bits_left_in_littlenum);
|
||||
++littlenum_pointer;
|
||||
++littlenums_left;
|
||||
} else
|
||||
bits_left_in_littlenum+=num;
|
||||
}
|
||||
|
||||
static void
|
||||
make_invalid_floating_point_number (words)
|
||||
LITTLENUM_TYPE * words;
|
||||
{
|
||||
as_bad("cannot create floating-point number");
|
||||
words[0]= ((unsigned)-1)>>1; /* Zero the leftmost bit */
|
||||
words[1]= -1;
|
||||
words[2]= -1;
|
||||
words[3]= -1;
|
||||
words[4]= -1;
|
||||
words[5]= -1;
|
||||
}
|
||||
|
||||
/***********************************************************************\
|
||||
* Warning: this returns 16-bit LITTLENUMs. It is up to the caller *
|
||||
* to figure out any alignment problems and to conspire for the *
|
||||
* bytes/word to be emitted in the right order. Bigendians beware! *
|
||||
* *
|
||||
\***********************************************************************/
|
||||
|
||||
/* Note that atof-ieee always has X and P precisions enabled. it is up
|
||||
to md_atof to filter them out if the target machine does not support
|
||||
them. */
|
||||
|
||||
char * /* Return pointer past text consumed. */
|
||||
atof_ieee (str, what_kind, words)
|
||||
char * str; /* Text to convert to binary. */
|
||||
char what_kind; /* 'd', 'f', 'g', 'h' */
|
||||
LITTLENUM_TYPE * words; /* Build the binary here. */
|
||||
{
|
||||
static LITTLENUM_TYPE bits [MAX_PRECISION + MAX_PRECISION + GUARD];
|
||||
/* Extra bits for zeroed low-order bits. */
|
||||
/* The 1st MAX_PRECISION are zeroed, */
|
||||
/* the last contain flonum bits. */
|
||||
char * return_value;
|
||||
int precision; /* Number of 16-bit words in the format. */
|
||||
long exponent_bits;
|
||||
|
||||
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_bad("Error converting floating point number (Exponent overflow?)"); */
|
||||
make_invalid_floating_point_number (words);
|
||||
return NULL;
|
||||
}
|
||||
gen_to_words(words, precision, exponent_bits);
|
||||
return return_value;
|
||||
}
|
||||
|
||||
/* Turn generic_floating_point_number into a real float/double/extended */
|
||||
int gen_to_words(words, precision, exponent_bits)
|
||||
LITTLENUM_TYPE *words;
|
||||
int precision;
|
||||
long exponent_bits;
|
||||
{
|
||||
int return_value=0;
|
||||
|
||||
long exponent_1;
|
||||
long exponent_2;
|
||||
long exponent_3;
|
||||
long exponent_4;
|
||||
int exponent_skippage;
|
||||
LITTLENUM_TYPE word1;
|
||||
LITTLENUM_TYPE * lp;
|
||||
|
||||
if (generic_floating_point_number.low > generic_floating_point_number.leader) {
|
||||
/* 0.0e0 seen. */
|
||||
if(generic_floating_point_number.sign=='+')
|
||||
words[0]=0x0000;
|
||||
else
|
||||
words[0]=0x8000;
|
||||
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 carry;
|
||||
|
||||
for (carry = 1; carry && (lp >= words); lp --) {
|
||||
carry = * lp + carry;
|
||||
* lp = carry;
|
||||
carry >>= LITTLENUM_NUMBER_OF_BITS;
|
||||
}
|
||||
}
|
||||
} else if((*lp&mask[prec_bits])!=mask[prec_bits])
|
||||
lp++;
|
||||
}
|
||||
|
||||
return return_value;
|
||||
} else if (exponent_4 & ~ mask [exponent_bits]) {
|
||||
/*
|
||||
* Exponent overflow. Lose immediately.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We leave return_value alone: admit we read the
|
||||
* number, but return a floating exception
|
||||
* because we can't encode the number.
|
||||
*/
|
||||
make_invalid_floating_point_number (words);
|
||||
return return_value;
|
||||
} else {
|
||||
word1 |= (exponent_4 << ((LITTLENUM_NUMBER_OF_BITS-1) - exponent_bits))
|
||||
| next_bits ((LITTLENUM_NUMBER_OF_BITS-1) - exponent_bits);
|
||||
}
|
||||
|
||||
* lp ++ = word1;
|
||||
|
||||
/* X_PRECISION is special: it has 16 bits of zero in the middle,
|
||||
followed by a 1 bit. */
|
||||
if(exponent_bits==15 && precision==X_PRECISION) {
|
||||
*lp++=0;
|
||||
*lp++= 1<<(LITTLENUM_NUMBER_OF_BITS)|next_bits(LITTLENUM_NUMBER_OF_BITS-1);
|
||||
}
|
||||
|
||||
/* The rest of the words are just mantissa bits. */
|
||||
while(lp < words + precision)
|
||||
*lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS);
|
||||
|
||||
if (next_bits (1)) {
|
||||
unsigned long carry;
|
||||
/*
|
||||
* Since the NEXT bit is a 1, round UP the mantissa.
|
||||
* The cunning design of these hidden-1 floats permits
|
||||
* us to let the mantissa overflow into the exponent, and
|
||||
* it 'does the right thing'. However, we lose if the
|
||||
* highest-order bit of the lowest-order word flips.
|
||||
* Is that clear?
|
||||
*/
|
||||
|
||||
|
||||
/* #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2)
|
||||
Please allow at least 1 more bit in carry than is in a LITTLENUM.
|
||||
We need that extra bit to hold a carry during a LITTLENUM carry
|
||||
propagation. Another extra bit (kept 0) will assure us that we
|
||||
don't get a sticky sign bit after shifting right, and that
|
||||
permits us to propagate the carry without any masking of bits.
|
||||
#endif */
|
||||
for (carry = 1, lp --; carry && (lp >= words); lp --) {
|
||||
carry = * lp + carry;
|
||||
* lp = carry;
|
||||
carry >>= LITTLENUM_NUMBER_OF_BITS;
|
||||
}
|
||||
if ( (word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1)) ) {
|
||||
/* We leave return_value alone: admit we read the
|
||||
* number, but return a floating exception
|
||||
* because we can't encode the number.
|
||||
*/
|
||||
*words&= ~ (1 << (LITTLENUM_NUMBER_OF_BITS - 1));
|
||||
/* make_invalid_floating_point_number (words); */
|
||||
/* return return_value; */
|
||||
}
|
||||
}
|
||||
return (return_value);
|
||||
}
|
||||
|
||||
/* This routine is a real kludge. Someone really should do it better, but
|
||||
I'm too lazy, and I don't understand this stuff all too well anyway
|
||||
(JF)
|
||||
*/
|
||||
void
|
||||
int_to_gen(x)
|
||||
long x;
|
||||
{
|
||||
char buf[20];
|
||||
char *bufp;
|
||||
|
||||
sprintf(buf,"%ld",x);
|
||||
bufp= &buf[0];
|
||||
if(atof_generic(&bufp,".", EXP_CHARS, &generic_floating_point_number))
|
||||
as_bad("Error converting number to floating point (Exponent overflow?)");
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
char *
|
||||
print_gen(gen)
|
||||
FLONUM_TYPE *gen;
|
||||
{
|
||||
FLONUM_TYPE f;
|
||||
LITTLENUM_TYPE arr[10];
|
||||
double dv;
|
||||
float fv;
|
||||
static char sbuf[40];
|
||||
|
||||
if(gen) {
|
||||
f=generic_floating_point_number;
|
||||
generic_floating_point_number= *gen;
|
||||
}
|
||||
gen_to_words(&arr[0],4,11);
|
||||
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
|
509
gas/config/atof-vax.c
Normal file
509
gas/config/atof-vax.c
Normal file
|
@ -0,0 +1,509 @@
|
|||
/* atof_vax.c - turn a Flonum into a VAX floating point number
|
||||
Copyright (C) 1987 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* JF added these two for md_atof() */
|
||||
#include "as.h"
|
||||
|
||||
#include "flonum.h"
|
||||
|
||||
|
||||
/* Precision in LittleNums. */
|
||||
#define MAX_PRECISION (8)
|
||||
#define H_PRECISION (8)
|
||||
#define G_PRECISION (4)
|
||||
#define D_PRECISION (4)
|
||||
#define F_PRECISION (2)
|
||||
|
||||
/* Length in LittleNums of guard bits. */
|
||||
#define GUARD (2)
|
||||
|
||||
int /* Number of chars in flonum type 'letter'. */
|
||||
atof_vax_sizeof (letter)
|
||||
char letter;
|
||||
{
|
||||
int return_value;
|
||||
|
||||
/*
|
||||
* Permitting uppercase letters is probably a bad idea.
|
||||
* Please use only lower-cased letters in case the upper-cased
|
||||
* ones become unsupported!
|
||||
*/
|
||||
switch (letter)
|
||||
{
|
||||
case 'f':
|
||||
case 'F':
|
||||
return_value = 4;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'D':
|
||||
case 'g':
|
||||
case 'G':
|
||||
return_value = 8;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case 'H':
|
||||
return_value = 16;
|
||||
break;
|
||||
|
||||
default:
|
||||
return_value = 0;
|
||||
break;
|
||||
}
|
||||
return (return_value);
|
||||
} /* atof_vax_sizeof */
|
||||
|
||||
static const long mask [] = {
|
||||
0x00000000,
|
||||
0x00000001,
|
||||
0x00000003,
|
||||
0x00000007,
|
||||
0x0000000f,
|
||||
0x0000001f,
|
||||
0x0000003f,
|
||||
0x0000007f,
|
||||
0x000000ff,
|
||||
0x000001ff,
|
||||
0x000003ff,
|
||||
0x000007ff,
|
||||
0x00000fff,
|
||||
0x00001fff,
|
||||
0x00003fff,
|
||||
0x00007fff,
|
||||
0x0000ffff,
|
||||
0x0001ffff,
|
||||
0x0003ffff,
|
||||
0x0007ffff,
|
||||
0x000fffff,
|
||||
0x001fffff,
|
||||
0x003fffff,
|
||||
0x007fffff,
|
||||
0x00ffffff,
|
||||
0x01ffffff,
|
||||
0x03ffffff,
|
||||
0x07ffffff,
|
||||
0x0fffffff,
|
||||
0x1fffffff,
|
||||
0x3fffffff,
|
||||
0x7fffffff,
|
||||
0xffffffff
|
||||
};
|
||||
|
||||
|
||||
/* Shared between flonum_gen2vax and next_bits */
|
||||
static int bits_left_in_littlenum;
|
||||
static LITTLENUM_TYPE * littlenum_pointer;
|
||||
static LITTLENUM_TYPE * littlenum_end;
|
||||
|
||||
static int
|
||||
next_bits (number_of_bits)
|
||||
int number_of_bits;
|
||||
{
|
||||
int return_value;
|
||||
|
||||
if(littlenum_pointer<littlenum_end)
|
||||
return 0;
|
||||
if (number_of_bits >= bits_left_in_littlenum)
|
||||
{
|
||||
return_value = mask [bits_left_in_littlenum] & * littlenum_pointer;
|
||||
number_of_bits -= bits_left_in_littlenum;
|
||||
return_value <<= number_of_bits;
|
||||
bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits;
|
||||
littlenum_pointer --;
|
||||
if(littlenum_pointer>=littlenum_end)
|
||||
return_value |= ( (* littlenum_pointer) >> (bits_left_in_littlenum) ) & mask [number_of_bits];
|
||||
}
|
||||
else
|
||||
{
|
||||
bits_left_in_littlenum -= number_of_bits;
|
||||
return_value = mask [number_of_bits] & ( (* littlenum_pointer) >> bits_left_in_littlenum);
|
||||
}
|
||||
return (return_value);
|
||||
}
|
||||
|
||||
static void
|
||||
make_invalid_floating_point_number (words)
|
||||
LITTLENUM_TYPE * words;
|
||||
{
|
||||
* words = 0x8000; /* Floating Reserved Operand Code */
|
||||
}
|
||||
|
||||
static int /* 0 means letter is OK. */
|
||||
what_kind_of_float (letter, precisionP, exponent_bitsP)
|
||||
char letter; /* In: lowercase please. What kind of float? */
|
||||
int * precisionP; /* Number of 16-bit words in the float. */
|
||||
long * exponent_bitsP; /* Number of exponent bits. */
|
||||
{
|
||||
int retval; /* 0: OK. */
|
||||
|
||||
retval = 0;
|
||||
switch (letter)
|
||||
{
|
||||
case 'f':
|
||||
* precisionP = F_PRECISION;
|
||||
* exponent_bitsP = 8;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
* precisionP = D_PRECISION;
|
||||
* exponent_bitsP = 8;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
* precisionP = G_PRECISION;
|
||||
* exponent_bitsP = 11;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
* precisionP = H_PRECISION;
|
||||
* exponent_bitsP = 15;
|
||||
break;
|
||||
|
||||
default:
|
||||
retval = 69;
|
||||
break;
|
||||
}
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/***********************************************************************\
|
||||
* *
|
||||
* Warning: this returns 16-bit LITTLENUMs, because that is *
|
||||
* what the VAX thinks in. It is up to the caller to figure *
|
||||
* out any alignment problems and to conspire for the bytes/word *
|
||||
* to be emitted in the right order. Bigendians beware! *
|
||||
* *
|
||||
\***********************************************************************/
|
||||
|
||||
char * /* Return pointer past text consumed. */
|
||||
atof_vax (str, what_kind, words)
|
||||
char * str; /* Text to convert to binary. */
|
||||
char what_kind; /* 'd', 'f', 'g', 'h' */
|
||||
LITTLENUM_TYPE * words; /* Build the binary here. */
|
||||
{
|
||||
FLONUM_TYPE f;
|
||||
LITTLENUM_TYPE bits [MAX_PRECISION + MAX_PRECISION + GUARD];
|
||||
/* Extra bits for zeroed low-order bits. */
|
||||
/* The 1st MAX_PRECISION are zeroed, */
|
||||
/* the last contain flonum bits. */
|
||||
char * return_value;
|
||||
int precision; /* Number of 16-bit words in the format. */
|
||||
long exponent_bits;
|
||||
|
||||
return_value = str;
|
||||
f . low = bits + MAX_PRECISION;
|
||||
f . high = NULL;
|
||||
f . leader = NULL;
|
||||
f . exponent = NULL;
|
||||
f . sign = '\0';
|
||||
|
||||
if (what_kind_of_float (what_kind, & precision, & exponent_bits))
|
||||
{
|
||||
return_value = NULL; /* We lost. */
|
||||
make_invalid_floating_point_number (words);
|
||||
}
|
||||
if (return_value)
|
||||
{
|
||||
bzero (bits, sizeof(LITTLENUM_TYPE) * MAX_PRECISION);
|
||||
|
||||
/* Use more LittleNums than seems */
|
||||
/* necessary: the highest flonum may have */
|
||||
/* 15 leading 0 bits, so could be useless. */
|
||||
f . high = f . low + precision - 1 + GUARD;
|
||||
|
||||
if (atof_generic (& return_value, ".", "eE", & f))
|
||||
{
|
||||
make_invalid_floating_point_number (words);
|
||||
return_value = NULL; /* we lost */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flonum_gen2vax (what_kind, & f, words))
|
||||
{
|
||||
return_value = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (return_value);
|
||||
}
|
||||
|
||||
/*
|
||||
* In: a flonum, a vax floating point format.
|
||||
* Out: a vax floating-point bit pattern.
|
||||
*/
|
||||
|
||||
int /* 0: OK. */
|
||||
flonum_gen2vax (format_letter, f, words)
|
||||
char format_letter; /* One of 'd' 'f' 'g' 'h'. */
|
||||
FLONUM_TYPE * f;
|
||||
LITTLENUM_TYPE * words; /* Deliver answer here. */
|
||||
{
|
||||
LITTLENUM_TYPE * lp;
|
||||
int precision;
|
||||
long exponent_bits;
|
||||
int return_value; /* 0 == OK. */
|
||||
|
||||
return_value = what_kind_of_float (format_letter, & precision, & exponent_bits);
|
||||
if (return_value != 0)
|
||||
{
|
||||
make_invalid_floating_point_number (words);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (f -> low > f -> leader)
|
||||
{
|
||||
/* 0.0e0 seen. */
|
||||
bzero (words, sizeof(LITTLENUM_TYPE) * precision);
|
||||
}
|
||||
else
|
||||
{
|
||||
long exponent_1;
|
||||
long exponent_2;
|
||||
long exponent_3;
|
||||
long exponent_4;
|
||||
int exponent_skippage;
|
||||
LITTLENUM_TYPE word1;
|
||||
|
||||
/* JF: Deal with new Nan, +Inf and -Inf codes */
|
||||
if(f->sign!='-' && f->sign!='+') {
|
||||
make_invalid_floating_point_number(words);
|
||||
return return_value;
|
||||
}
|
||||
/*
|
||||
* All vaxen floating_point formats (so far) have:
|
||||
* Bit 15 is sign bit.
|
||||
* Bits 14:n are excess-whatever exponent.
|
||||
* Bits n-1:0 (if any) are most significant bits of fraction.
|
||||
* Bits 15:0 of the next word are the next most significant bits.
|
||||
* And so on for each other word.
|
||||
*
|
||||
* All this to be compatible with a KF11?? (Which is still faster
|
||||
* than lots of vaxen I can think of, but it also has higher
|
||||
* maintenance costs ... sigh).
|
||||
*
|
||||
* So we need: number of bits of exponent, number of bits of
|
||||
* mantissa.
|
||||
*/
|
||||
|
||||
#ifdef NEVER /******* This zeroing seems redundant - Dean 3may86 **********/
|
||||
/*
|
||||
* No matter how few bits we got back from the atof()
|
||||
* routine, add enough zero littlenums so the rest of the
|
||||
* code won't run out of "significant" bits in the mantissa.
|
||||
*/
|
||||
{
|
||||
LITTLENUM_TYPE * ltp;
|
||||
for (ltp = f -> leader + 1;
|
||||
ltp <= f -> low + precision;
|
||||
ltp ++)
|
||||
{
|
||||
* ltp = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS;
|
||||
littlenum_pointer = f -> leader;
|
||||
littlenum_end = f->low;
|
||||
/* Seek (and forget) 1st significant bit */
|
||||
for (exponent_skippage = 0;
|
||||
! next_bits(1);
|
||||
exponent_skippage ++)
|
||||
{
|
||||
}
|
||||
exponent_1 = f -> exponent + f -> leader + 1 - f -> low;
|
||||
/* Radix LITTLENUM_RADIX, point just higher than f -> leader. */
|
||||
exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS;
|
||||
/* Radix 2. */
|
||||
exponent_3 = exponent_2 - exponent_skippage;
|
||||
/* Forget leading zeros, forget 1st bit. */
|
||||
exponent_4 = exponent_3 + (1 << (exponent_bits - 1));
|
||||
/* Offset exponent. */
|
||||
|
||||
if (exponent_4 & ~ mask [exponent_bits])
|
||||
{
|
||||
/*
|
||||
* Exponent overflow. Lose immediately.
|
||||
*/
|
||||
|
||||
make_invalid_floating_point_number (words);
|
||||
|
||||
/*
|
||||
* We leave return_value alone: admit we read the
|
||||
* number, but return a floating exception
|
||||
* because we can't encode the number.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
lp = words;
|
||||
|
||||
/* Word 1. Sign, exponent and perhaps high bits. */
|
||||
/* Assume 2's complement integers. */
|
||||
word1 = ((exponent_4 & mask [exponent_bits]) << (15 - exponent_bits))
|
||||
| ((f -> sign == '+') ? 0 : 0x8000)
|
||||
| next_bits (15 - exponent_bits);
|
||||
* lp ++ = word1;
|
||||
|
||||
/* The rest of the words are just mantissa bits. */
|
||||
for (; lp < words + precision; lp++)
|
||||
{
|
||||
* lp = next_bits (LITTLENUM_NUMBER_OF_BITS);
|
||||
}
|
||||
|
||||
if (next_bits (1))
|
||||
{
|
||||
/*
|
||||
* Since the NEXT bit is a 1, round UP the mantissa.
|
||||
* The cunning design of these hidden-1 floats permits
|
||||
* us to let the mantissa overflow into the exponent, and
|
||||
* it 'does the right thing'. However, we lose if the
|
||||
* highest-order bit of the lowest-order word flips.
|
||||
* Is that clear?
|
||||
*/
|
||||
|
||||
unsigned long carry;
|
||||
|
||||
/*
|
||||
#if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2)
|
||||
Please allow at least 1 more bit in carry than is in a LITTLENUM.
|
||||
We need that extra bit to hold a carry during a LITTLENUM carry
|
||||
propagation. Another extra bit (kept 0) will assure us that we
|
||||
don't get a sticky sign bit after shifting right, and that
|
||||
permits us to propagate the carry without any masking of bits.
|
||||
#endif
|
||||
*/
|
||||
for (carry = 1, lp --;
|
||||
carry && (lp >= words);
|
||||
lp --)
|
||||
{
|
||||
carry = * lp + carry;
|
||||
* lp = carry;
|
||||
carry >>= LITTLENUM_NUMBER_OF_BITS;
|
||||
}
|
||||
|
||||
if ( (word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1)) )
|
||||
{
|
||||
make_invalid_floating_point_number (words);
|
||||
/*
|
||||
* We leave return_value alone: admit we read the
|
||||
* number, but return a floating exception
|
||||
* because we can't encode the number.
|
||||
*/
|
||||
}
|
||||
} /* if (we needed to round up) */
|
||||
} /* if (exponent overflow) */
|
||||
} /* if (0.0e0) */
|
||||
} /* if (float_type was OK) */
|
||||
return (return_value);
|
||||
}
|
||||
|
||||
|
||||
/* JF this used to be in vax.c but this looks like a better place for it */
|
||||
|
||||
/*
|
||||
* md_atof()
|
||||
*
|
||||
* In: input_line_pointer -> the 1st character of a floating-point
|
||||
* number.
|
||||
* 1 letter denoting the type of statement that wants a
|
||||
* binary floating point number returned.
|
||||
* Address of where to build floating point literal.
|
||||
* Assumed to be 'big enough'.
|
||||
* Address of where to return size of literal (in chars).
|
||||
*
|
||||
* Out: Input_line_pointer -> of next char after floating number.
|
||||
* Error message, or "".
|
||||
* Floating point literal.
|
||||
* Number of chars we used for the literal.
|
||||
*/
|
||||
|
||||
#define MAXIMUM_NUMBER_OF_LITTLENUMS (8) /* For .hfloats. */
|
||||
|
||||
char *
|
||||
md_atof (what_statement_type, literalP, sizeP)
|
||||
char what_statement_type;
|
||||
char * literalP;
|
||||
int * sizeP;
|
||||
{
|
||||
LITTLENUM_TYPE words [MAXIMUM_NUMBER_OF_LITTLENUMS];
|
||||
register char kind_of_float;
|
||||
register int number_of_chars;
|
||||
register LITTLENUM_TYPE * littlenum_pointer;
|
||||
|
||||
switch (what_statement_type)
|
||||
{
|
||||
case 'F': /* .float */
|
||||
case 'f': /* .ffloat */
|
||||
kind_of_float = 'f';
|
||||
break;
|
||||
|
||||
case 'D': /* .double */
|
||||
case 'd': /* .dfloat */
|
||||
kind_of_float = 'd';
|
||||
break;
|
||||
|
||||
case 'g': /* .gfloat */
|
||||
kind_of_float = 'g';
|
||||
break;
|
||||
|
||||
case 'h': /* .hfloat */
|
||||
kind_of_float = 'h';
|
||||
break;
|
||||
|
||||
default:
|
||||
kind_of_float = 0;
|
||||
break;
|
||||
};
|
||||
|
||||
if (kind_of_float)
|
||||
{
|
||||
register LITTLENUM_TYPE * limit;
|
||||
|
||||
input_line_pointer = atof_vax (input_line_pointer,
|
||||
kind_of_float,
|
||||
words);
|
||||
/*
|
||||
* The atof_vax() builds up 16-bit numbers.
|
||||
* Since the assembler may not be running on
|
||||
* a little-endian machine, be very careful about
|
||||
* converting words to chars.
|
||||
*/
|
||||
number_of_chars = atof_vax_sizeof (kind_of_float);
|
||||
know( number_of_chars <= MAXIMUM_NUMBER_OF_LITTLENUMS * sizeof(LITTLENUM_TYPE) );
|
||||
limit = words + (number_of_chars / sizeof(LITTLENUM_TYPE));
|
||||
for (littlenum_pointer = words;
|
||||
littlenum_pointer < limit;
|
||||
littlenum_pointer ++)
|
||||
{
|
||||
md_number_to_chars (literalP, * littlenum_pointer, sizeof(LITTLENUM_TYPE));
|
||||
literalP += sizeof(LITTLENUM_TYPE);
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
number_of_chars = 0;
|
||||
};
|
||||
|
||||
* sizeP = number_of_chars;
|
||||
return (kind_of_float ? "" : "Bad call to md_atof()");
|
||||
} /* md_atof() */
|
||||
|
||||
/* atof_vax.c */
|
500
gas/config/obj-aout.c
Normal file
500
gas/config/obj-aout.c
Normal file
|
@ -0,0 +1,500 @@
|
|||
/* a.out object file format
|
||||
Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 1,
|
||||
or (at your option) any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with GAS; see the file COPYING. If not, write
|
||||
to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#include "as.h"
|
||||
|
||||
#include "obstack.h"
|
||||
|
||||
/* in: segT out: N_TYPE bits */
|
||||
const short seg_N_TYPE[] = {
|
||||
N_ABS,
|
||||
N_TEXT,
|
||||
N_DATA,
|
||||
N_BSS,
|
||||
N_UNDF, /* unknown */
|
||||
N_UNDF, /* absent */
|
||||
N_UNDF, /* pass1 */
|
||||
N_UNDF, /* error */
|
||||
N_UNDF, /* bignum/flonum */
|
||||
N_UNDF, /* difference */
|
||||
N_UNDF, /* debug */
|
||||
N_UNDF, /* ntv */
|
||||
N_UNDF, /* ptv */
|
||||
N_REGISTER, /* register */
|
||||
};
|
||||
|
||||
const segT N_TYPE_seg [N_TYPE+2] = { /* N_TYPE == 0x1E = 32-2 */
|
||||
SEG_UNKNOWN, /* N_UNDF == 0 */
|
||||
SEG_GOOF,
|
||||
SEG_ABSOLUTE, /* N_ABS == 2 */
|
||||
SEG_GOOF,
|
||||
SEG_TEXT, /* N_TEXT == 4 */
|
||||
SEG_GOOF,
|
||||
SEG_DATA, /* N_DATA == 6 */
|
||||
SEG_GOOF,
|
||||
SEG_BSS, /* N_BSS == 8 */
|
||||
SEG_GOOF,
|
||||
SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
|
||||
SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
|
||||
SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
|
||||
SEG_REGISTER, /* dummy N_REGISTER for regs = 30 */
|
||||
SEG_GOOF,
|
||||
};
|
||||
|
||||
#ifdef __STDC__
|
||||
static void obj_aout_stab(int what);
|
||||
static void obj_aout_line(void);
|
||||
static void obj_aout_desc(void);
|
||||
#else /* __STDC__ */
|
||||
static void obj_aout_desc();
|
||||
static void obj_aout_stab();
|
||||
static void obj_aout_line();
|
||||
#endif /* __STDC__ */
|
||||
|
||||
const pseudo_typeS obj_pseudo_table[] = {
|
||||
{ "line", obj_aout_line, 0 }, /* source code line number */
|
||||
{ "ln", obj_aout_line, 0 }, /* source code line number */
|
||||
{ "desc", obj_aout_desc, 0 }, /* def */
|
||||
{ "stabd", obj_aout_stab, 'd' }, /* stabs */
|
||||
{ "stabn", obj_aout_stab, 'n' }, /* stabs */
|
||||
{ "stabs", obj_aout_stab, 's' }, /* stabs */
|
||||
|
||||
{ NULL} /* end sentinel */
|
||||
}; /* obj_pseudo_table */
|
||||
|
||||
|
||||
/* Relocation. */
|
||||
|
||||
/*
|
||||
* 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
|
||||
};
|
||||
|
||||
/*
|
||||
* emit_relocations()
|
||||
*
|
||||
* Crawl along a fixS chain. Emit the segment's relocations.
|
||||
*/
|
||||
void obj_emit_relocations(where, fixP, segment_address_in_file)
|
||||
char **where;
|
||||
fixS *fixP; /* Fixup chain for this segment. */
|
||||
relax_addressT segment_address_in_file;
|
||||
{
|
||||
struct reloc_info_generic ri;
|
||||
register symbolS *symbolP;
|
||||
|
||||
/* If a machine dependent emitter is needed, call it instead. */
|
||||
if (md_emit_relocations) {
|
||||
(*md_emit_relocations) (fixP, segment_address_in_file);
|
||||
return;
|
||||
}
|
||||
|
||||
/* JF this is for paranoia */
|
||||
bzero((char *)&ri,sizeof(ri));
|
||||
for (; fixP; fixP = fixP->fx_next) {
|
||||
if ((symbolP = fixP->fx_addsy) != 0) {
|
||||
ri.r_bsr = fixP->fx_bsr;
|
||||
ri.r_disp = fixP->fx_im_disp;
|
||||
ri.r_callj = fixP->fx_callj;
|
||||
ri.r_length = nbytes_r_length [fixP->fx_size];
|
||||
ri.r_pcrel = fixP->fx_pcrel;
|
||||
ri.r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file;
|
||||
|
||||
if (S_GET_TYPE(symbolP) == N_UNDF) {
|
||||
ri.r_extern = 1;
|
||||
ri.r_symbolnum = symbolP->sy_number;
|
||||
} else {
|
||||
ri.r_extern = 0;
|
||||
ri.r_symbolnum = S_GET_TYPE(symbolP);
|
||||
}
|
||||
|
||||
/* Output the relocation information in machine-dependent form. */
|
||||
md_ri_to_chars(*where, &ri);
|
||||
*where += md_reloc_size;
|
||||
} /* if there is an add symbol */
|
||||
} /* for each fix */
|
||||
|
||||
return;
|
||||
} /* emit_relocations() */
|
||||
|
||||
/* Aout file generation & utilities */
|
||||
void obj_header_append(where, headers)
|
||||
char **where;
|
||||
object_headers *headers;
|
||||
{
|
||||
tc_headers_hook(headers);
|
||||
|
||||
#ifdef CROSS_ASSEMBLE
|
||||
md_number_to_chars(*where, headers->header.a_info, sizeof(headers->header.a_info));
|
||||
*where += sizeof(headers->header.a_info);
|
||||
md_number_to_chars(*where, headers->header.a_text, sizeof(headers->header.a_text));
|
||||
*where += sizeof(headers->header.a_text);
|
||||
md_number_to_chars(*where, headers->header.a_data, sizeof(headers->header.a_data));
|
||||
*where += sizeof(headers->header.a_data);
|
||||
md_number_to_chars(*where, headers->header.a_bss, sizeof(headers->header.a_bss));
|
||||
*where += sizeof(headers->header.a_bss);
|
||||
md_number_to_chars(*where, headers->header.a_syms, sizeof(headers->header.a_syms));
|
||||
*where += sizeof(headers->header.a_syms);
|
||||
md_number_to_chars(*where, headers->header.a_entry, sizeof(headers->header.a_entry));
|
||||
*where += sizeof(headers->header.a_entry);
|
||||
md_number_to_chars(*where, headers->header.a_trsize, sizeof(headers->header.a_trsize));
|
||||
*where += sizeof(headers->header.a_trsize);
|
||||
md_number_to_chars(*where, headers->header.a_drsize, sizeof(headers->header.a_drsize));
|
||||
*where += sizeof(headers->header.a_drsize);
|
||||
#ifdef EXEC_MACHINE_TYPE
|
||||
md_number_to_chars(*where, headers->header.a_machtype, sizeof(headers->header.a_machtype));
|
||||
*where += sizeof(headers->header.a_machtype);
|
||||
#endif /* EXEC_MACHINE_TYPE */
|
||||
#ifdef EXEC_VERSION
|
||||
md_number_to_chars(*where, headers->header.a_version, sizeof(headers->header.a_version));
|
||||
*where += sizeof(headers->header.a_version);
|
||||
#endif /* EXEC_VERSION */
|
||||
|
||||
#else /* CROSS_ASSEMBLE */
|
||||
|
||||
append(where, (char *) &headers->header, sizeof(headers->header));
|
||||
#endif /* CROSS_ASSEMBLE */
|
||||
|
||||
return;
|
||||
} /* obj_append_header() */
|
||||
|
||||
void obj_symbol_to_chars(where, symbolP)
|
||||
char **where;
|
||||
symbolS *symbolP;
|
||||
{
|
||||
md_number_to_chars((char *)&(S_GET_OFFSET(symbolP)), S_GET_OFFSET(symbolP), sizeof(S_GET_OFFSET(symbolP)));
|
||||
md_number_to_chars((char *)&(S_GET_DESC(symbolP)), S_GET_DESC(symbolP), sizeof(S_GET_DESC(symbolP)));
|
||||
md_number_to_chars((char *)&(S_GET_VALUE(symbolP)), S_GET_VALUE(symbolP), sizeof(S_GET_VALUE(symbolP)));
|
||||
|
||||
append(where, (char *)&symbolP->sy_symbol, sizeof(obj_symbol_type));
|
||||
} /* obj_symbol_to_chars() */
|
||||
|
||||
void obj_emit_symbols(where, symbol_rootP)
|
||||
char **where;
|
||||
symbolS *symbol_rootP;
|
||||
{
|
||||
symbolS * symbolP;
|
||||
|
||||
/*
|
||||
* Emit all symbols left in the symbol chain.
|
||||
*/
|
||||
for(symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
|
||||
/* Used to save the offset of the name. It is used to point
|
||||
to the string in memory but must be a file offset. */
|
||||
register char *temp;
|
||||
|
||||
temp = S_GET_NAME(symbolP);
|
||||
S_SET_OFFSET(symbolP, symbolP->sy_name_offset);
|
||||
|
||||
/* Any symbol still undefined and is not a dbg symbol is made N_EXT. */
|
||||
if (!S_IS_DEBUG(symbolP) && !S_IS_DEFINED(symbolP)) S_SET_EXTERNAL(symbolP);
|
||||
|
||||
obj_symbol_to_chars(where, symbolP);
|
||||
S_SET_NAME(symbolP,temp);
|
||||
}
|
||||
} /* emit_symbols() */
|
||||
|
||||
void obj_symbol_new_hook(symbolP)
|
||||
symbolS *symbolP;
|
||||
{
|
||||
S_SET_OTHER(symbolP, 0);
|
||||
S_SET_DESC(symbolP, 0);
|
||||
return;
|
||||
} /* obj_symbol_new_hook() */
|
||||
|
||||
static void obj_aout_line() {
|
||||
/* Assume delimiter is part of expression. */
|
||||
/* BSD4.2 as fails with delightful bug, so we */
|
||||
/* are not being incompatible here. */
|
||||
new_logical_line((char *)NULL, (int)(get_absolute_expression()));
|
||||
demand_empty_rest_of_line();
|
||||
} /* obj_aout_line() */
|
||||
|
||||
/*
|
||||
* stab()
|
||||
*
|
||||
* Handle .stabX directives, which used to be open-coded.
|
||||
* So much creeping featurism overloaded the semantics that we decided
|
||||
* to put all .stabX thinking in one place. Here.
|
||||
*
|
||||
* We try to make any .stabX directive legal. Other people's AS will often
|
||||
* do assembly-time consistency checks: eg assigning meaning to n_type bits
|
||||
* and "protecting" you from setting them to certain values. (They also zero
|
||||
* certain bits before emitting symbols. Tut tut.)
|
||||
*
|
||||
* If an expression is not absolute we either gripe or use the relocation
|
||||
* information. Other people's assemblers silently forget information they
|
||||
* don't need and invent information they need that you didn't supply.
|
||||
*
|
||||
* .stabX directives always make a symbol table entry. It may be junk if
|
||||
* the rest of your .stabX directive is malformed.
|
||||
*/
|
||||
static void obj_aout_stab(what)
|
||||
int what;
|
||||
{
|
||||
register symbolS * symbolP = 0;
|
||||
register char * string;
|
||||
int saved_type = 0;
|
||||
int length;
|
||||
int goof; /* TRUE if we have aborted. */
|
||||
long longint;
|
||||
|
||||
/*
|
||||
* Enter with input_line_pointer pointing past .stabX and any following
|
||||
* whitespace.
|
||||
*/
|
||||
goof = 0; /* JF who forgot this?? */
|
||||
if (what == 's') {
|
||||
string = demand_copy_C_string(& length);
|
||||
SKIP_WHITESPACE();
|
||||
if (* input_line_pointer == ',')
|
||||
input_line_pointer ++;
|
||||
else {
|
||||
as_bad("I need a comma after symbol's name");
|
||||
goof = 1;
|
||||
}
|
||||
} else
|
||||
string = "";
|
||||
|
||||
/*
|
||||
* Input_line_pointer->after ','. String->symbol name.
|
||||
*/
|
||||
if (! goof) {
|
||||
symbolP = symbol_new(string,
|
||||
SEG_UNKNOWN,
|
||||
0,
|
||||
(struct frag *)0);
|
||||
switch (what) {
|
||||
case 'd':
|
||||
S_SET_NAME(symbolP, NULL); /* .stabd feature. */
|
||||
S_SET_VALUE(symbolP, obstack_next_free(&frags) - frag_now->fr_literal);
|
||||
symbolP->sy_frag = frag_now;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
symbolP->sy_frag = &zero_address_frag;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
symbolP->sy_frag = & zero_address_frag;
|
||||
break;
|
||||
|
||||
default:
|
||||
BAD_CASE(what);
|
||||
break;
|
||||
}
|
||||
|
||||
if (get_absolute_expression_and_terminator(&longint) == ',')
|
||||
symbolP->sy_symbol.n_type = saved_type = longint;
|
||||
else {
|
||||
as_bad("I want a comma after the n_type expression");
|
||||
goof = 1;
|
||||
input_line_pointer --; /* Backup over a non-',' char. */
|
||||
}
|
||||
}
|
||||
|
||||
if (!goof) {
|
||||
if (get_absolute_expression_and_terminator(&longint) == ',')
|
||||
S_SET_OTHER(symbolP, longint);
|
||||
else {
|
||||
as_bad("I want a comma after the n_other expression");
|
||||
goof = 1;
|
||||
input_line_pointer--; /* Backup over a non-',' char. */
|
||||
}
|
||||
}
|
||||
|
||||
if (!goof) {
|
||||
S_SET_DESC(symbolP, get_absolute_expression());
|
||||
if (what == 's' || what == 'n') {
|
||||
if (*input_line_pointer != ',') {
|
||||
as_bad("I want a comma after the n_desc expression");
|
||||
goof = 1;
|
||||
} else {
|
||||
input_line_pointer++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((!goof) && (what=='s' || what=='n')) {
|
||||
pseudo_set(symbolP);
|
||||
symbolP->sy_symbol.n_type = saved_type;
|
||||
}
|
||||
|
||||
if (goof)
|
||||
ignore_rest_of_line();
|
||||
else
|
||||
demand_empty_rest_of_line ();
|
||||
} /* obj_aout_stab() */
|
||||
|
||||
static void obj_aout_desc() {
|
||||
register char *name;
|
||||
register char c;
|
||||
register char *p;
|
||||
register symbolS *symbolP;
|
||||
register int temp;
|
||||
|
||||
/*
|
||||
* Frob invented at RMS' request. Set the n_desc of a symbol.
|
||||
*/
|
||||
name = input_line_pointer;
|
||||
c = get_symbol_end();
|
||||
p = input_line_pointer;
|
||||
* p = c;
|
||||
SKIP_WHITESPACE();
|
||||
if (*input_line_pointer != ',') {
|
||||
*p = 0;
|
||||
as_bad("Expected comma after name \"%s\"", name);
|
||||
*p = c;
|
||||
ignore_rest_of_line();
|
||||
} else {
|
||||
input_line_pointer ++;
|
||||
temp = get_absolute_expression();
|
||||
*p = 0;
|
||||
symbolP = symbol_find_or_make(name);
|
||||
*p = c;
|
||||
S_SET_DESC(symbolP,temp);
|
||||
}
|
||||
demand_empty_rest_of_line();
|
||||
} /* obj_aout_desc() */
|
||||
|
||||
void obj_read_begin_hook() {
|
||||
return;
|
||||
} /* obj_read_begin_hook() */
|
||||
|
||||
void obj_crawl_symbol_chain(headers)
|
||||
object_headers *headers;
|
||||
{
|
||||
symbolS *symbolP;
|
||||
symbolS **symbolPP;
|
||||
int symbol_number = 0;
|
||||
|
||||
/* JF deal with forward references first... */
|
||||
for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
|
||||
if (symbolP->sy_forward) {
|
||||
S_SET_VALUE(symbolP, S_GET_VALUE(symbolP)
|
||||
+ S_GET_VALUE(symbolP->sy_forward)
|
||||
+ symbolP->sy_forward->sy_frag->fr_address);
|
||||
|
||||
symbolP->sy_forward=0;
|
||||
} /* if it has a forward reference */
|
||||
} /* walk the symbol chain */
|
||||
|
||||
tc_crawl_symbol_chain(headers);
|
||||
|
||||
symbolPP = &symbol_rootP; /*->last symbol chain link. */
|
||||
while ((symbolP = *symbolPP) != NULL) {
|
||||
if (flagseen['R'] && (S_GET_SEGMENT(symbolP) == SEG_DATA)) {
|
||||
S_SET_SEGMENT(symbolP, SEG_TEXT);
|
||||
} /* if pusing data into text */
|
||||
|
||||
S_SET_VALUE(symbolP, S_GET_VALUE(symbolP) + symbolP->sy_frag->fr_address);
|
||||
|
||||
/* OK, here is how we decide which symbols go out into the
|
||||
brave new symtab. Symbols that do are:
|
||||
|
||||
* symbols with no name (stabd's?)
|
||||
* symbols with debug info in their N_TYPE
|
||||
|
||||
Symbols that don't are:
|
||||
* symbols that are registers
|
||||
* symbols with \1 as their 3rd character (numeric labels)
|
||||
* "local labels" as defined by S_LOCAL_NAME(name)
|
||||
if the -L switch was passed to gas.
|
||||
|
||||
All other symbols are output. We complain if a deleted
|
||||
symbol was marked external. */
|
||||
|
||||
|
||||
if (!S_IS_REGISTER(symbolP)
|
||||
&& (!S_GET_NAME(symbolP)
|
||||
|| S_IS_DEBUG(symbolP)
|
||||
#ifdef TC_I960
|
||||
/* FIXME-SOON this ifdef seems highly dubious to me. xoxorich. */
|
||||
|| !S_IS_DEFINED(symbolP)
|
||||
|| S_IS_EXTERNAL(symbolP)
|
||||
#endif /* TC_I960 */
|
||||
|| (S_GET_NAME(symbolP)[0] != '\001' && (flagseen ['L'] || ! S_LOCAL_NAME(symbolP))))) {
|
||||
symbolP->sy_number = symbol_number++;
|
||||
|
||||
/* The + 1 after strlen account for the \0 at the
|
||||
end of each string */
|
||||
if (!S_IS_STABD(symbolP)) {
|
||||
/* Ordinary case. */
|
||||
symbolP->sy_name_offset = string_byte_count;
|
||||
string_byte_count += strlen(S_GET_NAME(symbolP)) + 1;
|
||||
}
|
||||
else /* .Stabd case. */
|
||||
symbolP->sy_name_offset = 0;
|
||||
symbolPP = &(symbol_next(symbolP));
|
||||
} else {
|
||||
if (S_IS_EXTERNAL(symbolP) || !S_IS_DEFINED(symbolP)) {
|
||||
as_bad("Local symbol %s never defined", S_GET_NAME(symbolP));
|
||||
} /* oops. */
|
||||
|
||||
/* Unhook it from the chain */
|
||||
*symbolPP = symbol_next(symbolP);
|
||||
} /* if this symbol should be in the output */
|
||||
} /* for each symbol */
|
||||
|
||||
H_SET_SYMBOL_TABLE_SIZE(headers, symbol_number);
|
||||
|
||||
return;
|
||||
} /* obj_crawl_symbol_chain() */
|
||||
|
||||
/*
|
||||
* Find strings by crawling along symbol table chain.
|
||||
*/
|
||||
|
||||
void obj_emit_strings(where)
|
||||
char **where;
|
||||
{
|
||||
symbolS *symbolP;
|
||||
|
||||
#ifdef CROSS_ASSEMBLE
|
||||
/* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */
|
||||
md_number_to_chars(*where, string_byte_count, sizeof(string_byte_count));
|
||||
*where += sizeof(string_byte_count);
|
||||
#else /* CROSS_ASSEMBLE */
|
||||
append (where, (char *)&string_byte_count, (unsigned long)sizeof(string_byte_count));
|
||||
#endif /* CROSS_ASSEMBLE */
|
||||
|
||||
for(symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
|
||||
if(S_GET_NAME(symbolP))
|
||||
append(&next_object_file_charP, S_GET_NAME(symbolP),
|
||||
(unsigned long)(strlen (S_GET_NAME(symbolP)) + 1));
|
||||
} /* walk symbol chain */
|
||||
|
||||
return;
|
||||
} /* obj_emit_strings() */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of obj-aout.c */
|
187
gas/config/obj-aout.h
Normal file
187
gas/config/obj-aout.h
Normal file
|
@ -0,0 +1,187 @@
|
|||
/* a.out object file format
|
||||
Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 1,
|
||||
or (at your option) any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with GAS; see the file COPYING. If not, write
|
||||
to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/* Tag to validate a.out object file format processing */
|
||||
#define OBJ_AOUT 1
|
||||
|
||||
#include "targ-cpu.h"
|
||||
|
||||
#ifndef VMS
|
||||
#include "a.out.gnu.h" /* Needed to define struct nlist. Sigh. */
|
||||
#else
|
||||
#include "a_out.h"
|
||||
#endif
|
||||
|
||||
extern const short seg_N_TYPE[];
|
||||
extern const segT N_TYPE_seg[];
|
||||
|
||||
#ifndef DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE
|
||||
#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (OMAGIC)
|
||||
#endif /* DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE */
|
||||
|
||||
/* SYMBOL TABLE */
|
||||
/* Symbol table entry data type */
|
||||
|
||||
typedef struct nlist obj_symbol_type; /* Symbol table entry */
|
||||
|
||||
/* If compiler generate leading underscores, remove them. */
|
||||
|
||||
#ifndef STRIP_UNDERSCORE
|
||||
#define STRIP_UNDERSCORE 0
|
||||
#endif /* STRIP_UNDERSCORE */
|
||||
|
||||
/* Symbol table macros and constants */
|
||||
|
||||
/*
|
||||
* Macros to extract information from a symbol table entry.
|
||||
* This syntaxic indirection allows independence regarding a.out or coff.
|
||||
* The argument (s) of all these macros is a pointer to a symbol table entry.
|
||||
*/
|
||||
|
||||
/* True if the symbol is external */
|
||||
#define S_IS_EXTERNAL(s) ((s)->sy_symbol.n_type & N_EXT)
|
||||
|
||||
/* True if symbol has been defined, ie is in N_{TEXT,DATA,BSS,ABS} or N_EXT */
|
||||
#define S_IS_DEFINED(s) ((S_GET_TYPE(s) != N_UNDF) || (S_GET_OTHER(s) != 0) || (S_GET_DESC(s) != 0))
|
||||
|
||||
#define S_IS_REGISTER(s) ((s)->sy_symbol.n_type == N_REGISTER)
|
||||
|
||||
/* True if a debug special symbol entry */
|
||||
#define S_IS_DEBUG(s) ((s)->sy_symbol.n_type & N_STAB)
|
||||
/* True if a symbol is local symbol name */
|
||||
/* A symbol name whose name begin with ^A is a gas internal pseudo symbol
|
||||
nameless symbols come from .stab directives. */
|
||||
#define S_IS_LOCAL(s) (S_GET_NAME(s) && \
|
||||
!S_IS_DEBUG(s) && \
|
||||
(S_GET_NAME(s)[0] == '\001' || \
|
||||
(S_LOCAL_NAME(s) && !flagseen['L'])))
|
||||
/* True if a symbol is not defined in this file */
|
||||
#define S_IS_EXTERN(s) ((s)->sy_symbol.n_type & N_EXT)
|
||||
/* True if the symbol has been generated because of a .stabd directive */
|
||||
#define S_IS_STABD(s) (S_GET_NAME(s) == (char *)0)
|
||||
|
||||
/* Accessors */
|
||||
/* The value of the symbol */
|
||||
#define S_GET_VALUE(s) (((s)->sy_symbol.n_value))
|
||||
/* The name of the symbol */
|
||||
#define S_GET_NAME(s) ((s)->sy_symbol.n_un.n_name)
|
||||
/* The pointer to the string table */
|
||||
#define S_GET_OFFSET(s) ((s)->sy_symbol.n_un.n_strx)
|
||||
/* The type of the symbol */
|
||||
#define S_GET_TYPE(s) ((s)->sy_symbol.n_type & N_TYPE)
|
||||
/* The numeric value of the segment */
|
||||
#define S_GET_SEGMENT(s) (N_TYPE_seg[S_GET_TYPE(s)])
|
||||
/* The n_other expression value */
|
||||
#define S_GET_OTHER(s) ((s)->sy_symbol.n_other)
|
||||
/* The n_desc expression value */
|
||||
#define S_GET_DESC(s) ((s)->sy_symbol.n_desc)
|
||||
|
||||
/* Modifiers */
|
||||
/* Set the value of the symbol */
|
||||
#define S_SET_VALUE(s,v) ((s)->sy_symbol.n_value = (unsigned long) (v))
|
||||
/* Assume that a symbol cannot be simultaneously in more than on segment */
|
||||
/* set segment */
|
||||
#define S_SET_SEGMENT(s,seg) ((s)->sy_symbol.n_type &= ~N_TYPE,(s)->sy_symbol.n_type|=SEGMENT_TO_SYMBOL_TYPE(seg))
|
||||
/* The symbol is external */
|
||||
#define S_SET_EXTERNAL(s) ((s)->sy_symbol.n_type |= N_EXT)
|
||||
/* The symbol is not external */
|
||||
#define S_CLEAR_EXTERNAL(s) ((s)->sy_symbol.n_type &= ~N_EXT)
|
||||
/* Set the name of the symbol */
|
||||
#define S_SET_NAME(s,v) ((s)->sy_symbol.n_un.n_name = (v))
|
||||
/* Set the offset in the string table */
|
||||
#define S_SET_OFFSET(s,v) ((s)->sy_symbol.n_un.n_strx = (v))
|
||||
/* Set the n_other expression value */
|
||||
#define S_SET_OTHER(s,v) ((s)->sy_symbol.n_other = (v))
|
||||
/* Set the n_desc expression value */
|
||||
#define S_SET_DESC(s,v) ((s)->sy_symbol.n_desc = (v))
|
||||
|
||||
/* File header macro and type definition */
|
||||
|
||||
#define H_GET_FILE_SIZE(h) (sizeof(struct exec) + \
|
||||
H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \
|
||||
H_GET_SYMBOL_TABLE_SIZE(h) + \
|
||||
H_GET_TEXT_RELOCATION_SIZE(h) + \
|
||||
H_GET_DATA_RELOCATION_SIZE(h) + \
|
||||
(h)->string_table_size)
|
||||
|
||||
#define H_GET_TEXT_SIZE(h) ((h)->header.a_text)
|
||||
#define H_GET_DATA_SIZE(h) ((h)->header.a_data)
|
||||
#define H_GET_BSS_SIZE(h) ((h)->header.a_bss)
|
||||
#define H_GET_TEXT_RELOCATION_SIZE(h) ((h)->header.a_trsize)
|
||||
#define H_GET_DATA_RELOCATION_SIZE(h) ((h)->header.a_drsize)
|
||||
#define H_GET_SYMBOL_TABLE_SIZE(h) ((h)->header.a_syms)
|
||||
#define H_GET_MAGIC_NUMBER(h) ((h)->header.a_info)
|
||||
#define H_GET_ENTRY_POINT(h) ((h)->header.a_entry)
|
||||
#define H_GET_STRING_SIZE(h) ((h)->string_table_size)
|
||||
#ifdef EXEC_MACHINE_TYPE
|
||||
#define H_GET_MACHINE_TYPE(h) ((h)->header.a_machtype)
|
||||
#endif /* EXEC_MACHINE_TYPE */
|
||||
#ifdef EXEC_VERSION
|
||||
#define H_GET_VERSION(h) ((h)->header.a_version)
|
||||
#endif /* EXEC_VERSION */
|
||||
|
||||
#define H_SET_TEXT_SIZE(h,v) ((h)->header.a_text = md_section_align(SEG_TEXT, (v)))
|
||||
#define H_SET_DATA_SIZE(h,v) ((h)->header.a_data = md_section_align(SEG_DATA, (v)))
|
||||
#define H_SET_BSS_SIZE(h,v) ((h)->header.a_bss = md_section_align(SEG_BSS, (v)))
|
||||
|
||||
#define H_SET_RELOCATION_SIZE(h,t,d) (H_SET_TEXT_RELOCATION_SIZE((h),(t)),\
|
||||
H_SET_DATA_RELOCATION_SIZE((h),(d)))
|
||||
|
||||
#define H_SET_TEXT_RELOCATION_SIZE(h,v) ((h)->header.a_trsize = (v))
|
||||
#define H_SET_DATA_RELOCATION_SIZE(h,v) ((h)->header.a_drsize = (v))
|
||||
#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->header.a_syms = (v) * \
|
||||
sizeof(struct nlist))
|
||||
|
||||
#define H_SET_MAGIC_NUMBER(h,v) ((h)->header.a_info = (v))
|
||||
|
||||
#define H_SET_ENTRY_POINT(h,v) ((h)->header.a_entry = (v))
|
||||
#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v))
|
||||
#ifdef EXEC_MACHINE_TYPE
|
||||
#define H_SET_MACHINE_TYPE(h,v) ((h)->header.a_machtype = (v))
|
||||
#endif /* EXEC_MACHINE_TYPE */
|
||||
#ifdef EXEC_VERSION
|
||||
#define H_SET_VERSION(h,v) ((h)->header.a_version = (v))
|
||||
#endif /* EXEC_VERSION */
|
||||
|
||||
/*
|
||||
* Current means for getting the name of a segment.
|
||||
* This will change for infinite-segments support (e.g. COFF).
|
||||
*/
|
||||
#define segment_name(seg) ( seg_name[(int)(seg)] )
|
||||
extern char *const seg_name[];
|
||||
|
||||
typedef struct {
|
||||
struct exec header; /* a.out header */
|
||||
long string_table_size; /* names + '\0' + sizeof(int) */
|
||||
} object_headers;
|
||||
|
||||
/* line numbering stuff. */
|
||||
#define OBJ_EMIT_LINENO(a, b, c) ;
|
||||
#define obj_pre_write_hook(a) ;
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of obj-aout.h */
|
485
gas/config/obj-bout.c
Normal file
485
gas/config/obj-bout.c
Normal file
|
@ -0,0 +1,485 @@
|
|||
/* b.out object file format
|
||||
Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 1,
|
||||
or (at your option) any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with GAS; see the file COPYING. If not, write
|
||||
to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#include "as.h"
|
||||
#include "obstack.h"
|
||||
|
||||
const short /* in: segT out: N_TYPE bits */
|
||||
seg_N_TYPE[] = {
|
||||
N_ABS,
|
||||
N_TEXT,
|
||||
N_DATA,
|
||||
N_BSS,
|
||||
N_UNDF, /* unknown */
|
||||
N_UNDF, /* absent */
|
||||
N_UNDF, /* pass1 */
|
||||
N_UNDF, /* error */
|
||||
N_UNDF, /* bignum/flonum */
|
||||
N_UNDF, /* difference */
|
||||
N_REGISTER, /* register */
|
||||
};
|
||||
|
||||
const segT N_TYPE_seg [N_TYPE+2] = { /* N_TYPE == 0x1E = 32-2 */
|
||||
SEG_UNKNOWN, /* N_UNDF == 0 */
|
||||
SEG_GOOF,
|
||||
SEG_ABSOLUTE, /* N_ABS == 2 */
|
||||
SEG_GOOF,
|
||||
SEG_TEXT, /* N_TEXT == 4 */
|
||||
SEG_GOOF,
|
||||
SEG_DATA, /* N_DATA == 6 */
|
||||
SEG_GOOF,
|
||||
SEG_BSS, /* N_BSS == 8 */
|
||||
SEG_GOOF,
|
||||
SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
|
||||
SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
|
||||
SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
|
||||
SEG_REGISTER, /* dummy N_REGISTER for regs = 30 */
|
||||
SEG_GOOF,
|
||||
};
|
||||
|
||||
#ifdef __STDC__
|
||||
static void obj_bout_stab(int what);
|
||||
static void obj_bout_line(void);
|
||||
static void obj_bout_desc(void);
|
||||
#else /* __STDC__ */
|
||||
static void obj_bout_desc();
|
||||
static void obj_bout_stab();
|
||||
static void obj_bout_line();
|
||||
#endif /* __STDC__ */
|
||||
|
||||
const pseudo_typeS obj_pseudo_table[] = {
|
||||
/* stabs (aka a.out aka b.out directives for debug symbols) */
|
||||
{ "desc", obj_bout_desc, 0 }, /* def */
|
||||
{ "line", obj_bout_line, 0 }, /* source code line number */
|
||||
{ "stabd", obj_bout_stab, 'd' }, /* stabs */
|
||||
{ "stabn", obj_bout_stab, 'n' }, /* stabs */
|
||||
{ "stabs", obj_bout_stab, 's' }, /* stabs */
|
||||
|
||||
/* coff debugging directives. Currently ignored silently */
|
||||
{ "def", s_ignore, 0 },
|
||||
{ "dim", s_ignore, 0 },
|
||||
{ "endef", s_ignore, 0 },
|
||||
{ "ln", s_ignore, 0 },
|
||||
{ "scl", s_ignore, 0 },
|
||||
{ "size", s_ignore, 0 },
|
||||
{ "tag", s_ignore, 0 },
|
||||
{ "type", s_ignore, 0 },
|
||||
{ "val", s_ignore, 0 },
|
||||
|
||||
/* other stuff we don't handle */
|
||||
{ "ABORT", s_ignore, 0 },
|
||||
{ "ident", s_ignore, 0 },
|
||||
|
||||
{ NULL} /* end sentinel */
|
||||
}; /* obj_pseudo_table */
|
||||
|
||||
/* Relocation. */
|
||||
|
||||
/*
|
||||
* 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
|
||||
};
|
||||
|
||||
/*
|
||||
* emit_relocations()
|
||||
*
|
||||
* Crawl along a fixS chain. Emit the segment's relocations.
|
||||
*/
|
||||
void obj_emit_relocations(where, fixP, segment_address_in_file)
|
||||
char **where;
|
||||
fixS *fixP; /* Fixup chain for this segment. */
|
||||
relax_addressT segment_address_in_file;
|
||||
{
|
||||
struct reloc_info_generic ri;
|
||||
register symbolS * symbolP;
|
||||
|
||||
/* If a machine dependent emitter is needed, call it instead. */
|
||||
if (md_emit_relocations) {
|
||||
(*md_emit_relocations) (fixP, segment_address_in_file);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* JF this is for paranoia */
|
||||
bzero((char *)&ri,sizeof(ri));
|
||||
for (; fixP; fixP = fixP->fx_next) {
|
||||
if ((symbolP = fixP->fx_addsy) != 0) {
|
||||
ri . r_bsr = fixP->fx_bsr;
|
||||
ri . r_disp = fixP->fx_im_disp;
|
||||
ri . r_callj = fixP->fx_callj;
|
||||
ri . r_length = nbytes_r_length [fixP->fx_size];
|
||||
ri . r_pcrel = fixP->fx_pcrel;
|
||||
ri . r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file;
|
||||
|
||||
if (S_GET_TYPE(symbolP) == N_UNDF) {
|
||||
ri . r_extern = 1;
|
||||
ri . r_symbolnum = symbolP->sy_number;
|
||||
} else {
|
||||
ri . r_extern = 0;
|
||||
ri . r_symbolnum = S_GET_TYPE(symbolP);
|
||||
}
|
||||
|
||||
/* Output the relocation information in machine-dependent form. */
|
||||
md_ri_to_chars(*where, &ri);
|
||||
*where += md_reloc_size;
|
||||
}
|
||||
}
|
||||
} /* emit_relocations() */
|
||||
|
||||
/* Aout file generation & utilities */
|
||||
|
||||
/* Convert a lvalue to machine dependent data */
|
||||
void obj_header_append(where, headers)
|
||||
char **where;
|
||||
object_headers *headers;
|
||||
{
|
||||
/* Always leave in host byte order */
|
||||
|
||||
headers->header.a_talign = section_alignment[SEG_TEXT];
|
||||
|
||||
if (headers->header.a_talign < 2){
|
||||
headers->header.a_talign = 2;
|
||||
} /* force to at least 2 */
|
||||
|
||||
headers->header.a_dalign = section_alignment[SEG_DATA];
|
||||
headers->header.a_balign = section_alignment[SEG_BSS];
|
||||
|
||||
headers->header.a_tload = 0;
|
||||
headers->header.a_dload = md_section_align(SEG_DATA, headers->header.a_text);
|
||||
|
||||
append(where, (char *) &headers->header, sizeof(headers->header));
|
||||
} /* a_header_append() */
|
||||
|
||||
void obj_symbol_to_chars(where, symbolP)
|
||||
char **where;
|
||||
symbolS *symbolP;
|
||||
{
|
||||
/* leave in host byte order */
|
||||
append(where, (char *)&symbolP->sy_symbol, sizeof(obj_symbol_type));
|
||||
} /* obj_symbol_to_chars() */
|
||||
|
||||
void obj_emit_symbols(where, symbol_rootP)
|
||||
char **where;
|
||||
symbolS *symbol_rootP;
|
||||
{
|
||||
symbolS * symbolP;
|
||||
|
||||
/*
|
||||
* Emit all symbols left in the symbol chain.
|
||||
*/
|
||||
for(symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
|
||||
/* Used to save the offset of the name. It is used to point
|
||||
to the string in memory but must be a file offset. */
|
||||
char *temp;
|
||||
|
||||
temp = S_GET_NAME(symbolP);
|
||||
S_SET_OFFSET(symbolP, symbolP->sy_name_offset);
|
||||
|
||||
/* Any symbol still undefined and is not a dbg symbol is made N_EXT. */
|
||||
if (!S_IS_DEBUG(symbolP) && !S_IS_DEFINED(symbolP)) S_SET_EXTERNAL(symbolP);
|
||||
|
||||
obj_symbol_to_chars(where, symbolP);
|
||||
S_SET_NAME(symbolP,temp);
|
||||
}
|
||||
} /* emit_symbols() */
|
||||
|
||||
void obj_symbol_new_hook(symbolP)
|
||||
symbolS *symbolP;
|
||||
{
|
||||
S_SET_OTHER(symbolP, 0);
|
||||
S_SET_DESC(symbolP, 0);
|
||||
return;
|
||||
} /* obj_symbol_new_hook() */
|
||||
|
||||
static void obj_bout_line() {
|
||||
/* Assume delimiter is part of expression. */
|
||||
/* BSD4.2 as fails with delightful bug, so we */
|
||||
/* are not being incompatible here. */
|
||||
new_logical_line ((char *)NULL, (int)(get_absolute_expression ()));
|
||||
demand_empty_rest_of_line();
|
||||
} /* obj_bout_line() */
|
||||
|
||||
/*
|
||||
* stab()
|
||||
*
|
||||
* Handle .stabX directives, which used to be open-coded.
|
||||
* So much creeping featurism overloaded the semantics that we decided
|
||||
* to put all .stabX thinking in one place. Here.
|
||||
*
|
||||
* We try to make any .stabX directive legal. Other people's AS will often
|
||||
* do assembly-time consistency checks: eg assigning meaning to n_type bits
|
||||
* and "protecting" you from setting them to certain values. (They also zero
|
||||
* certain bits before emitting symbols. Tut tut.)
|
||||
*
|
||||
* If an expression is not absolute we either gripe or use the relocation
|
||||
* information. Other people's assemblers silently forget information they
|
||||
* don't need and invent information they need that you didn't supply.
|
||||
*
|
||||
* .stabX directives always make a symbol table entry. It may be junk if
|
||||
* the rest of your .stabX directive is malformed.
|
||||
*/
|
||||
static void obj_bout_stab(what)
|
||||
int what;
|
||||
{
|
||||
register symbolS * symbolP = 0;
|
||||
register char * string;
|
||||
int saved_type = 0;
|
||||
int length;
|
||||
int goof; /* TRUE if we have aborted. */
|
||||
long longint;
|
||||
|
||||
/*
|
||||
* Enter with input_line_pointer pointing past .stabX and any following
|
||||
* whitespace.
|
||||
*/
|
||||
goof = 0; /* JF who forgot this?? */
|
||||
if (what == 's') {
|
||||
string = demand_copy_C_string(& length);
|
||||
SKIP_WHITESPACE();
|
||||
if (*input_line_pointer == ',')
|
||||
input_line_pointer ++;
|
||||
else {
|
||||
as_bad("I need a comma after symbol's name");
|
||||
goof = 1;
|
||||
}
|
||||
} else
|
||||
string = "";
|
||||
|
||||
/*
|
||||
* Input_line_pointer->after ','. String->symbol name.
|
||||
*/
|
||||
if (!goof) {
|
||||
symbolP = symbol_new(string,
|
||||
SEG_UNKNOWN,
|
||||
0,
|
||||
(struct frag *)0);
|
||||
switch (what) {
|
||||
case 'd':
|
||||
S_SET_NAME(symbolP,NULL); /* .stabd feature. */
|
||||
S_SET_VALUE(symbolP,obstack_next_free(&frags) -
|
||||
frag_now->fr_literal);
|
||||
symbolP->sy_frag = frag_now;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
symbolP->sy_frag = &zero_address_frag;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
symbolP->sy_frag = & zero_address_frag;
|
||||
break;
|
||||
|
||||
default:
|
||||
BAD_CASE(what);
|
||||
break;
|
||||
}
|
||||
if (get_absolute_expression_and_terminator(& longint) == ',')
|
||||
symbolP->sy_symbol.n_type = saved_type = longint;
|
||||
else {
|
||||
as_bad("I want a comma after the n_type expression");
|
||||
goof = 1;
|
||||
input_line_pointer--; /* Backup over a non-',' char. */
|
||||
}
|
||||
}
|
||||
if (! goof) {
|
||||
if (get_absolute_expression_and_terminator (& longint) == ',')
|
||||
S_SET_OTHER(symbolP,longint);
|
||||
else {
|
||||
as_bad("I want a comma after the n_other expression");
|
||||
goof = 1;
|
||||
input_line_pointer--; /* Backup over a non-',' char. */
|
||||
}
|
||||
}
|
||||
if (! goof) {
|
||||
S_SET_DESC(symbolP, get_absolute_expression ());
|
||||
if (what == 's' || what == 'n') {
|
||||
if (* input_line_pointer != ',') {
|
||||
as_bad("I want a comma after the n_desc expression");
|
||||
goof = 1;
|
||||
} else {
|
||||
input_line_pointer ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((! goof) && (what=='s' || what=='n')) {
|
||||
pseudo_set(symbolP);
|
||||
symbolP->sy_symbol.n_type = saved_type;
|
||||
}
|
||||
if (goof)
|
||||
ignore_rest_of_line ();
|
||||
else
|
||||
demand_empty_rest_of_line ();
|
||||
} /* obj_bout_stab() */
|
||||
|
||||
static void obj_bout_desc() {
|
||||
register char *name;
|
||||
register char c;
|
||||
register char *p;
|
||||
register symbolS * symbolP;
|
||||
register int temp;
|
||||
|
||||
/*
|
||||
* Frob invented at RMS' request. Set the n_desc of a symbol.
|
||||
*/
|
||||
name = input_line_pointer;
|
||||
c = get_symbol_end();
|
||||
p = input_line_pointer;
|
||||
* p = c;
|
||||
SKIP_WHITESPACE();
|
||||
if (*input_line_pointer != ',') {
|
||||
*p = 0;
|
||||
as_bad("Expected comma after name \"%s\"", name);
|
||||
*p = c;
|
||||
ignore_rest_of_line();
|
||||
} else {
|
||||
input_line_pointer ++;
|
||||
temp = get_absolute_expression ();
|
||||
*p = 0;
|
||||
symbolP = symbol_find_or_make(name);
|
||||
*p = c;
|
||||
S_SET_DESC(symbolP,temp);
|
||||
}
|
||||
demand_empty_rest_of_line();
|
||||
} /* obj_bout_desc() */
|
||||
|
||||
void obj_read_begin_hook() {
|
||||
return;
|
||||
} /* obj_read_begin_hook() */
|
||||
|
||||
void obj_crawl_symbol_chain(headers)
|
||||
object_headers *headers;
|
||||
{
|
||||
symbolS **symbolPP;
|
||||
symbolS *symbolP;
|
||||
int symbol_number = 0;
|
||||
|
||||
/* JF deal with forward references first... */
|
||||
for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
|
||||
if (symbolP->sy_forward) {
|
||||
S_SET_VALUE(symbolP, S_GET_VALUE(symbolP)
|
||||
+ S_GET_VALUE(symbolP->sy_forward)
|
||||
+ symbolP->sy_forward->sy_frag->fr_address);
|
||||
|
||||
symbolP->sy_forward=0;
|
||||
} /* if it has a forward reference */
|
||||
} /* walk the symbol chain */
|
||||
|
||||
tc_crawl_symbol_chain(headers);
|
||||
|
||||
symbolPP = & symbol_rootP; /*->last symbol chain link. */
|
||||
while ((symbolP = *symbolPP) != NULL) {
|
||||
if (flagseen['R'] && (S_GET_SEGMENT(symbolP) == SEG_DATA)) {
|
||||
S_SET_SEGMENT(symbolP, SEG_TEXT);
|
||||
} /* if pusing data into text */
|
||||
|
||||
S_SET_VALUE(symbolP, S_GET_VALUE(symbolP) + symbolP->sy_frag->fr_address);
|
||||
|
||||
/* OK, here is how we decide which symbols go out into the
|
||||
brave new symtab. Symbols that do are:
|
||||
|
||||
* symbols with no name (stabd's?)
|
||||
* symbols with debug info in their N_TYPE
|
||||
|
||||
Symbols that don't are:
|
||||
* symbols that are registers
|
||||
* symbols with \1 as their 3rd character (numeric labels)
|
||||
* "local labels" as defined by S_LOCAL_NAME(name)
|
||||
if the -L switch was passed to gas.
|
||||
|
||||
All other symbols are output. We complain if a deleted
|
||||
symbol was marked external. */
|
||||
|
||||
|
||||
if (1
|
||||
&& !S_IS_REGISTER(symbolP)
|
||||
&& (!S_GET_NAME(symbolP)
|
||||
|| S_IS_DEBUG(symbolP)
|
||||
#ifdef TC_I960
|
||||
/* FIXME-SOON this ifdef seems highly dubious to me. xoxorich. */
|
||||
|| !S_IS_DEFINED(symbolP)
|
||||
|| S_IS_EXTERNAL(symbolP)
|
||||
#endif /* TC_I960 */
|
||||
|| (S_GET_NAME(symbolP)[0] != '\001' && (flagseen ['L'] || ! S_LOCAL_NAME(symbolP))))) {
|
||||
symbolP->sy_number = symbol_number++;
|
||||
|
||||
/* The + 1 after strlen account for the \0 at the
|
||||
end of each string */
|
||||
if (!S_IS_STABD(symbolP)) {
|
||||
/* Ordinary case. */
|
||||
symbolP->sy_name_offset = string_byte_count;
|
||||
string_byte_count += strlen(S_GET_NAME(symbolP)) + 1;
|
||||
}
|
||||
else /* .Stabd case. */
|
||||
symbolP->sy_name_offset = 0;
|
||||
symbolPP = &(symbol_next(symbolP));
|
||||
} else {
|
||||
if (S_IS_EXTERNAL(symbolP) || !S_IS_DEFINED(symbolP)) {
|
||||
as_bad("Local symbol %s never defined", S_GET_NAME(symbolP));
|
||||
} /* oops. */
|
||||
|
||||
/* Unhook it from the chain */
|
||||
*symbolPP = symbol_next(symbolP);
|
||||
} /* if this symbol should be in the output */
|
||||
} /* for each symbol */
|
||||
|
||||
H_SET_SYMBOL_TABLE_SIZE(headers, symbol_number);
|
||||
|
||||
return;
|
||||
} /* obj_crawl_symbol_chain() */
|
||||
|
||||
/*
|
||||
* Find strings by crawling along symbol table chain.
|
||||
*/
|
||||
|
||||
void obj_emit_strings(where)
|
||||
char **where;
|
||||
{
|
||||
symbolS *symbolP;
|
||||
|
||||
#ifdef CROSS_ASSEMBLE
|
||||
/* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */
|
||||
md_number_to_chars(*where, string_byte_count, sizeof(string_byte_count));
|
||||
*where += sizeof(string_byte_count);
|
||||
#else /* CROSS_ASSEMBLE */
|
||||
append(where, (char *) &string_byte_count, (unsigned long) sizeof(string_byte_count));
|
||||
#endif /* CROSS_ASSEMBLE */
|
||||
|
||||
for(symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
|
||||
if(S_GET_NAME(symbolP))
|
||||
append(where, S_GET_NAME(symbolP), (unsigned long)(strlen (S_GET_NAME(symbolP)) + 1));
|
||||
} /* walk symbol chain */
|
||||
|
||||
return;
|
||||
} /* obj_emit_strings() */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of obj-bout.c */
|
312
gas/config/obj-bout.h
Normal file
312
gas/config/obj-bout.h
Normal file
|
@ -0,0 +1,312 @@
|
|||
/* b.out object file format
|
||||
Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 1,
|
||||
or (at your option) any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with GAS; see the file COPYING. If not, write
|
||||
to the Free Software Foundation, 675 Mass Ave, Cambridge, MA
|
||||
02139, USA. */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is a modified version of 'a.out.h'. It is to be used in all GNU
|
||||
* tools modified to support the i80960 b.out format (or tools that operate on
|
||||
* object files created by such tools).
|
||||
*
|
||||
* All i80960 development is done in a CROSS-DEVELOPMENT environment. I.e.,
|
||||
* object code is generated on, and executed under the direction of a symbolic
|
||||
* debugger running on, a host system. We do not want to be subject to the
|
||||
* vagaries of which host it is or whether it supports COFF or a.out format, or
|
||||
* anything else. We DO want to:
|
||||
*
|
||||
* o always generate the same format object files, regardless of host.
|
||||
*
|
||||
* o have an 'a.out' header that we can modify for our own purposes
|
||||
* (the 80960 is typically an embedded processor and may require
|
||||
* enhanced linker support that the normal a.out.h header can't
|
||||
* accommodate).
|
||||
*
|
||||
* As for byte-ordering, the following rules apply:
|
||||
*
|
||||
* o Text and data that is actually downloaded to the target is always
|
||||
* in i80960 (little-endian) order.
|
||||
*
|
||||
* o All other numbers (in the header, symbols, relocation directives)
|
||||
* are in host byte-order: object files CANNOT be lifted from a
|
||||
* little-end host and used on a big-endian (or vice versa) without
|
||||
* modification.
|
||||
*
|
||||
* o The downloader ('comm960') takes care to generate a pseudo-header
|
||||
* with correct (i80960) byte-ordering before shipping text and data
|
||||
* off to the NINDY monitor in the target systems. Symbols and
|
||||
* relocation info are never sent to the target.
|
||||
*/
|
||||
|
||||
|
||||
#define OBJ_BOUT 1
|
||||
|
||||
#include "targ-cpu.h"
|
||||
|
||||
/* bout uses host byte order for headers */
|
||||
#ifdef CROSS_ASSEMBLE
|
||||
#undef CROSS_ASSEMBLE
|
||||
#endif /* CROSS_ASSEMBLE */
|
||||
|
||||
/* We want \v. */
|
||||
#define BACKSLASH_V 1
|
||||
|
||||
#define OBJ_DEFAULT_OUTPUT_FILE_NAME "b.out"
|
||||
|
||||
extern const short seg_N_TYPE[];
|
||||
extern const segT N_TYPE_seg[];
|
||||
|
||||
#define BMAGIC 0415
|
||||
/* We don't accept the following (see N_BADMAG macro).
|
||||
* They're just here so GNU code will compile.
|
||||
*/
|
||||
#define OMAGIC 0407 /* old impure format */
|
||||
#define NMAGIC 0410 /* read-only text */
|
||||
#define ZMAGIC 0413 /* demand load format */
|
||||
|
||||
#ifndef DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE
|
||||
#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (BMAGIC)
|
||||
#endif /* DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE */
|
||||
|
||||
/* FILE HEADER
|
||||
* All 'lengths' are given as a number of bytes.
|
||||
* All 'alignments' are for relinkable files only; an alignment of
|
||||
* 'n' indicates the corresponding segment must begin at an
|
||||
* address that is a multiple of (2**n).
|
||||
*/
|
||||
struct exec {
|
||||
/* Standard stuff */
|
||||
unsigned long a_magic; /* Identifies this as a b.out file */
|
||||
unsigned long a_text; /* Length of text */
|
||||
unsigned long a_data; /* Length of data */
|
||||
unsigned long a_bss; /* Length of runtime uninitialized data area */
|
||||
unsigned long a_syms; /* Length of symbol table */
|
||||
unsigned long a_entry; /* Runtime start address */
|
||||
unsigned long a_trsize; /* Length of text relocation info */
|
||||
unsigned long a_drsize; /* Length of data relocation info */
|
||||
|
||||
/* Added for i960 */
|
||||
unsigned long a_tload; /* Text runtime load address */
|
||||
unsigned long a_dload; /* Data runtime load address */
|
||||
unsigned char a_talign; /* Alignment of text segment */
|
||||
unsigned char a_dalign; /* Alignment of data segment */
|
||||
unsigned char a_balign; /* Alignment of bss segment */
|
||||
unsigned char unused; /* (Just to make struct size a multiple of 4) */
|
||||
};
|
||||
|
||||
#define N_BADMAG(x) (((x).a_magic)!=BMAGIC)
|
||||
#define N_TXTOFF(x) ( sizeof(struct exec) )
|
||||
#define N_DATOFF(x) ( N_TXTOFF(x) + (x).a_text )
|
||||
#define N_TROFF(x) ( N_DATOFF(x) + (x).a_data )
|
||||
#define N_DROFF(x) ( N_TROFF(x) + (x).a_trsize )
|
||||
#define N_SYMOFF(x) ( N_DROFF(x) + (x).a_drsize )
|
||||
#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms )
|
||||
|
||||
/* A single entry in the symbol table
|
||||
*/
|
||||
struct nlist {
|
||||
union {
|
||||
char *n_name;
|
||||
struct nlist *n_next;
|
||||
long n_strx; /* Index into string table */
|
||||
} n_un;
|
||||
unsigned char n_type; /* See below */
|
||||
char n_other; /* Used in i80960 support -- see below */
|
||||
short n_desc;
|
||||
unsigned long n_value;
|
||||
};
|
||||
|
||||
typedef struct nlist obj_symbol_type;
|
||||
|
||||
/* Legal values of n_type
|
||||
*/
|
||||
#define N_UNDF 0 /* Undefined symbol */
|
||||
#define N_ABS 2 /* Absolute symbol */
|
||||
#define N_TEXT 4 /* Text symbol */
|
||||
#define N_DATA 6 /* Data symbol */
|
||||
#define N_BSS 8 /* BSS symbol */
|
||||
#define N_FN 31 /* Filename symbol */
|
||||
|
||||
#define N_EXT 1 /* External symbol (OR'd in with one of above) */
|
||||
#define N_TYPE 036 /* Mask for all the type bits */
|
||||
#define N_STAB 0340 /* Mask for all bits used for SDB entries */
|
||||
|
||||
#ifndef CUSTOM_RELOC_FORMAT
|
||||
struct relocation_info {
|
||||
int r_address; /* File address of item to be relocated */
|
||||
unsigned
|
||||
r_index:24,/* Index of symbol on which relocation is based*/
|
||||
r_pcrel:1, /* 1 => relocate PC-relative; else absolute
|
||||
* On i960, pc-relative implies 24-bit
|
||||
* address, absolute implies 32-bit.
|
||||
*/
|
||||
r_length:2, /* Number of bytes to relocate:
|
||||
* 0 => 1 byte
|
||||
* 1 => 2 bytes
|
||||
* 2 => 4 bytes -- only value used for i960
|
||||
*/
|
||||
r_extern:1,
|
||||
r_bsr:1, /* Something for the GNU NS32K assembler */
|
||||
r_disp:1, /* Something for the GNU NS32K assembler */
|
||||
r_callj:1, /* 1 if relocation target is an i960 'callj' */
|
||||
nuthin:1; /* Unused */
|
||||
};
|
||||
#endif /* CUSTOM_RELOC_FORMAT */
|
||||
|
||||
/* If compiler generate leading underscores, remove them. */
|
||||
|
||||
#ifndef STRIP_UNDERSCORE
|
||||
#define STRIP_UNDERSCORE 0
|
||||
#endif /* STRIP_UNDERSCORE */
|
||||
|
||||
/*
|
||||
* Macros to extract information from a symbol table entry.
|
||||
* This syntaxic indirection allows independence regarding a.out or coff.
|
||||
* The argument (s) of all these macros is a pointer to a symbol table entry.
|
||||
*/
|
||||
|
||||
/* Predicates */
|
||||
/* True if the symbol is external */
|
||||
#define S_IS_EXTERNAL(s) ((s)->sy_symbol.n_type & N_EXT)
|
||||
|
||||
/* True if symbol has been defined, ie is in N_{TEXT,DATA,BSS,ABS} or N_EXT */
|
||||
#define S_IS_DEFINED(s) ((S_GET_TYPE(s) != N_UNDF) || (S_GET_DESC(s) != 0))
|
||||
#define S_IS_REGISTER(s) ((s)->sy_symbol.n_type == N_REGISTER)
|
||||
|
||||
/* True if a debug special symbol entry */
|
||||
#define S_IS_DEBUG(s) ((s)->sy_symbol.n_type & N_STAB)
|
||||
/* True if a symbol is local symbol name */
|
||||
/* A symbol name whose name begin with ^A is a gas internal pseudo symbol
|
||||
nameless symbols come from .stab directives. */
|
||||
#define S_IS_LOCAL(s) (S_GET_NAME(s) && \
|
||||
!S_IS_DEBUG(s) && \
|
||||
(S_GET_NAME(s)[0] == '\001' || \
|
||||
(S_LOCAL_NAME(s) && !flagseen['L'])))
|
||||
/* True if a symbol is not defined in this file */
|
||||
#define S_IS_EXTERN(s) ((s)->sy_symbol.n_type & N_EXT)
|
||||
/* True if the symbol has been generated because of a .stabd directive */
|
||||
#define S_IS_STABD(s) (S_GET_NAME(s) == NULL)
|
||||
|
||||
/* Accessors */
|
||||
/* The value of the symbol */
|
||||
#define S_GET_VALUE(s) ((long) ((s)->sy_symbol.n_value))
|
||||
/* The name of the symbol */
|
||||
#define S_GET_NAME(s) ((s)->sy_symbol.n_un.n_name)
|
||||
/* The pointer to the string table */
|
||||
#define S_GET_OFFSET(s) ((s)->sy_symbol.n_un.n_strx)
|
||||
/* The type of the symbol */
|
||||
#define S_GET_TYPE(s) ((s)->sy_symbol.n_type & N_TYPE)
|
||||
/* The numeric value of the segment */
|
||||
#define S_GET_SEGMENT(s) (N_TYPE_seg[S_GET_TYPE(s)])
|
||||
/* The n_other expression value */
|
||||
#define S_GET_OTHER(s) ((s)->sy_symbol.n_other)
|
||||
/* The n_desc expression value */
|
||||
#define S_GET_DESC(s) ((s)->sy_symbol.n_desc)
|
||||
|
||||
/* Modifiers */
|
||||
/* Set the value of the symbol */
|
||||
#define S_SET_VALUE(s,v) ((s)->sy_symbol.n_value = (unsigned long) (v))
|
||||
/* Assume that a symbol cannot be simultaneously in more than on segment */
|
||||
/* set segment */
|
||||
#define S_SET_SEGMENT(s,seg) ((s)->sy_symbol.n_type &= ~N_TYPE,(s)->sy_symbol.n_type|=SEGMENT_TO_SYMBOL_TYPE(seg))
|
||||
/* The symbol is external */
|
||||
#define S_SET_EXTERNAL(s) ((s)->sy_symbol.n_type |= N_EXT)
|
||||
/* The symbol is not external */
|
||||
#define S_CLEAR_EXTERNAL(s) ((s)->sy_symbol.n_type &= ~N_EXT)
|
||||
/* Set the name of the symbol */
|
||||
#define S_SET_NAME(s,v) ((s)->sy_symbol.n_un.n_name = (v))
|
||||
/* Set the offset in the string table */
|
||||
#define S_SET_OFFSET(s,v) ((s)->sy_symbol.n_un.n_strx = (v))
|
||||
/* Set the n_other expression value */
|
||||
#define S_SET_OTHER(s,v) ((s)->sy_symbol.n_other = (v))
|
||||
/* Set the n_desc expression value */
|
||||
#define S_SET_DESC(s,v) ((s)->sy_symbol.n_desc = (v))
|
||||
|
||||
/* File header macro and type definition */
|
||||
|
||||
#define H_GET_FILE_SIZE(h) (sizeof(struct exec) + \
|
||||
H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \
|
||||
H_GET_SYMBOL_TABLE_SIZE(h) + \
|
||||
H_GET_TEXT_RELOCATION_SIZE(h) + \
|
||||
H_GET_DATA_RELOCATION_SIZE(h) + \
|
||||
(h)->string_table_size)
|
||||
|
||||
#define H_GET_TEXT_SIZE(h) ((h)->header.a_text)
|
||||
#define H_GET_DATA_SIZE(h) ((h)->header.a_data)
|
||||
#define H_GET_BSS_SIZE(h) ((h)->header.a_bss)
|
||||
#define H_GET_TEXT_RELOCATION_SIZE(h) ((h)->header.a_trsize)
|
||||
#define H_GET_DATA_RELOCATION_SIZE(h) ((h)->header.a_drsize)
|
||||
#define H_GET_SYMBOL_TABLE_SIZE(h) ((h)->header.a_syms)
|
||||
#define H_GET_MAGIC_NUMBER(h) ((h)->header.a_info)
|
||||
#define H_GET_ENTRY_POINT(h) ((h)->header.a_entry)
|
||||
#define H_GET_STRING_SIZE(h) ((h)->string_table_size)
|
||||
#ifdef EXEC_MACHINE_TYPE
|
||||
#define H_GET_MACHINE_TYPE(h) ((h)->header.a_machtype)
|
||||
#endif /* EXEC_MACHINE_TYPE */
|
||||
#ifdef EXEC_VERSION
|
||||
#define H_GET_VERSION(h) ((h)->header.a_version)
|
||||
#endif /* EXEC_VERSION */
|
||||
|
||||
#define H_SET_TEXT_SIZE(h,v) ((h)->header.a_text = md_section_align(SEG_TEXT, (v)))
|
||||
#define H_SET_DATA_SIZE(h,v) ((h)->header.a_data = md_section_align(SEG_DATA, (v)))
|
||||
#define H_SET_BSS_SIZE(h,v) ((h)->header.a_bss = md_section_align(SEG_BSS, (v)))
|
||||
|
||||
#define H_SET_RELOCATION_SIZE(h,t,d) (H_SET_TEXT_RELOCATION_SIZE((h),(t)),\
|
||||
H_SET_DATA_RELOCATION_SIZE((h),(d)))
|
||||
|
||||
#define H_SET_TEXT_RELOCATION_SIZE(h,v) ((h)->header.a_trsize = (v))
|
||||
#define H_SET_DATA_RELOCATION_SIZE(h,v) ((h)->header.a_drsize = (v))
|
||||
#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->header.a_syms = (v) * \
|
||||
sizeof(struct nlist))
|
||||
|
||||
#define H_SET_MAGIC_NUMBER(h,v) ((h)->header.a_magic = (v))
|
||||
|
||||
#define H_SET_ENTRY_POINT(h,v) ((h)->header.a_entry = (v))
|
||||
#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v))
|
||||
#ifdef EXEC_MACHINE_TYPE
|
||||
#define H_SET_MACHINE_TYPE(h,v) ((h)->header.a_machtype = (v))
|
||||
#endif /* EXEC_MACHINE_TYPE */
|
||||
#ifdef EXEC_VERSION
|
||||
#define H_SET_VERSION(h,v) ((h)->header.a_version = (v))
|
||||
#endif /* EXEC_VERSION */
|
||||
|
||||
/*
|
||||
* Current means for getting the name of a segment.
|
||||
* This will change for infinite-segments support (e.g. COFF).
|
||||
*/
|
||||
#define segment_name(seg) ( seg_name[(int)(seg)] )
|
||||
extern char *const seg_name[];
|
||||
|
||||
typedef struct {
|
||||
struct exec header; /* a.out header */
|
||||
long string_table_size; /* names + '\0' + sizeof(int) */
|
||||
} object_headers;
|
||||
|
||||
/* unused hooks. */
|
||||
#define OBJ_EMIT_LINENO(a, b, c) ;
|
||||
#define obj_pre_write_hook(a) ;
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of obj-bout.h */
|
1772
gas/config/obj-coff.c
Normal file
1772
gas/config/obj-coff.c
Normal file
File diff suppressed because it is too large
Load diff
494
gas/config/obj-coff.h
Normal file
494
gas/config/obj-coff.h
Normal file
|
@ -0,0 +1,494 @@
|
|||
/* coff object file format
|
||||
Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#define OBJ_COFF 1
|
||||
|
||||
#include "targ-cpu.h"
|
||||
|
||||
#include "coff.gnu.h"
|
||||
|
||||
#ifdef USE_NATIVE_HEADERS
|
||||
#include <filehdr.h>
|
||||
#include <aouthdr.h>
|
||||
#include <scnhdr.h>
|
||||
#include <storclass.h>
|
||||
#include <linenum.h>
|
||||
#include <syms.h>
|
||||
#include <reloc.h>
|
||||
#include <sys/types.h>
|
||||
#endif /* USE_NATIVE_HEADERS */
|
||||
|
||||
/* Define some processor dependent values according to the processor we are
|
||||
on. */
|
||||
#ifdef TC_M68K
|
||||
|
||||
#define BYTE_ORDERING F_AR32W /* See filehdr.h for more info. */
|
||||
#ifndef FILE_HEADER_MAGIC
|
||||
#define FILE_HEADER_MAGIC MC68MAGIC /* ... */
|
||||
#endif /* FILE_HEADER_MAGIC */
|
||||
|
||||
#elif defined(TC_I386)
|
||||
|
||||
#define BYTE_ORDERING F_AR32WR /* See filehdr.h for more info. */
|
||||
#ifndef FILE_HEADER_MAGIC
|
||||
#define FILE_HEADER_MAGIC I386MAGIC /* ... */
|
||||
#endif /* FILE_HEADER_MAGIC */
|
||||
|
||||
#elif defined(TC_I960)
|
||||
|
||||
#define BYTE_ORDERING F_AR32WR /* See filehdr.h for more info. */
|
||||
#ifndef FILE_HEADER_MAGIC
|
||||
#define FILE_HEADER_MAGIC I960ROMAGIC /* ... */
|
||||
#endif /* FILE_HEADER_MAGIC */
|
||||
|
||||
#elif defined(TC_A29K)
|
||||
|
||||
#define BYTE_ORDERING F_AR32W /* big endian. */
|
||||
#ifndef FILE_HEADER_MAGIC
|
||||
#define FILE_HEADER_MAGIC SIPFBOMAGIC
|
||||
#endif /* FILE_HEADER_MAGIC */
|
||||
|
||||
#else
|
||||
you lose
|
||||
#endif
|
||||
|
||||
#ifndef OBJ_COFF_MAX_AUXENTRIES
|
||||
#define OBJ_COFF_MAX_AUXENTRIES 1
|
||||
#endif /* OBJ_COFF_MAX_AUXENTRIES */
|
||||
|
||||
extern const short seg_N_TYPE[];
|
||||
extern const segT N_TYPE_seg[];
|
||||
|
||||
/* Magic number of paged executable. */
|
||||
#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (OMAGIC)
|
||||
|
||||
/* Add these definitions to have a consistent convention for all the
|
||||
types used in COFF format. */
|
||||
#define AOUTHDR struct aouthdr
|
||||
#define AOUTHDRSZ sizeof(AOUTHDR)
|
||||
|
||||
/* SYMBOL TABLE */
|
||||
|
||||
/* targets may also set this */
|
||||
#ifndef SYMBOLS_NEED_BACKPOINTERS
|
||||
#define SYMBOLS_NEED_BACKPOINTERS 1
|
||||
#endif /* SYMBOLS_NEED_BACKPOINTERS */
|
||||
|
||||
/* Symbol table entry data type */
|
||||
|
||||
typedef struct {
|
||||
SYMENT ost_entry; /* Basic symbol */
|
||||
AUXENT ost_auxent[OBJ_COFF_MAX_AUXENTRIES]; /* Auxiliary entry. */
|
||||
unsigned int ost_flags; /* obj_coff internal use only flags */
|
||||
} obj_symbol_type;
|
||||
|
||||
/* If compiler generate leading underscores, remove them. */
|
||||
|
||||
#ifndef STRIP_UNDERSCORE
|
||||
#define STRIP_UNDERSCORE 0
|
||||
#endif /* STRIP_UNDERSCORE */
|
||||
#define DO_NOT_STRIP 0
|
||||
#define DO_STRIP 1
|
||||
|
||||
/* Symbol table macros and constants */
|
||||
|
||||
/* Possible and usefull section number in symbol table
|
||||
* The values of TEXT, DATA and BSS may not be portable.
|
||||
*/
|
||||
|
||||
#define C_TEXT_SECTION ((short)1)
|
||||
#define C_DATA_SECTION ((short)2)
|
||||
#define C_BSS_SECTION ((short)3)
|
||||
#define C_ABS_SECTION N_ABS
|
||||
#define C_UNDEF_SECTION N_UNDEF
|
||||
#define C_DEBUG_SECTION N_DEBUG
|
||||
#define C_NTV_SECTION N_TV
|
||||
#define C_PTV_SECTION P_TV
|
||||
|
||||
/*
|
||||
* Macros to extract information from a symbol table entry.
|
||||
* This syntaxic indirection allows independence regarding a.out or coff.
|
||||
* The argument (s) of all these macros is a pointer to a symbol table entry.
|
||||
*/
|
||||
|
||||
/* Predicates */
|
||||
/* True if the symbol is external */
|
||||
#define S_IS_EXTERNAL(s) ((s)->sy_symbol.ost_entry.n_scnum == C_UNDEF_SECTION)
|
||||
/* True if symbol has been defined, ie :
|
||||
section > 0 (DATA, TEXT or BSS)
|
||||
section == 0 and value > 0 (external bss symbol) */
|
||||
#define S_IS_DEFINED(s) ((s)->sy_symbol.ost_entry.n_scnum > C_UNDEF_SECTION || \
|
||||
((s)->sy_symbol.ost_entry.n_scnum == C_UNDEF_SECTION && \
|
||||
(s)->sy_symbol.ost_entry.n_value > 0))
|
||||
/* True if a debug special symbol entry */
|
||||
#define S_IS_DEBUG(s) ((s)->sy_symbol.ost_entry.n_scnum == C_DEBUG_SECTION)
|
||||
/* True if a symbol is local symbol name */
|
||||
/* A symbol name whose name begin with ^A is a gas internal pseudo symbol */
|
||||
#define S_IS_LOCAL(s) (S_GET_NAME(s)[0] == '\001' || \
|
||||
(S_LOCAL_NAME(s) && !flagseen['L']))
|
||||
/* True if a symbol is not defined in this file */
|
||||
#define S_IS_EXTERN(s) ((s)->sy_symbol.ost_entry.n_scnum == 0 && (s)->sy_symbol.ost_entry.n_value == 0)
|
||||
/*
|
||||
* True if a symbol can be multiply defined (bss symbols have this def
|
||||
* though it is bad practice)
|
||||
*/
|
||||
#define S_IS_COMMON(s) ((s)->sy_symbol.ost_entry.n_scnum == 0 && (s)->sy_symbol.ost_entry.n_value != 0)
|
||||
/* True if a symbol name is in the string table, i.e. its length is > 8. */
|
||||
#define S_IS_STRING(s) (strlen(S_GET_NAME(s)) > 8 ? 1 : 0)
|
||||
|
||||
/* Accessors */
|
||||
/* The name of the symbol */
|
||||
#define S_GET_NAME(s) ((char*)(s)->sy_symbol.ost_entry.n_offset)
|
||||
/* The pointer to the string table */
|
||||
#define S_GET_OFFSET(s) ((s)->sy_symbol.ost_entry.n_offset)
|
||||
/* The zeroes if symbol name is longer than 8 chars */
|
||||
#define S_GET_ZEROES(s) ((s)->sy_symbol.ost_entry.n_zeroes)
|
||||
/* The value of the symbol */
|
||||
#define S_GET_VALUE(s) ((s)->sy_symbol.ost_entry.n_value)
|
||||
/* The numeric value of the segment */
|
||||
#define S_GET_SEGMENT(s) (N_TYPE_seg[(s)->sy_symbol.ost_entry.n_scnum+4])
|
||||
/* The data type */
|
||||
#define S_GET_DATA_TYPE(s) ((s)->sy_symbol.ost_entry.n_type)
|
||||
/* The storage class */
|
||||
#define S_GET_STORAGE_CLASS(s) ((s)->sy_symbol.ost_entry.n_sclass)
|
||||
/* The number of auxiliary entries */
|
||||
#define S_GET_NUMBER_AUXILIARY(s) ((s)->sy_symbol.ost_entry.n_numaux)
|
||||
|
||||
/* Modifiers */
|
||||
/* Set the name of the symbol */
|
||||
#define S_SET_NAME(s,v) ((s)->sy_symbol.ost_entry.n_offset = (unsigned long)(v))
|
||||
/* Set the offset of the symbol */
|
||||
#define S_SET_OFFSET(s,v) ((s)->sy_symbol.ost_entry.n_offset = (v))
|
||||
/* The zeroes if symbol name is longer than 8 chars */
|
||||
#define S_SET_ZEROES(s,v) ((s)->sy_symbol.ost_entry.n_zeroes = (v))
|
||||
/* Set the value of the symbol */
|
||||
#define S_SET_VALUE(s,v) ((s)->sy_symbol.ost_entry.n_value = (v))
|
||||
/* The numeric value of the segment */
|
||||
#define S_SET_SEGMENT(s,v) ((s)->sy_symbol.ost_entry.n_scnum = SEGMENT_TO_SYMBOL_TYPE(v))
|
||||
/* The data type */
|
||||
#define S_SET_DATA_TYPE(s,v) ((s)->sy_symbol.ost_entry.n_type = (v))
|
||||
/* The storage class */
|
||||
#define S_SET_STORAGE_CLASS(s,v) ((s)->sy_symbol.ost_entry.n_sclass = (v))
|
||||
/* The number of auxiliary entries */
|
||||
#define S_SET_NUMBER_AUXILIARY(s,v) ((s)->sy_symbol.ost_entry.n_numaux = (v))
|
||||
|
||||
/* Additional modifiers */
|
||||
/* The symbol is external (does not mean undefined) */
|
||||
#define S_SET_EXTERNAL(s) { S_SET_STORAGE_CLASS(s, C_EXT) ; SF_CLEAR_LOCAL(s); }
|
||||
|
||||
/* Auxiliary entry macros. SA_ stands for symbol auxiliary */
|
||||
/* Omit the tv related fields */
|
||||
/* Accessors */
|
||||
#define SA_GET_SYM_TAGNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx)
|
||||
#define SA_GET_SYM_LNNO(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_lnno)
|
||||
#define SA_GET_SYM_SIZE(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_size)
|
||||
#define SA_GET_SYM_FSIZE(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_fsize)
|
||||
#define SA_GET_SYM_LNNOPTR(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr)
|
||||
#define SA_GET_SYM_ENDNDX(s) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx)
|
||||
#define SA_GET_SYM_DIMEN(s,i) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen[(i)])
|
||||
#define SA_GET_FILE_FNAME(s) ((s)->sy_symbol.ost_auxent[0].x_file.x_fname)
|
||||
#define SA_GET_SCN_SCNLEN(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_scnlen)
|
||||
#define SA_GET_SCN_NRELOC(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nreloc)
|
||||
#define SA_GET_SCN_NLINNO(s) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nlinno)
|
||||
|
||||
/* Modifiers */
|
||||
#define SA_SET_SYM_TAGNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx=(v))
|
||||
#define SA_SET_SYM_LNNO(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_lnno=(v))
|
||||
#define SA_SET_SYM_SIZE(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_size=(v))
|
||||
#define SA_SET_SYM_FSIZE(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_fsize=(v))
|
||||
#define SA_SET_SYM_LNNOPTR(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr=(v))
|
||||
#define SA_SET_SYM_ENDNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx=(v))
|
||||
#define SA_SET_SYM_DIMEN(s,i,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen[(i)]=(v))
|
||||
#define SA_SET_FILE_FNAME(s,v) strncpy((s)->sy_symbol.ost_auxent[0].x_file.x_fname,(v),FILNMLEN)
|
||||
#define SA_SET_SCN_SCNLEN(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_scnlen=(v))
|
||||
#define SA_SET_SCN_NRELOC(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nreloc=(v))
|
||||
#define SA_SET_SCN_NLINNO(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nlinno=(v))
|
||||
|
||||
/*
|
||||
* Internal use only definitions. SF_ stands for symbol flags.
|
||||
*
|
||||
* These values can be assigned to sy_symbol.ost_flags field of a symbolS.
|
||||
*
|
||||
* You'll break i960 if you shift the SYSPROC bits anywhere else. for
|
||||
* more on the balname/callname hack, see tc-i960.h. b.out is done
|
||||
* differently.
|
||||
*/
|
||||
|
||||
#define SF_I960_MASK (0x000001ff) /* Bits 0-8 are used by the i960 port. */
|
||||
#define SF_SYSPROC (0x0000003f) /* bits 0-5 are used to store the sysproc number */
|
||||
#define SF_IS_SYSPROC (0x00000040) /* bit 6 marks symbols that are sysprocs */
|
||||
#define SF_BALNAME (0x00000080) /* bit 7 marks BALNAME symbols */
|
||||
#define SF_CALLNAME (0x00000100) /* bit 8 marks CALLNAME symbols */
|
||||
|
||||
#define SF_NORMAL_MASK (0x0000ffff) /* bits 12-15 are general purpose. */
|
||||
|
||||
#define SF_STATICS (0x00001000) /* Mark the .text & all symbols */
|
||||
#define SF_DEFINED (0x00002000) /* Symbol is defined in this file */
|
||||
#define SF_STRING (0x00004000) /* Symbol name length > 8 */
|
||||
#define SF_LOCAL (0x00008000) /* Symbol must not be emitted */
|
||||
|
||||
#define SF_DEBUG_MASK (0xffff0000) /* bits 16-31 are debug info */
|
||||
|
||||
#define SF_FUNCTION (0x00010000) /* The symbol is a function */
|
||||
#define SF_PROCESS (0x00020000) /* Process symbol before write */
|
||||
#define SF_TAGGED (0x00040000) /* Is associated with a tag */
|
||||
#define SF_TAG (0x00080000) /* Is a tag */
|
||||
#define SF_DEBUG (0x00100000) /* Is in debug or abs section */
|
||||
#define SF_GET_SEGMENT (0x00200000) /* Get the section of the forward symbol. */
|
||||
/* All other bits are unused. */
|
||||
|
||||
/* Accessors */
|
||||
#define SF_GET(s) ((s)->sy_symbol.ost_flags)
|
||||
#define SF_GET_NORMAL_FIELD(s) ((s)->sy_symbol.ost_flags & SF_NORMAL_MASK)
|
||||
#define SF_GET_DEBUG_FIELD(s) ((s)->sy_symbol.ost_flags & SF_DEBUG_MASK)
|
||||
#define SF_GET_FILE(s) ((s)->sy_symbol.ost_flags & SF_FILE)
|
||||
#define SF_GET_STATICS(s) ((s)->sy_symbol.ost_flags & SF_STATICS)
|
||||
#define SF_GET_DEFINED(s) ((s)->sy_symbol.ost_flags & SF_DEFINED)
|
||||
#define SF_GET_STRING(s) ((s)->sy_symbol.ost_flags & SF_STRING)
|
||||
#define SF_GET_LOCAL(s) ((s)->sy_symbol.ost_flags & SF_LOCAL)
|
||||
#define SF_GET_FUNCTION(s) ((s)->sy_symbol.ost_flags & SF_FUNCTION)
|
||||
#define SF_GET_PROCESS(s) ((s)->sy_symbol.ost_flags & SF_PROCESS)
|
||||
#define SF_GET_DEBUG(s) ((s)->sy_symbol.ost_flags & SF_DEBUG)
|
||||
#define SF_GET_TAGGED(s) ((s)->sy_symbol.ost_flags & SF_TAGGED)
|
||||
#define SF_GET_TAG(s) ((s)->sy_symbol.ost_flags & SF_TAG)
|
||||
#define SF_GET_GET_SEGMENT(s) ((s)->sy_symbol.ost_flags & SF_GET_SEGMENT)
|
||||
#define SF_GET_I960(s) ((s)->sy_symbol.ost_flags & SF_I960_MASK) /* used by i960 */
|
||||
#define SF_GET_BALNAME(s) ((s)->sy_symbol.ost_flags & SF_BALNAME) /* used by i960 */
|
||||
#define SF_GET_CALLNAME(s) ((s)->sy_symbol.ost_flags & SF_CALLNAME) /* used by i960 */
|
||||
#define SF_GET_IS_SYSPROC(s) ((s)->sy_symbol.ost_flags & SF_IS_SYSPROC) /* used by i960 */
|
||||
#define SF_GET_SYSPROC(s) ((s)->sy_symbol.ost_flags & SF_SYSPROC) /* used by i960 */
|
||||
|
||||
/* Modifiers */
|
||||
#define SF_SET(s,v) ((s)->sy_symbol.ost_flags = (v))
|
||||
#define SF_SET_NORMAL_FIELD(s,v)((s)->sy_symbol.ost_flags |= ((v) & SF_NORMAL_MASK))
|
||||
#define SF_SET_DEBUG_FIELD(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_DEBUG_MASK))
|
||||
#define SF_SET_FILE(s) ((s)->sy_symbol.ost_flags |= SF_FILE)
|
||||
#define SF_SET_STATICS(s) ((s)->sy_symbol.ost_flags |= SF_STATICS)
|
||||
#define SF_SET_DEFINED(s) ((s)->sy_symbol.ost_flags |= SF_DEFINED)
|
||||
#define SF_SET_STRING(s) ((s)->sy_symbol.ost_flags |= SF_STRING)
|
||||
#define SF_SET_LOCAL(s) ((s)->sy_symbol.ost_flags |= SF_LOCAL)
|
||||
#define SF_CLEAR_LOCAL(s) ((s)->sy_symbol.ost_flags &= ~SF_LOCAL)
|
||||
#define SF_SET_FUNCTION(s) ((s)->sy_symbol.ost_flags |= SF_FUNCTION)
|
||||
#define SF_SET_PROCESS(s) ((s)->sy_symbol.ost_flags |= SF_PROCESS)
|
||||
#define SF_SET_DEBUG(s) ((s)->sy_symbol.ost_flags |= SF_DEBUG)
|
||||
#define SF_SET_TAGGED(s) ((s)->sy_symbol.ost_flags |= SF_TAGGED)
|
||||
#define SF_SET_TAG(s) ((s)->sy_symbol.ost_flags |= SF_TAG)
|
||||
#define SF_SET_GET_SEGMENT(s) ((s)->sy_symbol.ost_flags |= SF_GET_SEGMENT)
|
||||
#define SF_SET_I960(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_I960_MASK)) /* used by i960 */
|
||||
#define SF_SET_BALNAME(s) ((s)->sy_symbol.ost_flags |= SF_BALNAME) /* used by i960 */
|
||||
#define SF_SET_CALLNAME(s) ((s)->sy_symbol.ost_flags |= SF_CALLNAME) /* used by i960 */
|
||||
#define SF_SET_IS_SYSPROC(s) ((s)->sy_symbol.ost_flags |= SF_IS_SYSPROC) /* used by i960 */
|
||||
#define SF_SET_SYSPROC(s,v) ((s)->sy_symbol.ost_flags |= ((v) & SF_SYSPROC)) /* used by i960 */
|
||||
|
||||
/* File header macro and type definition */
|
||||
|
||||
/*
|
||||
* File position calculators. Beware to use them when all the
|
||||
* appropriate fields are set in the header.
|
||||
*/
|
||||
|
||||
#ifdef OBJ_COFF_OMIT_OPTIONAL_HEADER
|
||||
#define OBJ_COFF_AOUTHDRSZ (0)
|
||||
#else
|
||||
#define OBJ_COFF_AOUTHDRSZ (AOUTHDRSZ)
|
||||
#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */
|
||||
|
||||
#define H_GET_FILE_SIZE(h) \
|
||||
(long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
|
||||
H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
|
||||
H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \
|
||||
H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h) + \
|
||||
H_GET_SYMBOL_TABLE_SIZE(h) * SYMESZ + \
|
||||
(h)->string_table_size)
|
||||
#define H_GET_TEXT_FILE_OFFSET(h) \
|
||||
(long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
|
||||
H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ)
|
||||
#define H_GET_DATA_FILE_OFFSET(h) \
|
||||
(long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
|
||||
H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
|
||||
H_GET_TEXT_SIZE(h))
|
||||
#define H_GET_BSS_FILE_OFFSET(h) 0
|
||||
#define H_GET_RELOCATION_FILE_OFFSET(h) \
|
||||
(long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
|
||||
H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
|
||||
H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h))
|
||||
#define H_GET_LINENO_FILE_OFFSET(h) \
|
||||
(long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
|
||||
H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
|
||||
H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \
|
||||
H_GET_RELOCATION_SIZE(h))
|
||||
#define H_GET_SYMBOL_TABLE_FILE_OFFSET(h) \
|
||||
(long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \
|
||||
H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \
|
||||
H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \
|
||||
H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h))
|
||||
|
||||
/* Accessors */
|
||||
/* aouthdr */
|
||||
#define H_GET_MAGIC_NUMBER(h) ((h)->aouthdr.magic)
|
||||
#define H_GET_VERSION_STAMP(h) ((h)->aouthdr.vstamp)
|
||||
#define H_GET_TEXT_SIZE(h) ((h)->aouthdr.tsize)
|
||||
#define H_GET_DATA_SIZE(h) ((h)->aouthdr.dsize)
|
||||
#define H_GET_BSS_SIZE(h) ((h)->aouthdr.bsize)
|
||||
#define H_GET_ENTRY_POINT(h) ((h)->aouthdr.entry)
|
||||
#define H_GET_TEXT_START(h) ((h)->aouthdr.text_start)
|
||||
#define H_GET_DATA_START(h) ((h)->aouthdr.data_start)
|
||||
/* filehdr */
|
||||
#define H_GET_FILE_MAGIC_NUMBER(h) ((h)->filehdr.f_magic)
|
||||
#define H_GET_NUMBER_OF_SECTIONS(h) ((h)->filehdr.f_nscns)
|
||||
#define H_GET_TIME_STAMP(h) ((h)->filehdr.f_timdat)
|
||||
#define H_GET_SYMBOL_TABLE_POINTER(h) ((h)->filehdr.f_symptr)
|
||||
#define H_GET_SYMBOL_TABLE_SIZE(h) ((h)->filehdr.f_nsyms)
|
||||
#define H_GET_SIZEOF_OPTIONAL_HEADER(h) ((h)->filehdr.f_opthdr)
|
||||
#define H_GET_FLAGS(h) ((h)->filehdr.f_flags)
|
||||
/* Extra fields to achieve bsd a.out compatibility and for convenience */
|
||||
#define H_GET_RELOCATION_SIZE(h) ((h)->relocation_size)
|
||||
#define H_GET_STRING_SIZE(h) ((h)->string_table_size)
|
||||
#define H_GET_LINENO_SIZE(h) ((h)->lineno_size)
|
||||
|
||||
/* Modifiers */
|
||||
/* aouthdr */
|
||||
#define H_SET_MAGIC_NUMBER(h,v) ((h)->aouthdr.magic = (v))
|
||||
#define H_SET_VERSION_STAMP(h,v) ((h)->aouthdr.vstamp = (v))
|
||||
#define H_SET_TEXT_SIZE(h,v) ((h)->aouthdr.tsize = (v))
|
||||
#define H_SET_DATA_SIZE(h,v) ((h)->aouthdr.dsize = (v))
|
||||
#define H_SET_BSS_SIZE(h,v) ((h)->aouthdr.bsize = (v))
|
||||
#define H_SET_ENTRY_POINT(h,v) ((h)->aouthdr.entry = (v))
|
||||
#define H_SET_TEXT_START(h,v) ((h)->aouthdr.text_start = (v))
|
||||
#define H_SET_DATA_START(h,v) ((h)->aouthdr.data_start = (v))
|
||||
/* filehdr */
|
||||
#define H_SET_FILE_MAGIC_NUMBER(h,v) ((h)->filehdr.f_magic = (v))
|
||||
#define H_SET_NUMBER_OF_SECTIONS(h,v) ((h)->filehdr.f_nscns = (v))
|
||||
#define H_SET_TIME_STAMP(h,v) ((h)->filehdr.f_timdat = (v))
|
||||
#define H_SET_SYMBOL_TABLE_POINTER(h,v) ((h)->filehdr.f_symptr = (v))
|
||||
#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->filehdr.f_nsyms = (v))
|
||||
#define H_SET_SIZEOF_OPTIONAL_HEADER(h,v) ((h)->filehdr.f_opthdr = (v))
|
||||
#define H_SET_FLAGS(h,v) ((h)->filehdr.f_flags = (v))
|
||||
/* Extra fields to achieve bsd a.out compatibility and for convinience */
|
||||
#define H_SET_RELOCATION_SIZE(h,t,d) ((h)->relocation_size = (t)+(d))
|
||||
#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v))
|
||||
#define H_SET_LINENO_SIZE(h,v) ((h)->lineno_size = (v))
|
||||
|
||||
/* Segment flipping */
|
||||
#define segment_name(v) (seg_name[(int) (v)])
|
||||
|
||||
typedef struct {
|
||||
AOUTHDR aouthdr; /* a.out header */
|
||||
FILHDR filehdr; /* File header, not machine dep. */
|
||||
long string_table_size; /* names + '\0' + sizeof(int) */
|
||||
long relocation_size; /* Cumulated size of relocation
|
||||
information for all sections in
|
||||
bytes. */
|
||||
long lineno_size; /* Size of the line number information
|
||||
table in bytes */
|
||||
} object_headers;
|
||||
|
||||
/* -------------- Line number handling ------- */
|
||||
extern int text_lineno_number;
|
||||
|
||||
/* line numbering stuff. */
|
||||
|
||||
typedef struct internal_lineno {
|
||||
LINENO line; /* The lineno structure itself */
|
||||
char* frag; /* Frag to which the line number is related */
|
||||
struct internal_lineno* next; /* Forward chain pointer */
|
||||
} lineno;
|
||||
|
||||
extern lineno *lineno_lastP;
|
||||
extern lineno *lineno_rootP;
|
||||
#define OBJ_EMIT_LINENO(a, b, c) obj_emit_lineno((a),(b),(c))
|
||||
|
||||
#ifdef __STDC__
|
||||
void obj_emit_lineno(char **where, lineno *line, char *file_start);
|
||||
#else /* __STDC__ */
|
||||
void obj_emit_lineno();
|
||||
#endif /* __STDC__ */
|
||||
|
||||
/* stack stuff */
|
||||
typedef struct {
|
||||
unsigned long chunk_size;
|
||||
unsigned long element_size;
|
||||
unsigned long size;
|
||||
char* data;
|
||||
unsigned long pointer;
|
||||
} stack;
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
char *stack_pop(stack *st);
|
||||
char *stack_push(stack *st, char *element);
|
||||
char *stack_top(stack *st);
|
||||
stack *stack_init(unsigned long chunk_size, unsigned long element_size);
|
||||
void c_dot_file_symbol(char *filename);
|
||||
void obj_extra_stuff(object_headers *headers);
|
||||
void stack_delete(stack *st);
|
||||
|
||||
#ifndef tc_headers_hook
|
||||
void tc_headers_hook(object_headers *headers);
|
||||
#endif /* tc_headers_hook */
|
||||
|
||||
#ifndef tc_coff_symbol_emit_hook
|
||||
void tc_coff_symbol_emit_hook(); /* really tc_coff_symbol_emit_hook(symbolS *symbolP) */
|
||||
#endif /* tc_coff_symbol_emit_hook */
|
||||
|
||||
void c_section_header(SCNHDR *header,
|
||||
char *name,
|
||||
long core_address,
|
||||
long size,
|
||||
long data_ptr,
|
||||
long reloc_ptr,
|
||||
long lineno_ptr,
|
||||
long reloc_number,
|
||||
long lineno_number,
|
||||
long alignment);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
char *stack_pop();
|
||||
char *stack_push();
|
||||
char *stack_top();
|
||||
stack *stack_init();
|
||||
void c_dot_file_symbol();
|
||||
void c_section_header();
|
||||
void obj_extra_stuff();
|
||||
void stack_delete();
|
||||
void tc_headers_hook();
|
||||
void tc_coff_symbol_emit_hook();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
|
||||
/* sanity check */
|
||||
|
||||
#ifdef TC_I960
|
||||
#ifndef C_LEAFSTAT
|
||||
hey! Where is the C_LEAFSTAT definition? i960-coff support is depending on it.
|
||||
#endif /* no C_LEAFSTAT */
|
||||
#endif /* TC_I960 */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of obj-coff.h */
|
1157
gas/config/tc-a29k.c
Normal file
1157
gas/config/tc-a29k.c
Normal file
File diff suppressed because it is too large
Load diff
29
gas/config/tc-a29k.h
Normal file
29
gas/config/tc-a29k.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* tc-a29k.h -- Assemble for the AMD 29000.
|
||||
Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#define TC_A29K
|
||||
|
||||
#define tc_headers_hook(a) ; /* not used */
|
||||
#define tc_headers_hook(a) ; /* not used */
|
||||
#define tc_crawl_symbol_chain(a) ; /* not used */
|
||||
#define tc_coff_symbol_emit_hook(a) ; /* not used */
|
||||
|
||||
/* end of tc-a29k.h */
|
0
gas/config/tc-generic.c
Normal file
0
gas/config/tc-generic.c
Normal file
15
gas/config/tc-generic.h
Normal file
15
gas/config/tc-generic.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* This file is tc-generic.h and is intended to be a template for
|
||||
* target cpu specific header files.
|
||||
*/
|
||||
|
||||
#define TC_GENERIC 1
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of tc-generic.h */
|
1983
gas/config/tc-i386.c
Normal file
1983
gas/config/tc-i386.c
Normal file
File diff suppressed because it is too large
Load diff
247
gas/config/tc-i386.h
Normal file
247
gas/config/tc-i386.h
Normal file
|
@ -0,0 +1,247 @@
|
|||
/* 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 TC_I386 1
|
||||
|
||||
#define tc_crawl_symbol_chain(a) ; /* not used */
|
||||
#define tc_headers_hook(a) ; /* not used */
|
||||
|
||||
#define MAX_OPERANDS 3 /* max operands per insn */
|
||||
#define MAX_PREFIXES 4 /* max prefixes per opcode */
|
||||
#define MAX_IMMEDIATE_OPERANDS 2 /* max immediates per insn */
|
||||
#define MAX_MEMORY_OPERANDS 2 /* max memory ref per insn
|
||||
* lcall uses 2
|
||||
*/
|
||||
/* we define the syntax here (modulo base,index,scale syntax) */
|
||||
#define REGISTER_PREFIX '%'
|
||||
#define IMMEDIATE_PREFIX '$'
|
||||
#define ABSOLUTE_PREFIX '*'
|
||||
#define PREFIX_SEPERATOR '/'
|
||||
|
||||
#define TWO_BYTE_OPCODE_ESCAPE 0x0f
|
||||
|
||||
/* 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 struct {
|
||||
/* instruction name sans width suffix ("mov" for movl insns) */
|
||||
char *name;
|
||||
|
||||
/* how many operands */
|
||||
unsigned int operands;
|
||||
|
||||
/* base_opcode is the fundamental opcode byte with a optional prefix(es). */
|
||||
unsigned int base_opcode;
|
||||
|
||||
/* extension_opcode is the 3 bit extension for group <n> insns.
|
||||
If this template has no extension opcode (the usual case) use None */
|
||||
unsigned char extension_opcode;
|
||||
#define None 0xff /* If no extension_opcode is possible. */
|
||||
|
||||
/* the bits in opcode_modifier are used to generate the final opcode from
|
||||
the base_opcode. These bits also are used to detect alternate forms of
|
||||
the same instruction */
|
||||
unsigned int opcode_modifier;
|
||||
|
||||
/* opcode_modifier bits: */
|
||||
#define W 0x1 /* set if operands are words or dwords */
|
||||
#define D 0x2 /* D = 0 if Reg --> Regmem; D = 1 if Regmem --> Reg */
|
||||
/* direction flag for floating insns: MUST BE 0x400 */
|
||||
#define FloatD 0x400
|
||||
/* shorthand */
|
||||
#define DW (D|W)
|
||||
#define ShortForm 0x10 /* register is in low 3 bits of opcode */
|
||||
#define ShortFormW 0x20 /* ShortForm and W bit is 0x8 */
|
||||
#define Seg2ShortForm 0x40 /* encoding of load segment reg insns */
|
||||
#define Seg3ShortForm 0x80 /* fs/gs segment register insns. */
|
||||
#define Jump 0x100 /* special case for jump insns. */
|
||||
#define JumpInterSegment 0x200 /* special case for intersegment leaps/calls */
|
||||
/* 0x400 CANNOT BE USED since it's already used by FloatD above */
|
||||
#define DONT_USE 0x400
|
||||
#define NoModrm 0x800
|
||||
#define Modrm 0x1000
|
||||
#define imulKludge 0x2000
|
||||
#define JumpByte 0x4000
|
||||
#define JumpDword 0x8000
|
||||
#define ReverseRegRegmem 0x10000
|
||||
|
||||
/* (opcode_modifier & COMES_IN_ALL_SIZES) is true if the
|
||||
instuction comes in byte, word, and dword sizes and is encoded into
|
||||
machine code in the canonical way. */
|
||||
#define COMES_IN_ALL_SIZES (W)
|
||||
|
||||
/* (opcode_modifier & COMES_IN_BOTH_DIRECTIONS) indicates that the
|
||||
source and destination operands can be reversed by setting either
|
||||
the D (for integer insns) or the FloatD (for floating insns) bit
|
||||
in base_opcode. */
|
||||
#define COMES_IN_BOTH_DIRECTIONS (D|FloatD)
|
||||
|
||||
/* operand_types[i] describes the type of operand i. This is made
|
||||
by OR'ing together all of the possible type masks. (e.g.
|
||||
'operand_types[i] = Reg|Imm' specifies that operand i can be
|
||||
either a register or an immediate operand */
|
||||
unsigned int operand_types[3];
|
||||
} template;
|
||||
|
||||
/*
|
||||
'templates' is for grouping together 'template' structures for opcodes
|
||||
of the same name. This is only used for storing the insns in the grand
|
||||
ole hash table of insns.
|
||||
The templates themselves start at START and range up to (but not including)
|
||||
END.
|
||||
*/
|
||||
typedef struct {
|
||||
template *start;
|
||||
template *end;
|
||||
} templates;
|
||||
|
||||
/* these are for register name --> number & type hash lookup */
|
||||
typedef struct {
|
||||
char * reg_name;
|
||||
unsigned int reg_type;
|
||||
unsigned int reg_num;
|
||||
} reg_entry;
|
||||
|
||||
typedef struct {
|
||||
char * seg_name;
|
||||
unsigned int seg_prefix;
|
||||
} seg_entry;
|
||||
|
||||
/* these are for prefix name --> prefix code hash lookup */
|
||||
typedef struct {
|
||||
char * prefix_name;
|
||||
unsigned char prefix_code;
|
||||
} prefix_entry;
|
||||
|
||||
/* 386 operand encoding bytes: see 386 book for details of this. */
|
||||
typedef struct {
|
||||
unsigned regmem:3; /* codes register or memory operand */
|
||||
unsigned reg:3; /* codes register operand (or extended opcode) */
|
||||
unsigned mode:2; /* how to interpret regmem & reg */
|
||||
} modrm_byte;
|
||||
|
||||
/* 386 opcode byte to code indirect addressing. */
|
||||
typedef struct {
|
||||
unsigned base:3;
|
||||
unsigned index:3;
|
||||
unsigned scale:2;
|
||||
} base_index_byte;
|
||||
|
||||
/* end of tc-i386.h */
|
1255
gas/config/tc-i860.c
Normal file
1255
gas/config/tc-i860.c
Normal file
File diff suppressed because it is too large
Load diff
14
gas/config/tc-i860.h
Normal file
14
gas/config/tc-i860.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* This file is tc-i860.h.
|
||||
*/
|
||||
|
||||
#define TC_I860 1
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of tc-i860.h */
|
2800
gas/config/tc-i960.c
Normal file
2800
gas/config/tc-i960.c
Normal file
File diff suppressed because it is too large
Load diff
279
gas/config/tc-i960.h
Normal file
279
gas/config/tc-i960.h
Normal file
|
@ -0,0 +1,279 @@
|
|||
/* tc-i960.h - Basic 80960 instruction formats.
|
||||
Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 1,
|
||||
or (at your option) any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with GAS; see the file COPYING. If not, write
|
||||
to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* The 'COJ' instructions are actually COBR instructions with the 'b' in
|
||||
* the mnemonic replaced by a 'j'; they are ALWAYS "de-optimized" if necessary:
|
||||
* if the displacement will not fit in 13 bits, the assembler will replace them
|
||||
* with the corresponding compare and branch instructions.
|
||||
*
|
||||
* All of the 'MEMn' instructions are the same format; the 'n' in the name
|
||||
* indicates the default index scale factor (the size of the datum operated on).
|
||||
*
|
||||
* The FBRA formats are not actually an instruction format. They are the
|
||||
* "convenience directives" for branching on floating-point comparisons,
|
||||
* each of which generates 2 instructions (a 'bno' and one other branch).
|
||||
*
|
||||
* The CALLJ format is not actually an instruction format. It indicates that
|
||||
* the instruction generated (a CTRL-format 'call') should have its relocation
|
||||
* specially flagged for link-time replacement with a 'bal' or 'calls' if
|
||||
* appropriate.
|
||||
*/
|
||||
|
||||
#define TC_I960 1
|
||||
|
||||
/* tailor gas */
|
||||
#define SYMBOLS_NEED_BACKPOINTERS
|
||||
#define LOCAL_LABELS_FB
|
||||
#define WANT_BITFIELDS
|
||||
|
||||
/* tailor the coff format */
|
||||
#define OBJ_COFF_SECTION_HEADER_HAS_ALIGNMENT
|
||||
#define OBJ_COFF_MAX_AUXENTRIES (2)
|
||||
|
||||
/* other */
|
||||
#define CTRL 0
|
||||
#define COBR 1
|
||||
#define COJ 2
|
||||
#define REG 3
|
||||
#define MEM1 4
|
||||
#define MEM2 5
|
||||
#define MEM4 6
|
||||
#define MEM8 7
|
||||
#define MEM12 8
|
||||
#define MEM16 9
|
||||
#define FBRA 10
|
||||
#define CALLJ 11
|
||||
|
||||
/* Masks for the mode bits in REG format instructions */
|
||||
#define M1 0x0800
|
||||
#define M2 0x1000
|
||||
#define M3 0x2000
|
||||
|
||||
/* Generate the 12-bit opcode for a REG format instruction by placing the
|
||||
* high 8 bits in instruction bits 24-31, the low 4 bits in instruction bits
|
||||
* 7-10.
|
||||
*/
|
||||
|
||||
#define REG_OPC(opc) ((opc & 0xff0) << 20) | ((opc & 0xf) << 7)
|
||||
|
||||
/* Generate a template for a REG format instruction: place the opcode bits
|
||||
* in the appropriate fields and OR in mode bits for the operands that will not
|
||||
* be used. I.e.,
|
||||
* set m1=1, if src1 will not be used
|
||||
* set m2=1, if src2 will not be used
|
||||
* set m3=1, if dst will not be used
|
||||
*
|
||||
* Setting the "unused" mode bits to 1 speeds up instruction execution(!).
|
||||
* The information is also useful to us because some 1-operand REG instructions
|
||||
* use the src1 field, others the dst field; and some 2-operand REG instructions
|
||||
* use src1/src2, others src1/dst. The set mode bits enable us to distinguish.
|
||||
*/
|
||||
#define R_0(opc) ( REG_OPC(opc) | M1 | M2 | M3 ) /* No operands */
|
||||
#define R_1(opc) ( REG_OPC(opc) | M2 | M3 ) /* 1 operand: src1 */
|
||||
#define R_1D(opc) ( REG_OPC(opc) | M1 | M2 ) /* 1 operand: dst */
|
||||
#define R_2(opc) ( REG_OPC(opc) | M3 ) /* 2 ops: src1/src2 */
|
||||
#define R_2D(opc) ( REG_OPC(opc) | M2 ) /* 2 ops: src1/dst */
|
||||
#define R_3(opc) ( REG_OPC(opc) ) /* 3 operands */
|
||||
|
||||
/* DESCRIPTOR BYTES FOR REGISTER OPERANDS
|
||||
*
|
||||
* Interpret names as follows:
|
||||
* R: global or local register only
|
||||
* RS: global, local, or (if target allows) special-function register only
|
||||
* RL: global or local register, or integer literal
|
||||
* RSL: global, local, or (if target allows) special-function register;
|
||||
* or integer literal
|
||||
* F: global, local, or floating-point register
|
||||
* FL: global, local, or floating-point register; or literal (including
|
||||
* floating point)
|
||||
*
|
||||
* A number appended to a name indicates that registers must be aligned,
|
||||
* as follows:
|
||||
* 2: register number must be multiple of 2
|
||||
* 4: register number must be multiple of 4
|
||||
*/
|
||||
|
||||
#define SFR 0x10 /* Mask for the "sfr-OK" bit */
|
||||
#define LIT 0x08 /* Mask for the "literal-OK" bit */
|
||||
#define FP 0x04 /* Mask for "floating-point-OK" bit */
|
||||
|
||||
/* This macro ors the bits together. Note that 'align' is a mask
|
||||
* for the low 0, 1, or 2 bits of the register number, as appropriate.
|
||||
*/
|
||||
#define OP(align,lit,fp,sfr) ( align | lit | fp | sfr )
|
||||
|
||||
#define R OP( 0, 0, 0, 0 )
|
||||
#define RS OP( 0, 0, 0, SFR )
|
||||
#define RL OP( 0, LIT, 0, 0 )
|
||||
#define RSL OP( 0, LIT, 0, SFR )
|
||||
#define F OP( 0, 0, FP, 0 )
|
||||
#define FL OP( 0, LIT, FP, 0 )
|
||||
#define R2 OP( 1, 0, 0, 0 )
|
||||
#define RL2 OP( 1, LIT, 0, 0 )
|
||||
#define F2 OP( 1, 0, FP, 0 )
|
||||
#define FL2 OP( 1, LIT, FP, 0 )
|
||||
#define R4 OP( 3, 0, 0, 0 )
|
||||
#define RL4 OP( 3, LIT, 0, 0 )
|
||||
#define F4 OP( 3, 0, FP, 0 )
|
||||
#define FL4 OP( 3, LIT, FP, 0 )
|
||||
|
||||
#define M 0x7f /* Memory operand (MEMA & MEMB format instructions) */
|
||||
|
||||
/* Macros to extract info from the register operand descriptor byte 'od'.
|
||||
*/
|
||||
#define SFR_OK(od) (od & SFR) /* TRUE if sfr operand allowed */
|
||||
#define LIT_OK(od) (od & LIT) /* TRUE if literal operand allowed */
|
||||
#define FP_OK(od) (od & FP) /* TRUE if floating-point op allowed */
|
||||
#define REG_ALIGN(od,n) ((od & 0x3 & n) == 0)
|
||||
/* TRUE if reg #n is properly aligned */
|
||||
#define MEMOP(od) (od == M) /* TRUE if operand is a memory operand*/
|
||||
|
||||
/* Classes of 960 intructions:
|
||||
* - each instruction falls into one class.
|
||||
* - each target architecture supports one or more classes.
|
||||
*
|
||||
* EACH CONSTANT MUST CONTAIN 1 AND ONLY 1 SET BIT!: see targ_has_iclass().
|
||||
*/
|
||||
#define I_BASE 0x01 /* 80960 base instruction set */
|
||||
#define I_CX 0x02 /* 80960Cx instruction */
|
||||
#define I_DEC 0x04 /* Decimal instruction */
|
||||
#define I_FP 0x08 /* Floating point instruction */
|
||||
#define I_KX 0x10 /* 80960Kx instruction */
|
||||
#define I_MIL 0x20 /* Military instruction */
|
||||
|
||||
/* MEANING OF 'n_other' in the symbol record.
|
||||
*
|
||||
* If non-zero, the 'n_other' fields indicates either a leaf procedure or
|
||||
* a system procedure, as follows:
|
||||
*
|
||||
* 1 <= n_other <= 32 :
|
||||
* The symbol is the entry point to a system procedure.
|
||||
* 'n_value' is the address of the entry, as for any other
|
||||
* procedure. The system procedure number (which can be used in
|
||||
* a 'calls' instruction) is (n_other-1). These entries come from
|
||||
* '.sysproc' directives.
|
||||
*
|
||||
* n_other == N_CALLNAME
|
||||
* the symbol is the 'call' entry point to a leaf procedure.
|
||||
* The *next* symbol in the symbol table must be the corresponding
|
||||
* 'bal' entry point to the procedure (see following). These
|
||||
* entries come from '.leafproc' directives in which two different
|
||||
* symbols are specified (the first one is represented here).
|
||||
*
|
||||
*
|
||||
* n_other == N_BALNAME
|
||||
* the symbol is the 'bal' entry point to a leaf procedure.
|
||||
* These entries result from '.leafproc' directives in which only
|
||||
* one symbol is specified, or in which the same symbol is
|
||||
* specified twice.
|
||||
*
|
||||
* Note that an N_CALLNAME entry *must* have a corresponding N_BALNAME entry,
|
||||
* but not every N_BALNAME entry must have an N_CALLNAME entry.
|
||||
*/
|
||||
#define N_CALLNAME (-1)
|
||||
#define N_BALNAME (-2)
|
||||
|
||||
|
||||
/* i960 uses a custom relocation record. */
|
||||
|
||||
/* let obj-aout.h know */
|
||||
#define CUSTOM_RELOC_FORMAT 1
|
||||
/* let a.out.gnu.h know */
|
||||
#define N_RELOCATION_INFO_DECLARED 1
|
||||
struct relocation_info {
|
||||
int r_address; /* File address of item to be relocated */
|
||||
unsigned
|
||||
r_index:24,/* Index of symbol on which relocation is based*/
|
||||
r_pcrel:1, /* 1 => relocate PC-relative; else absolute
|
||||
* On i960, pc-relative implies 24-bit
|
||||
* address, absolute implies 32-bit.
|
||||
*/
|
||||
r_length:2, /* Number of bytes to relocate:
|
||||
* 0 => 1 byte
|
||||
* 1 => 2 bytes
|
||||
* 2 => 4 bytes -- only value used for i960
|
||||
*/
|
||||
r_extern:1,
|
||||
r_bsr:1, /* Something for the GNU NS32K assembler */
|
||||
r_disp:1, /* Something for the GNU NS32K assembler */
|
||||
r_callj:1, /* 1 if relocation target is an i960 'callj' */
|
||||
nuthin:1; /* Unused */
|
||||
};
|
||||
|
||||
/* hacks for tracking callj's */
|
||||
#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
|
||||
|
||||
#define TC_S_IS_SYSPROC(s) ((1<=S_GET_OTHER(s)) && (S_GET_OTHER(s)<=32))
|
||||
#define TC_S_IS_BALNAME(s) (S_GET_OTHER(s) == N_BALNAME)
|
||||
#define TC_S_IS_CALLNAME(s) (S_GET_OTHER(s) == N_CALLNAME)
|
||||
#define TC_S_IS_BADPROC(s) ((S_GET_OTHER(s) != 0) && !TC_S_IS_CALLNAME(s) && !TC_S_IS_BALNAME(s) && !TC_S_IS_SYSPROC(s))
|
||||
|
||||
#define TC_S_SET_SYSPROC(s, p) (S_SET_OTHER((s), (p)+1))
|
||||
#define TC_S_GET_SYSPROC(s) (S_GET_OTHER(s)-1)
|
||||
|
||||
#define TC_S_FORCE_TO_BALNAME(s) (S_SET_OTHER((s), N_BALNAME))
|
||||
#define TC_S_FORCE_TO_CALLNAME(s) (S_SET_OTHER((s), N_CALLNAME))
|
||||
#define TC_S_FORCE_TO_SYSPROC(s) {;}
|
||||
|
||||
#elif defined(OBJ_COFF)
|
||||
|
||||
#define TC_S_IS_SYSPROC(s) (S_GET_STORAGE_CLASS(s) == C_SCALL)
|
||||
#define TC_S_IS_BALNAME(s) (SF_GET_BALNAME(s))
|
||||
#define TC_S_IS_CALLNAME(s) (SF_GET_CALLNAME(s))
|
||||
#define TC_S_IS_BADPROC(s) (TC_S_IS_SYSPROC(s) && TC_S_GET_SYSPROC(s) < 0 && 31 < TC_S_GET_SYSPROC(s))
|
||||
|
||||
#define TC_S_SET_SYSPROC(s, p) ((s)->sy_symbol.ost_auxent[1].x_sc.x_stindx = (p))
|
||||
#define TC_S_GET_SYSPROC(s) ((s)->sy_symbol.ost_auxent[1].x_sc.x_stindx)
|
||||
|
||||
#define TC_S_FORCE_TO_BALNAME(s) (SF_SET_BALNAME(s))
|
||||
#define TC_S_FORCE_TO_CALLNAME(s) (SF_SET_CALLNAME(s))
|
||||
#define TC_S_FORCE_TO_SYSPROC(s) (S_SET_STORAGE_CLASS((s), C_SCALL))
|
||||
|
||||
#else /* switch on OBJ */
|
||||
you lose
|
||||
#endif /* witch on OBJ */
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
void brtab_emit(void);
|
||||
void reloc_callj(); /* this is really reloc_callj(fixS *fixP) but I don't want to change header inclusion order. */
|
||||
void tc_set_bal_of_call(); /* this is really tc_set_bal_of_call(symbolS *callP, symbolS *balP) */
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
void brtab_emit();
|
||||
void reloc_callj();
|
||||
void tc_set_bal_of_call();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
char *_tc_get_bal_of_call(); /* this is really symbolS *tc_get_bal_of_call(symbolS *callP). */
|
||||
#define tc_get_bal_of_call(c) ((symbolS *) _tc_get_bal_of_call(c))
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of tp-i960.h */
|
284
gas/config/tc-m68851.h
Normal file
284
gas/config/tc-m68851.h
Normal file
|
@ -0,0 +1,284 @@
|
|||
|
||||
/*
|
||||
* pmmu.h
|
||||
*/
|
||||
|
||||
/* I suppose we have to copyright this file. Someone on the net sent it
|
||||
to us as part of the changes for the m68851 Memory Management Unit */
|
||||
|
||||
/* Copyright (C) 1987 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of Gas, the GNU Assembler.
|
||||
|
||||
The GNU assembler is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY. No author or distributor
|
||||
accepts responsibility to anyone for the consequences of using it
|
||||
or for whether it serves any particular purpose or works at all,
|
||||
unless he says so in writing. Refer to the GNU Assembler General
|
||||
Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute
|
||||
the GNU Assembler, but only under the conditions described in the
|
||||
GNU Assembler General Public License. A copy of this license is
|
||||
supposed to have been given to you along with the GNU Assembler
|
||||
so you can know your rights and responsibilities. It should be
|
||||
in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies. */
|
||||
|
||||
#ifdef m68851
|
||||
|
||||
/*
|
||||
I didn't use much imagination in choosing the
|
||||
following codes, so many of them aren't very
|
||||
mnemonic. -rab
|
||||
|
||||
P pmmu register
|
||||
Possible values:
|
||||
000 TC Translation Control reg
|
||||
100 CAL Current Access Level
|
||||
101 VAL Validate Access Level
|
||||
110 SCC Stack Change Control
|
||||
111 AC Access Control
|
||||
|
||||
W wide pmmu registers
|
||||
Possible values:
|
||||
001 DRP Dma Root Pointer
|
||||
010 SRP Supervisor Root Pointer
|
||||
011 CRP Cpu Root Pointer
|
||||
|
||||
f function code register
|
||||
0 SFC
|
||||
1 DFC
|
||||
|
||||
V VAL register only
|
||||
|
||||
X BADx, BACx
|
||||
100 BAD Breakpoint Acknowledge Data
|
||||
101 BAC Breakpoint Acknowledge Control
|
||||
|
||||
Y PSR
|
||||
Z PCSR
|
||||
|
||||
| memory (modes 2-6, 7.*)
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* these defines should be in m68k.c but
|
||||
* i put them here to keep all the m68851 stuff
|
||||
* together -rab
|
||||
* JF--Make sure these #s don't clash with the ones in m68k.c
|
||||
* That would be BAD.
|
||||
*/
|
||||
#define TC (FPS+1) /* 48 */
|
||||
#define DRP (TC+1) /* 49 */
|
||||
#define SRP (DRP+1) /* 50 */
|
||||
#define CRP (SRP+1) /* 51 */
|
||||
#define CAL (CRP+1) /* 52 */
|
||||
#define VAL (CAL+1) /* 53 */
|
||||
#define SCC (VAL+1) /* 54 */
|
||||
#define AC (SCC+1) /* 55 */
|
||||
#define BAD (AC+1) /* 56,57,58,59, 60,61,62,63 */
|
||||
#define BAC (BAD+8) /* 64,65,66,67, 68,69,70,71 */
|
||||
#define PSR (BAC+8) /* 72 */
|
||||
#define PCSR (PSR+1) /* 73 */
|
||||
|
||||
/* name */ /* opcode */ /* match */ /* args */
|
||||
|
||||
{"pbac", one(0xf0c7), one(0xffbf), "Bc"},
|
||||
{"pbacw", one(0xf087), one(0xffbf), "Bc"},
|
||||
{"pbas", one(0xf0c6), one(0xffbf), "Bc"},
|
||||
{"pbasw", one(0xf086), one(0xffbf), "Bc"},
|
||||
{"pbbc", one(0xf0c1), one(0xffbf), "Bc"},
|
||||
{"pbbcw", one(0xf081), one(0xffbf), "Bc"},
|
||||
{"pbbs", one(0xf0c0), one(0xffbf), "Bc"},
|
||||
{"pbbsw", one(0xf080), one(0xffbf), "Bc"},
|
||||
{"pbcc", one(0xf0cf), one(0xffbf), "Bc"},
|
||||
{"pbccw", one(0xf08f), one(0xffbf), "Bc"},
|
||||
{"pbcs", one(0xf0ce), one(0xffbf), "Bc"},
|
||||
{"pbcsw", one(0xf08e), one(0xffbf), "Bc"},
|
||||
{"pbgc", one(0xf0cd), one(0xffbf), "Bc"},
|
||||
{"pbgcw", one(0xf08d), one(0xffbf), "Bc"},
|
||||
{"pbgs", one(0xf0cc), one(0xffbf), "Bc"},
|
||||
{"pbgsw", one(0xf08c), one(0xffbf), "Bc"},
|
||||
{"pbic", one(0xf0cb), one(0xffbf), "Bc"},
|
||||
{"pbicw", one(0xf08b), one(0xffbf), "Bc"},
|
||||
{"pbis", one(0xf0ca), one(0xffbf), "Bc"},
|
||||
{"pbisw", one(0xf08a), one(0xffbf), "Bc"},
|
||||
{"pblc", one(0xf0c3), one(0xffbf), "Bc"},
|
||||
{"pblcw", one(0xf083), one(0xffbf), "Bc"},
|
||||
{"pbls", one(0xf0c2), one(0xffbf), "Bc"},
|
||||
{"pblsw", one(0xf082), one(0xffbf), "Bc"},
|
||||
{"pbsc", one(0xf0c5), one(0xffbf), "Bc"},
|
||||
{"pbscw", one(0xf085), one(0xffbf), "Bc"},
|
||||
{"pbss", one(0xf0c4), one(0xffbf), "Bc"},
|
||||
{"pbssw", one(0xf084), one(0xffbf), "Bc"},
|
||||
{"pbwc", one(0xf0c9), one(0xffbf), "Bc"},
|
||||
{"pbwcw", one(0xf089), one(0xffbf), "Bc"},
|
||||
{"pbws", one(0xf0c8), one(0xffbf), "Bc"},
|
||||
{"pbwsw", one(0xf088), one(0xffbf), "Bc"},
|
||||
|
||||
|
||||
{"pdbac", two(0xf048, 0x0007), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdbas", two(0xf048, 0x0006), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdbbc", two(0xf048, 0x0001), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdbbs", two(0xf048, 0x0000), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdbcc", two(0xf048, 0x000f), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdbcs", two(0xf048, 0x000e), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdbgc", two(0xf048, 0x000d), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdbgs", two(0xf048, 0x000c), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdbic", two(0xf048, 0x000b), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdbis", two(0xf048, 0x000a), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdblc", two(0xf048, 0x0003), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdbls", two(0xf048, 0x0002), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdbsc", two(0xf048, 0x0005), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdbss", two(0xf048, 0x0004), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdbwc", two(0xf048, 0x0009), two(0xfff8, 0xffff), "DsBw"},
|
||||
{"pdbws", two(0xf048, 0x0008), two(0xfff8, 0xffff), "DsBw"},
|
||||
|
||||
{"pflusha", two(0xf000, 0x2400), two(0xffff, 0xffff), "" },
|
||||
|
||||
{"pflush", two(0xf000, 0x3010), two(0xffc0, 0xfe10), "T3T9" },
|
||||
{"pflush", two(0xf000, 0x3810), two(0xffc0, 0xfe10), "T3T9&s" },
|
||||
{"pflush", two(0xf000, 0x3008), two(0xffc0, 0xfe18), "D3T9" },
|
||||
{"pflush", two(0xf000, 0x3808), two(0xffc0, 0xfe18), "D3T9&s" },
|
||||
{"pflush", two(0xf000, 0x3000), two(0xffc0, 0xfe1e), "f3T9" },
|
||||
{"pflush", two(0xf000, 0x3800), two(0xffc0, 0xfe1e), "f3T9&s" },
|
||||
|
||||
{"pflushs", two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9" },
|
||||
{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe00), "T3T9&s" },
|
||||
{"pflushs", two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9" },
|
||||
{"pflushs", two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s" },
|
||||
{"pflushs", two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9" },
|
||||
{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s"},
|
||||
|
||||
{"pflushr", two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s" },
|
||||
|
||||
{"ploadr", two(0xf000, 0x2210), two(0xffc0, 0xfff0), "T3&s" },
|
||||
{"ploadr", two(0xf000, 0x2208), two(0xffc0, 0xfff8), "D3&s" },
|
||||
{"ploadr", two(0xf000, 0x2200), two(0xffc0, 0xfffe), "f3&s" },
|
||||
{"ploadw", two(0xf000, 0x2010), two(0xffc0, 0xfff0), "T3&s" },
|
||||
{"ploadw", two(0xf000, 0x2008), two(0xffc0, 0xfff8), "D3&s" },
|
||||
{"ploadw", two(0xf000, 0x2000), two(0xffc0, 0xfffe), "f3&s" },
|
||||
|
||||
/* TC, CRP, DRP, SRP, CAL, VAL, SCC, AC */
|
||||
{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "*sP8" },
|
||||
{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "P8%s" },
|
||||
{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "|sW8" },
|
||||
{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "W8~s" },
|
||||
|
||||
/* BADx, BACx */
|
||||
{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xe3e3), "*sX3" },
|
||||
{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xe3e3), "X3%s" },
|
||||
|
||||
/* PSR, PCSR */
|
||||
/* {"pmove", two(0xf000, 0x6100), two(oxffc0, oxffff), "*sZ8" }, */
|
||||
{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xffff), "*sY8" },
|
||||
{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xffff), "Y8%s" },
|
||||
{"pmove", two(0xf000, 0x6600), two(0xffc0, 0xffff), "Z8%s" },
|
||||
|
||||
{"prestore", one(0xf140), one(0xffc0), "&s"},
|
||||
{"prestore", one(0xf158), one(0xfff8), "+s"},
|
||||
{"psave", one(0xf100), one(0xffc0), "&s"},
|
||||
{"psave", one(0xf100), one(0xffc0), "+s"},
|
||||
|
||||
{"psac", two(0xf040, 0x0007), two(0xffc0, 0xffff), "@s"},
|
||||
{"psas", two(0xf040, 0x0006), two(0xffc0, 0xffff), "@s"},
|
||||
{"psbc", two(0xf040, 0x0001), two(0xffc0, 0xffff), "@s"},
|
||||
{"psbs", two(0xf040, 0x0000), two(0xffc0, 0xffff), "@s"},
|
||||
{"pscc", two(0xf040, 0x000f), two(0xffc0, 0xffff), "@s"},
|
||||
{"pscs", two(0xf040, 0x000e), two(0xffc0, 0xffff), "@s"},
|
||||
{"psgc", two(0xf040, 0x000d), two(0xffc0, 0xffff), "@s"},
|
||||
{"psgs", two(0xf040, 0x000c), two(0xffc0, 0xffff), "@s"},
|
||||
{"psic", two(0xf040, 0x000b), two(0xffc0, 0xffff), "@s"},
|
||||
{"psis", two(0xf040, 0x000a), two(0xffc0, 0xffff), "@s"},
|
||||
{"pslc", two(0xf040, 0x0003), two(0xffc0, 0xffff), "@s"},
|
||||
{"psls", two(0xf040, 0x0002), two(0xffc0, 0xffff), "@s"},
|
||||
{"pssc", two(0xf040, 0x0005), two(0xffc0, 0xffff), "@s"},
|
||||
{"psss", two(0xf040, 0x0004), two(0xffc0, 0xffff), "@s"},
|
||||
{"pswc", two(0xf040, 0x0009), two(0xffc0, 0xffff), "@s"},
|
||||
{"psws", two(0xf040, 0x0008), two(0xffc0, 0xffff), "@s"},
|
||||
|
||||
{"ptestr", two(0xf000, 0x8210), two(0xffc0, 0xe3f0), "T3&sQ8" },
|
||||
{"ptestr", two(0xf000, 0x8310), two(0xffc0, 0xe310), "T3&sQ8A9" },
|
||||
{"ptestr", two(0xf000, 0x8208), two(0xffc0, 0xe3f8), "D3&sQ8" },
|
||||
{"ptestr", two(0xf000, 0x8308), two(0xffc0, 0xe318), "D3&sQ8A9" },
|
||||
{"ptestr", two(0xf000, 0x8200), two(0xffc0, 0xe3fe), "f3&sQ8" },
|
||||
{"ptestr", two(0xf000, 0x8300), two(0xffc0, 0xe31e), "f3&sQ8A9" },
|
||||
|
||||
{"ptestw", two(0xf000, 0x8010), two(0xffc0, 0xe3f0), "T3&sQ8" },
|
||||
{"ptestw", two(0xf000, 0x8110), two(0xffc0, 0xe310), "T3&sQ8A9" },
|
||||
{"ptestw", two(0xf000, 0x8008), two(0xffc0, 0xe3f8), "D3&sQ8" },
|
||||
{"ptestw", two(0xf000, 0x8108), two(0xffc0, 0xe318), "D3&sQ8A9" },
|
||||
{"ptestw", two(0xf000, 0x8000), two(0xffc0, 0xe3fe), "f3&sQ8" },
|
||||
{"ptestw", two(0xf000, 0x8100), two(0xffc0, 0xe31e), "f3&sQ8A9" },
|
||||
|
||||
{"ptrapacw", two(0xf07a, 0x0007), two(0xffff, 0xffff), "#w"},
|
||||
{"ptrapacl", two(0xf07b, 0x0007), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapac", two(0xf07c, 0x0007), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptrapasw", two(0xf07a, 0x0006), two(0xffff, 0xffff), "#w"},
|
||||
{"ptrapasl", two(0xf07b, 0x0006), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapas", two(0xf07c, 0x0006), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptrapbcw", two(0xf07a, 0x0001), two(0xffff, 0xffff), "#w"},
|
||||
{"ptrapbcl", two(0xf07b, 0x0001), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapbc", two(0xf07c, 0x0001), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptrapbsw", two(0xf07a, 0x0000), two(0xffff, 0xffff), "#w"},
|
||||
{"ptrapbsl", two(0xf07b, 0x0000), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapbs", two(0xf07c, 0x0000), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptrapccw", two(0xf07a, 0x000f), two(0xffff, 0xffff), "#w"},
|
||||
{"ptrapccl", two(0xf07b, 0x000f), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapcc", two(0xf07c, 0x000f), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptrapcsw", two(0xf07a, 0x000e), two(0xffff, 0xffff), "#w"},
|
||||
{"ptrapcsl", two(0xf07b, 0x000e), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapcs", two(0xf07c, 0x000e), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptrapgcw", two(0xf07a, 0x000d), two(0xffff, 0xffff), "#w"},
|
||||
{"ptrapgcl", two(0xf07b, 0x000d), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapgc", two(0xf07c, 0x000d), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptrapgsw", two(0xf07a, 0x000c), two(0xffff, 0xffff), "#w"},
|
||||
{"ptrapgsl", two(0xf07b, 0x000c), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapgs", two(0xf07c, 0x000c), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptrapicw", two(0xf07a, 0x000b), two(0xffff, 0xffff), "#w"},
|
||||
{"ptrapicl", two(0xf07b, 0x000b), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapic", two(0xf07c, 0x000b), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptrapisw", two(0xf07a, 0x000a), two(0xffff, 0xffff), "#w"},
|
||||
{"ptrapisl", two(0xf07b, 0x000a), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapis", two(0xf07c, 0x000a), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptraplcw", two(0xf07a, 0x0003), two(0xffff, 0xffff), "#w"},
|
||||
{"ptraplcl", two(0xf07b, 0x0003), two(0xffff, 0xffff), "#l"},
|
||||
{"ptraplc", two(0xf07c, 0x0003), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptraplsw", two(0xf07a, 0x0002), two(0xffff, 0xffff), "#w"},
|
||||
{"ptraplsl", two(0xf07b, 0x0002), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapls", two(0xf07c, 0x0002), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptrapscw", two(0xf07a, 0x0005), two(0xffff, 0xffff), "#w"},
|
||||
{"ptrapscl", two(0xf07b, 0x0005), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapsc", two(0xf07c, 0x0005), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptrapssw", two(0xf07a, 0x0004), two(0xffff, 0xffff), "#w"},
|
||||
{"ptrapssl", two(0xf07b, 0x0004), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapss", two(0xf07c, 0x0004), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptrapwcw", two(0xf07a, 0x0009), two(0xffff, 0xffff), "#w"},
|
||||
{"ptrapwcl", two(0xf07b, 0x0009), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapwc", two(0xf07c, 0x0009), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"ptrapwsw", two(0xf07a, 0x0008), two(0xffff, 0xffff), "#w"},
|
||||
{"ptrapwsl", two(0xf07b, 0x0008), two(0xffff, 0xffff), "#l"},
|
||||
{"ptrapws", two(0xf07c, 0x0008), two(0xffff, 0xffff), ""},
|
||||
|
||||
{"pvalid", two(0xf000, 0x2800), two(0xffc0, 0xffff), "Vs&s"},
|
||||
{"pvalid", two(0xf000, 0x2c00), two(0xffc0, 0xfff8), "A3&s" },
|
||||
|
||||
#endif /* m68851 */
|
||||
/* end pmmu.h */
|
3808
gas/config/tc-m68k.c
Normal file
3808
gas/config/tc-m68k.c
Normal file
File diff suppressed because it is too large
Load diff
26
gas/config/tc-m68k.h
Normal file
26
gas/config/tc-m68k.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* This file is tp-generic.h and is intended to be a template for
|
||||
* target processor specific header files.
|
||||
*/
|
||||
|
||||
#define TC_M68K 1
|
||||
|
||||
#ifdef TE_SUN3
|
||||
/* This variable contains the value to write out at the beginning of
|
||||
the a.out file. The 2<<16 means that this is a 68020 file instead
|
||||
of an old-style 68000 file */
|
||||
|
||||
#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (2<<16|OMAGIC); /* Magic byte for file header */
|
||||
#endif /* TE_SUN3 */
|
||||
|
||||
#define tc_crawl_symbol_chain(a) ; /* not used */
|
||||
#define tc_headers_hook(a) ; /* not used */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of tc-m68k.h */
|
1867
gas/config/tc-ns32k.c
Normal file
1867
gas/config/tc-ns32k.c
Normal file
File diff suppressed because it is too large
Load diff
57
gas/config/tc-ns32k.h
Normal file
57
gas/config/tc-ns32k.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/* ns32k-opcode.h -- Opcode table for National Semi 32k processor
|
||||
Copyright (C) 1987 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
|
||||
#ifdef SEQUENT_COMPATABILITY
|
||||
#define DEF_MODEC 20
|
||||
#define DEF_MODEL 21
|
||||
#endif
|
||||
|
||||
#ifndef DEF_MODEC
|
||||
#define DEF_MODEC 20
|
||||
#endif
|
||||
|
||||
#ifndef DEF_MODEL
|
||||
#define DEF_MODEL 20
|
||||
#endif
|
||||
|
||||
#define MAX_ARGS 4
|
||||
#define ARG_LEN 50
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
void fix_new_ns32k(fragS *frag,
|
||||
int where,
|
||||
void *add_symbol, /* really symbolS */
|
||||
void *sub_symbol, /* really symbolS */
|
||||
long offset,
|
||||
int pcrel,
|
||||
int pcrel_adjust,
|
||||
int im_disp,
|
||||
void *bit_fixP, /* really bit_fixS */
|
||||
int bsr);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
void fix_new_ns32k();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
|
||||
/* end of tc-ns32k.h */
|
1297
gas/config/tc-sparc.c
Normal file
1297
gas/config/tc-sparc.c
Normal file
File diff suppressed because it is too large
Load diff
42
gas/config/tc-sparc.h
Normal file
42
gas/config/tc-sparc.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* tc-sparc.h - Macros and type defines for the sparc.
|
||||
Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 1,
|
||||
or (at your option) any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with GAS; see the file COPYING. If not, write
|
||||
to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#define TC_SPARC 1
|
||||
|
||||
#ifdef OBJ_BOUT
|
||||
#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE ((0x103 << 16) | BMAGIC) /* Magic number for header */
|
||||
#else
|
||||
#ifdef OBJ_AOUT
|
||||
#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE ((0x103 << 16) | OMAGIC) /* Magic number for header */
|
||||
#endif /* OBJ_AOUT */
|
||||
#endif /* OBJ_BOUT */
|
||||
|
||||
#define tc_headers_hook(a) ; /* don't need it. */
|
||||
#define tc_crawl_symbol_chain(a) ; /* don't need it. */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of tp-sparc.h */
|
3337
gas/config/tc-vax.c
Normal file
3337
gas/config/tc-vax.c
Normal file
File diff suppressed because it is too large
Load diff
14
gas/config/tc-vax.h
Normal file
14
gas/config/tc-vax.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* This file is tc-vax.h.
|
||||
*/
|
||||
|
||||
#define TC_VAX 1
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of tc-vax.h */
|
18
gas/config/te-generic.h
Normal file
18
gas/config/te-generic.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* This file is te-generic.h and is intended to be a template for
|
||||
* target environment specific header files.
|
||||
*/
|
||||
|
||||
#define TE_GENERIC 1
|
||||
|
||||
/* these define interfaces */
|
||||
#include "obj-format.h"
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of te-generic.h */
|
28
gas/config/te-ic960.h
Normal file
28
gas/config/te-ic960.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* This file is te-ic960.h and is intended to define ic960 environment
|
||||
* specific differences.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#define TE_IC960 1
|
||||
|
||||
/* intel uses host byte order for headers */
|
||||
#ifdef CROSS_ASSEMBLE
|
||||
#undef CROSS_ASSEMBLE
|
||||
#endif /* CROSS_ASSEMBLE */
|
||||
|
||||
#define OBJ_COFF_OMIT_OPTIONAL_HEADER
|
||||
#define LOCAL_LABEL(name) ( (name[0] =='L') \
|
||||
|| (name[0] =='.' \
|
||||
&& (name[1]=='C' || name[1]=='I' || name[1]=='.')))
|
||||
#include "obj-format.h"
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of te-ic960.h */
|
48
gas/config/te-sun3.h
Normal file
48
gas/config/te-sun3.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/* te-sun3.h -- Sun-3 target environment declarations.
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/* This header file contains the #defines specific
|
||||
to SUN computer SUN 3 series computers. (The only kind
|
||||
we have around here, unfortunatly.)
|
||||
|
||||
Rumor has it that this file will work on the Sun-2 if the assembler
|
||||
is called with -m68010 This is not tested. */
|
||||
|
||||
|
||||
#define TE_SUN3 1
|
||||
#define SUN_ASM_SYNTAX
|
||||
|
||||
/* Could also be :
|
||||
#define S_LOCAL_NAME(s) (S_GET_NAME(s)[0] == '.' &&
|
||||
S_GET_NAME(s)[1] == 'L' ||
|
||||
S_GET_NAME(s)[1] == '.')
|
||||
*/
|
||||
|
||||
#include "obj-format.h"
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of te-sun3.h */
|
77
gas/config/vax-inst.h
Normal file
77
gas/config/vax-inst.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* vax-inst.h - GNU - Part of vax.c
|
||||
Copyright (C) 1987 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*
|
||||
* This is part of vax-ins-parse.c & friends.
|
||||
* We want to parse a vax instruction text into a tree defined here.
|
||||
*/
|
||||
|
||||
#define VIT_MAX_OPERANDS (6) /* maximum number of operands in one */
|
||||
/* single vax instruction */
|
||||
|
||||
struct vop /* vax instruction operand */
|
||||
{
|
||||
short int vop_ndx; /* -1, or index register. eg 7=[R7] */
|
||||
short int vop_reg; /* -1, or register number. eg @I^#=0xF */
|
||||
/* Helps distinguish "abs" from "abs(PC)". */
|
||||
short int vop_mode; /* addressing mode 4 bits. eg I^#=0x9 */
|
||||
char vop_short; /* operand displacement length as written */
|
||||
/* ' '=none, "bilsw"=B^I^L^S^W^. */
|
||||
char vop_access; /* 'b'branch ' 'no-instruction 'amrvw'norm */
|
||||
char vop_width; /* Operand width, one of "bdfghloqw" */
|
||||
char * vop_warn; /* warning message of this operand, if any */
|
||||
char * vop_error; /* say if operand is inappropriate */
|
||||
char * vop_expr_begin; /* Unparsed expression, 1st char ... */
|
||||
char * vop_expr_end; /* ... last char. */
|
||||
unsigned char vop_nbytes; /* number of bytes in datum */
|
||||
};
|
||||
|
||||
|
||||
typedef long vax_opcodeT; /* For initialising array of opcodes */
|
||||
/* Some synthetic opcodes > 16 bits! */
|
||||
|
||||
#define VIT_OPCODE_SYNTHETIC 0x80000000 /* Not real hardware instruction. */
|
||||
#define VIT_OPCODE_SPECIAL 0x40000000 /* Not normal branch optimising. */
|
||||
/* Never set without ..._SYNTHETIC */
|
||||
|
||||
#define VAX_WIDTH_UNCONDITIONAL_JUMP '-' /* These are encoded into */
|
||||
#define VAX_WIDTH_CONDITIONAL_JUMP '?' /* vop_width when vop_access=='b' */
|
||||
#define VAX_WIDTH_WORD_JUMP '!' /* and VIT_OPCODE_SYNTHETIC set. */
|
||||
#define VAX_WIDTH_BYTE_JUMP ':' /* */
|
||||
|
||||
#define VAX_JMP (0x17) /* Useful for branch optimising. Jump instr*/
|
||||
#define VAX_PC_RELATIVE_MODE (0xef) /* Use it after VAX_JMP */
|
||||
#define VAX_ABSOLUTE_MODE (0x9F) /* Use as @#... */
|
||||
#define VAX_BRB (0x11) /* Canonical branch. */
|
||||
#define VAX_BRW (0x31) /* Another canonical branch */
|
||||
#define VAX_WIDEN_WORD (0x20) /* Add this to byte branch to get word br. */
|
||||
#define VAX_WIDEN_LONG (0x6) /* Add this to byte branch to get long jmp.*/
|
||||
/* Needs VAX_PC_RELATIVE_MODE byte after it*/
|
||||
|
||||
struct vit /* vax instruction tree */
|
||||
{
|
||||
/* vit_opcode is char[] for portability. */
|
||||
char vit_opcode [ sizeof (vax_opcodeT) ];
|
||||
unsigned char vit_opcode_nbytes; /* How long is _opcode? (chars) */
|
||||
unsigned char vit_operands;/* */
|
||||
struct vop vit_operand[VIT_MAX_OPERANDS]; /* operands */
|
||||
char * vit_error; /* "" or error text */
|
||||
};
|
||||
|
||||
/* end: vax-inst.h */
|
876
gas/configure
vendored
Executable file
876
gas/configure
vendored
Executable file
|
@ -0,0 +1,876 @@
|
|||
#!/bin/sh
|
||||
# Do not edit this file. It is generated automatically from configure.in
|
||||
# and a configure template.
|
||||
configdirs=
|
||||
|
||||
#!/bin/sh
|
||||
# Do not edit this file. It is generated automatically from configure.in
|
||||
# and a configure template.
|
||||
configdirs=
|
||||
|
||||
# Configuration script template
|
||||
# Copyright (C) 1988, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
#This file is part of GNU.
|
||||
|
||||
#GNU CC is free software; you can redistribute it and/or modify
|
||||
#it under the terms of the GNU General Public License as published by
|
||||
#the Free Software Foundation; either version 1, or (at your option)
|
||||
#any later version.
|
||||
|
||||
#GNU CC is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU General Public License for more details.
|
||||
|
||||
#You should have received a copy of the GNU General Public License
|
||||
#along with GNU CC; see the file COPYING. If not, write to
|
||||
#the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
#
|
||||
# Shell script to create proper links to machine-dependent files in
|
||||
# preparation for compiling gcc.
|
||||
#
|
||||
# Usage: configure [+srcdir=DIR] [+host=HOST] [+gas] [+nfp] TARGET
|
||||
#
|
||||
# If configure succeeds, it leaves its status in config.status.
|
||||
# If configure fails after disturbing the status quo,
|
||||
# config.status is removed.
|
||||
#
|
||||
|
||||
progname=$0
|
||||
|
||||
remove=rm
|
||||
hard_link=ln
|
||||
symbolic_link='ln -s'
|
||||
|
||||
#for Test
|
||||
#remove="echo rm"
|
||||
#hard_link="echo ln"
|
||||
#symbolic_link="echo ln -s"
|
||||
|
||||
# clear some things potentially inherited from environment.
|
||||
target=
|
||||
template=
|
||||
removing=
|
||||
norecurse=
|
||||
ansi=
|
||||
|
||||
for arg in $*;
|
||||
do
|
||||
case $arg in
|
||||
-ansi | +ansi)
|
||||
ansi=true
|
||||
;;
|
||||
-template=* | +template=*)
|
||||
template=`echo $arg | sed 's/[+-]template=//'`
|
||||
;;
|
||||
-norecurse | +norecurse)
|
||||
norecurse=true
|
||||
;;
|
||||
-rm | +rm)
|
||||
removing=$arg
|
||||
;;
|
||||
-srcdir=* | +srcdir=* | +srcdi=* | +srcd=* | +src=* | +sr=* | +s=*)
|
||||
srcdir=`echo $arg | sed 's/[+-]s[a-z]*=//'`
|
||||
;;
|
||||
-host=* | +host=* | +hos=* | +ho=* | +h=*)
|
||||
host=`echo $arg | sed 's/[+-]h[a-z]*=//'`
|
||||
;;
|
||||
-languages=* | +languages=* | -languag=* | +languag=* | langua=* \
|
||||
| +langua=* | -langu=* | +langu=* | -lang=* | +lang=* | -lan=* \
|
||||
| +lan=* | -la=* | +la=* | -l=* | +l=*)
|
||||
languages="$languages `echo $arg | sed 's/[+-]l[a-z]*=//'`"
|
||||
;;
|
||||
-gas | +gas | +ga | +g)
|
||||
gas=yes
|
||||
;;
|
||||
-nfp | +nfp | +nf | +n)
|
||||
nfp=yes
|
||||
;;
|
||||
*)
|
||||
# Allow configure HOST TARGET
|
||||
if [ x$host = x ] ; then host=$target ; fi
|
||||
target=$arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# process host and target only if not rebuilding configure itself.
|
||||
if [ -z "$template" ]
|
||||
then
|
||||
# Complain if an arg is missing
|
||||
if [ x$target = x ]
|
||||
then
|
||||
echo "Usage: $progname [+srcdir=DIR] [+host=HOST] [+gas] [+nfp] TARGET"
|
||||
echo -n "Where HOST and TARGET are something like "
|
||||
echo "\`vax', \`sun3', \`encore', etc."
|
||||
if [ -r config.status ]
|
||||
then
|
||||
cat config.status
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Default other arg
|
||||
if [ x$host = x ]
|
||||
then
|
||||
host=$target
|
||||
fi
|
||||
|
||||
# Decode the host machine, then the target machine.
|
||||
# For the host machine, we save the xm_file variable as host_xm_file;
|
||||
# then we decode the target machine and forget everything else
|
||||
# that came from the host machine.
|
||||
for machine in $host $target; do
|
||||
|
||||
# Separate what the user gave into CPU/company and OS (if any).
|
||||
basic_machine=`echo $machine | sed 's/-[^-]*$//'`
|
||||
if [ $basic_machine != $machine ]
|
||||
then os=`echo $machine | sed 's/[^-]*-/-/'`
|
||||
else os=; fi
|
||||
|
||||
# Decode aliases for certain machine/company combinations.
|
||||
case $basic_machine in
|
||||
iris | iris4d)
|
||||
basic_machine=mips/sgi
|
||||
;;
|
||||
news | news800)
|
||||
basic_machine=m68k/sony
|
||||
;;
|
||||
3b1 | 7300 | 7300/att | att-7300)
|
||||
basic_machine=m68k/att
|
||||
;;
|
||||
delta | 3300 | motorola-3300 | motorola-delta \
|
||||
| 3300/motorola | delta/motorola)
|
||||
basic_machine=m68k/motorola
|
||||
;;
|
||||
vax/dec)
|
||||
basic_machine=vax
|
||||
;;
|
||||
balance)
|
||||
basic_machine=ns32k/sequent
|
||||
;;
|
||||
symmetry)
|
||||
basic_machine=i386/sequent
|
||||
;;
|
||||
sun2)
|
||||
basic_machine=m68000/sun
|
||||
;;
|
||||
sun3)
|
||||
basic_machine=m68k/sun
|
||||
;;
|
||||
sun4)
|
||||
basic_machine=sparc/sun
|
||||
;;
|
||||
sun386 | sun386i)
|
||||
basic_machine=i386/sun
|
||||
;;
|
||||
ps2)
|
||||
basic_machine=i386/ibm
|
||||
;;
|
||||
next)
|
||||
basic_machine=m68k/next
|
||||
;;
|
||||
hp9k3[2-9][0-9])
|
||||
basic_machine=m68k/hp
|
||||
;;
|
||||
hp9k31[0-9] | hp9k2[0-9][0-9])
|
||||
basic_machine=m68000/hp
|
||||
;;
|
||||
isi68)
|
||||
basic_machine=m68k/isi
|
||||
;;
|
||||
apollo68)
|
||||
basic_machine=m68k/apollo
|
||||
;;
|
||||
altos | altos3068)
|
||||
basic_machine=m68k/altos
|
||||
;;
|
||||
miniframe)
|
||||
basic_machine=m68000/convergent
|
||||
;;
|
||||
tower | tower-32)
|
||||
basic_machine=m68k/ncr
|
||||
;;
|
||||
news-3600 | risc-news)
|
||||
basic_machine=mips/sony
|
||||
;;
|
||||
decstation | decstation-3100 | pmax)
|
||||
basic_machine=mips/dec
|
||||
;;
|
||||
gmicro)
|
||||
basic_machine=tron
|
||||
;;
|
||||
convex-c1)
|
||||
basic_machine=c1/convex
|
||||
;;
|
||||
convex-c2)
|
||||
basic_machine=c2/convex
|
||||
;;
|
||||
esac
|
||||
|
||||
# Decode manufacturer-specific aliases for certain operating systems.
|
||||
|
||||
case $os in
|
||||
-newsos*)
|
||||
os=-bsd
|
||||
;;
|
||||
-ultrix*)
|
||||
os=-bsd
|
||||
;;
|
||||
-dynix*)
|
||||
os=-bsd
|
||||
;;
|
||||
-ctix*)
|
||||
os=-sysv
|
||||
;;
|
||||
esac
|
||||
|
||||
machine=$basic_machine$os
|
||||
|
||||
cpu_type=
|
||||
xm_file=
|
||||
tm_file=
|
||||
make_var_file=
|
||||
|
||||
case $machine in
|
||||
vax | vax-bsd*) # vaxen running BSD
|
||||
;;
|
||||
vax-vms | vms) # vaxen running VMS
|
||||
cpu_type=vax
|
||||
xm_file=xm-vms.h
|
||||
tm_file=tm-vms.h
|
||||
;;
|
||||
vax-sysv* | vaxv) # vaxen running system V
|
||||
cpu_type=vax
|
||||
xm_file=xm-vaxv.h
|
||||
tm_file=tm-vaxv.h
|
||||
;;
|
||||
tahoe | tahoe-bsd*) # tahoe running BSD
|
||||
;;
|
||||
tahoe/harris*) # Harris tahoe, using COFF.
|
||||
cpu_type=tahoe
|
||||
;;
|
||||
i386/sequent* | i386/sequent-bsd*) # 80386 from Sequent
|
||||
cpu_type=i386
|
||||
xm_file=xm-i386.h
|
||||
tm_file=tm-seq386.h
|
||||
;;
|
||||
i386-mach | i386/*-mach)
|
||||
cpu_type=i386
|
||||
xm_file=xm-i386.h
|
||||
tm_file=tm-i386gas.h
|
||||
;;
|
||||
i386/sco | i386/sco-sysv* | i386/*-sco) # 80386 running SCO system
|
||||
cpu_type=i386
|
||||
xm_file=xm-i386v.h
|
||||
tm_file=tm-i386sco.h
|
||||
make_var_file=make-i386sco
|
||||
;;
|
||||
i386/isc | i386/isc-sysv* | i386/*-isc) # 80386 running ISC system
|
||||
cpu_type=i386
|
||||
xm_file=xm-i386v.h
|
||||
tm_file=tm-i386isc.h
|
||||
make_var_file=make-i386isc
|
||||
;;
|
||||
i386/ibm | i386-aix | i386/ibm-aix) # IBM PS/2 running AIX
|
||||
cpu_type=i386
|
||||
tm_file=tm-i386v.h
|
||||
xm_file=xm-i386v.h
|
||||
make_var_file=make-i386v
|
||||
;;
|
||||
i386/sun*)
|
||||
cpu_type=i386
|
||||
xm_file=xm-sun386i.h
|
||||
tm_file=tm-sun386i.h
|
||||
;;
|
||||
i386-sysv4 | i386/*-sysv4 | i386v4) # Intel 80386's running system V.4
|
||||
cpu_type=i386
|
||||
xm_file=xm-i386v.h
|
||||
make_var_file=make-i386v
|
||||
tm_file=tm-i386v4.h
|
||||
;;
|
||||
i386-sysv* | i386/*-sysv* | i386v) # Intel 80386's running system V
|
||||
cpu_type=i386
|
||||
xm_file=xm-i386v.h
|
||||
make_var_file=make-i386v
|
||||
if [ x$gas = xyes ]
|
||||
then
|
||||
tm_file=tm-i386gas.h
|
||||
else
|
||||
tm_file=tm-i386v.h
|
||||
fi
|
||||
;;
|
||||
i860 | i860-sysv* | i860/*-sysv*)
|
||||
cpu_type=i860
|
||||
if [ x$gas = xyes ]
|
||||
then
|
||||
tm_file=tm-i860g.h
|
||||
else
|
||||
tm_file=tm-i860.h
|
||||
fi
|
||||
;;
|
||||
i860-bsd* | i860/*-bsd*)
|
||||
cpu_type=i860
|
||||
if [ x$gas = xyes ]
|
||||
then
|
||||
tm_file=tm-i860bsdg.h
|
||||
else
|
||||
tm_file=tm-i860bsd.h
|
||||
fi
|
||||
;;
|
||||
sparc | sparc/* | sparc-*os4 | sparc/*-*os4)
|
||||
cpu_type=sparc
|
||||
tm_file=tm-sparc.h
|
||||
;;
|
||||
sparc-*os3 | sparc/*-*os3)
|
||||
cpu_type=sparc
|
||||
tm_file=tm-sun4os3.h
|
||||
;;
|
||||
m68k/next)
|
||||
cpu_type=m68k
|
||||
tm_file=tm-next.h
|
||||
out_file=out-next.c
|
||||
xm_file=xm-next.h
|
||||
;;
|
||||
m68k/sun-*os3)
|
||||
cpu_type=m68k
|
||||
if [ x$nfp = xyes ]
|
||||
then
|
||||
tm_file=tm-sun3os3nf.h
|
||||
else
|
||||
tm_file=tm-sun3os3.h
|
||||
fi
|
||||
;;
|
||||
m68k/sun-mach)
|
||||
cpu_type=m68k
|
||||
tm_file=tm-sun3mach.h
|
||||
;;
|
||||
m68k/sun | m68k/sun-*os4)
|
||||
cpu_type=m68k
|
||||
if [ x$nfp = xyes ]
|
||||
then
|
||||
tm_file=tm-sun3nfp.h
|
||||
else
|
||||
tm_file=tm-sun3.h
|
||||
fi
|
||||
;;
|
||||
m68k/hp | m68k/hp-hpux*) # HP 9000 series 300
|
||||
cpu_type=m68k
|
||||
xm_file=xm-hp9k320.h
|
||||
if [ x$gas = xyes ]
|
||||
then
|
||||
make_var_file=make-hp9k320g
|
||||
tm_file=tm-hp9k320g.h
|
||||
else
|
||||
make_var_file=make-hp9k320
|
||||
tm_file=tm-hp9k320.h
|
||||
fi
|
||||
;;
|
||||
m68k/hp-bsd*) # HP 9000/3xx running Berkeley Unix
|
||||
cpu_type=m68k
|
||||
tm_file=tm-hp9k3bsd.h
|
||||
;;
|
||||
m68k/isi | m68k/isi-bsd*)
|
||||
cpu_type=m68k
|
||||
if [ x$nfp = xyes ]
|
||||
then
|
||||
tm_file=tm-isi68-nfp.h
|
||||
else
|
||||
tm_file=tm-isi68.h
|
||||
fi
|
||||
;;
|
||||
m68k/sony | m68k/sony-bsd*)
|
||||
xm_file=xm-m68k.h
|
||||
cpu_type=m68k
|
||||
if [ x$gas = xyes ]
|
||||
then
|
||||
tm_file=tm-newsgas.h
|
||||
else
|
||||
tm_file=tm-news.h
|
||||
fi
|
||||
;;
|
||||
m68k/altos | m68k/altos-sysv*) # Altos 3068
|
||||
cpu_type=m68k
|
||||
if [ x$gas = xyes ]
|
||||
then
|
||||
xm_file=xm-altos3068.h
|
||||
tm_file=tm-altos3068.h
|
||||
else
|
||||
echo "The Altos is supported only with the GNU assembler" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
m68k/motorola | m68k/motorola-sysv*)
|
||||
cpu_type=m68k
|
||||
tm_file=tm-mot3300.h
|
||||
xm_file=xm-mot3300.h
|
||||
;;
|
||||
m68k/crds | m68k/crds-unos | m68k-unos | crds | unos)
|
||||
cpu_type=m68k
|
||||
xm_file=xm-crds.h
|
||||
make_var_file=make-crds
|
||||
tm_file=tm-crds.h
|
||||
;;
|
||||
m68k/apollo)
|
||||
cpu_type=m68k
|
||||
make_var_file=make-apollo68
|
||||
tm_file=tm-apollo68.h
|
||||
;;
|
||||
m68k/ncr | m68k/ncr-sysv*) # NCR Tower 32 SVR3
|
||||
cpu_type=m68k
|
||||
tm_file=tm-tower-as.h
|
||||
xm_file=xm-tower.h
|
||||
;;
|
||||
m68000/sun | m68000/sun-*os3)
|
||||
cpu_type=m68k
|
||||
tm_file=tm-sun2.h
|
||||
;;
|
||||
m68000/sun-*os4)
|
||||
cpu_type=m68k
|
||||
tm_file=tm-sun2os4.h
|
||||
;;
|
||||
m68000/hp | m68000/hp-hpux*) # HP 9000 series 300
|
||||
cpu_type=m68k
|
||||
xm_file=xm-hp9k310.h
|
||||
if [ x$gas = xyes ]
|
||||
then
|
||||
make_var_file=make-hp9k320g
|
||||
tm_file=tm-hp9k310g.h
|
||||
else
|
||||
make_var_file=make-hp9k320
|
||||
tm_file=tm-hp9k310.h
|
||||
fi
|
||||
;;
|
||||
m68000/hp-bsd*) # HP 9000/200 running BSD
|
||||
cpu_type=m68k
|
||||
tm_file=tm-hp9k2bsd.h
|
||||
make_var_file=make-hp9k2bsd
|
||||
;;
|
||||
m68000/att | m68000/att-sysv*)
|
||||
cpu_type=m68k
|
||||
xm_file=xm-3b1.h
|
||||
if [ x$gas = xyes ]
|
||||
then
|
||||
tm_file=tm-3b1g.h
|
||||
else
|
||||
tm_file=tm-3b1.h
|
||||
fi
|
||||
;;
|
||||
m68000/convergent | m68000/convergent-sysv*)
|
||||
cpu_type=m68k
|
||||
xm_file=xm-3b1.h
|
||||
tm_file=tm-ctix.h
|
||||
;;
|
||||
ns32k/sequent | ns32k/sequent-bsd*)
|
||||
cpu_type=ns32k
|
||||
tm_file=tm-sequent.h
|
||||
;;
|
||||
ns32k/encore | ns32k/encore-bsd* | encore | encore-bsd*)
|
||||
cpu_type=ns32k
|
||||
tm_file=tm-encore.h
|
||||
;;
|
||||
ns32k-genix* | ns32k/*-genix* | genix)
|
||||
cpu_type=ns32k
|
||||
xm_file=xm-genix.h
|
||||
make_var_file=make-genix
|
||||
tm_file=tm-genix.h
|
||||
;;
|
||||
merlin)
|
||||
cpu_type=ns32k
|
||||
;;
|
||||
m88k/dg | m88k/dg-dgux* | m88k-dgux*)
|
||||
cpu_type=m88k
|
||||
xm_file=xm-m88kdgux.h
|
||||
make_var_file=make-m88kdgux
|
||||
tm_file=tm-m88kdgux.h
|
||||
;;
|
||||
m88k-v88r32 | m88k/*-v88r32)
|
||||
cpu_type=m88k
|
||||
tm_file=tm-v88r32.h
|
||||
xm_file=xm-v88r32.h
|
||||
;;
|
||||
m88k-sysv* | m88k/*-sysv*)
|
||||
cpu_type=m88k
|
||||
tm_file=tm-m88ksvr4.h
|
||||
xm_file=xm-m88ksvr4.h
|
||||
;;
|
||||
alliant | alliant/alliant) # Alliant FX/8
|
||||
cpu_type=alliant
|
||||
tm_file=tm-alliant.h
|
||||
;;
|
||||
c1/convex) # Convex C1
|
||||
if [ -r /usr/include/stdlib.h ]
|
||||
then
|
||||
tm_file=tm-convex1.h
|
||||
else
|
||||
tm_file=tm-conv1os7.h
|
||||
fi
|
||||
cpu_type=convex
|
||||
;;
|
||||
c2/convex) # Convex C2
|
||||
if [ -r /usr/include/stdlib.h ]
|
||||
then
|
||||
tm_file=tm-convex2.h
|
||||
else
|
||||
tm_file=tm-conv2os7.h
|
||||
fi
|
||||
cpu_type=convex
|
||||
;;
|
||||
mips/sgi | mips/sgi-sysv*) # Mostly like a MIPS.
|
||||
cpu_type=mips
|
||||
tm_file=tm-iris.h
|
||||
xm_file=xm-iris.h
|
||||
;;
|
||||
mips | mips/mips) # Default MIPS environment.
|
||||
;;
|
||||
mips/dec | mips/dec-bsd*) # Decstation.
|
||||
cpu_type=mips
|
||||
tm_file=tm-decstatn.h
|
||||
;;
|
||||
mips/sony | mips/sony-bsd*) # Sony NEWS 3600 or risc/news.
|
||||
cpu_type=mips
|
||||
tm_file=tm-mips-news.h
|
||||
;;
|
||||
mips/*-sysv* | mips-sysv*) # SYSV variant of MIPS system.
|
||||
cpu_type=mips
|
||||
tm_file=tm-mips-sysv.h
|
||||
;;
|
||||
mips/*-bsd* | mips-bsd*) # BSD 4.3 variant of MIPS system.
|
||||
cpu_type=mips
|
||||
tm_file=tm-mips-bsd.h
|
||||
;;
|
||||
pyramid | pyramid/* | pyramid-*)
|
||||
cpu_type=pyr
|
||||
tm_file=tm-pyr.h
|
||||
;;
|
||||
tron | tron/*)
|
||||
cpu_type=gmicro
|
||||
tm_file=tm_gmicro.h
|
||||
;;
|
||||
a29k-bsd* | a29k/*-bsd*)
|
||||
cpu_type=a29k
|
||||
tm_file=tm-a29kunix.h
|
||||
;;
|
||||
i960) # Default i960 environment.
|
||||
;;
|
||||
# 370)
|
||||
# ;;
|
||||
esac
|
||||
if [ x$pass1done = x ]
|
||||
then
|
||||
if [ x$cpu_type = x ]; then cpu_type=$host; fi
|
||||
if [ x$xm_file = x ]; then host_xm_file=xm-$cpu_type.h
|
||||
else host_xm_file=$xm_file
|
||||
fi
|
||||
if [ x$make_var_file = x ]
|
||||
then make_var_file=make-$cpu_type; fi
|
||||
host_make_var_file=$make_var_file
|
||||
pass1done=yes
|
||||
fi
|
||||
done
|
||||
|
||||
# Default the machine-specific variables that were not explicitly set.
|
||||
if [ x$cpu_type = x ]
|
||||
then cpu_type=$target; fi
|
||||
|
||||
if [ x$tm_file = x ]
|
||||
then tm_file=tm-$target.h; fi
|
||||
|
||||
md_file=${cpu_type}.md
|
||||
|
||||
if [ x$out_file = x ]
|
||||
then out_file=out-$cpu_type.c; fi
|
||||
fi
|
||||
|
||||
#### configure.in files go here.
|
||||
# This file is a shell script that supplies the information necessary
|
||||
# to tailor a template configure script into the configure script
|
||||
# appropriate for this directory. For more information, check any
|
||||
# existing configure script.
|
||||
|
||||
srctrigger=as.c
|
||||
srcname="gas"
|
||||
|
||||
case $target in
|
||||
*-coff)
|
||||
obj_format=coff
|
||||
;;
|
||||
*-bout)
|
||||
obj_format=bout
|
||||
;;
|
||||
*)
|
||||
obj_format=aout
|
||||
;;
|
||||
esac
|
||||
|
||||
case $target in
|
||||
vax)
|
||||
atof=vax
|
||||
;;
|
||||
*)
|
||||
atof=ieee
|
||||
;;
|
||||
esac
|
||||
|
||||
files="ho-${host}.h tc-${cpu_type}.c tc-${cpu_type}.h te-generic.h obj-${obj_format}.h obj-${obj_format}.c atof-${atof}.c"
|
||||
links="host.h targ-cpu.c targ-cpu.h targ-env.h obj-format.h obj-format.c atof-targ.c"
|
||||
### end of configure.in
|
||||
|
||||
# are we rebuilding config itself?
|
||||
if [ -n "$template" ]
|
||||
then
|
||||
if [ ! -r $template ]
|
||||
then
|
||||
echo "Can't find template ${template}."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mv configure configure.old
|
||||
echo "#!/bin/sh" > configure
|
||||
echo "# Do not edit this file. It is generated automatically from configure.in" >> configure
|
||||
echo "# and a configure template." >> configure
|
||||
echo "configdirs=" >> configure
|
||||
echo >> configure
|
||||
|
||||
if [ -r configure.in ]
|
||||
then
|
||||
sed -e "/^####/ r configure.in" $template >> configure
|
||||
else
|
||||
cat $template >> configure
|
||||
fi
|
||||
|
||||
chmod a+x configure
|
||||
rm configure.old
|
||||
# echo Rebuilt configure in `pwd` from ${template}.
|
||||
echo Rebuilt configure in `pwd`
|
||||
|
||||
if [ x$norecurse = x ]
|
||||
then
|
||||
while [ -n "$configdirs" ]
|
||||
do
|
||||
# set configdir to car of configdirs, configdirs to cdr of configdirs
|
||||
set $configdirs; configdir=$1; shift; configdirs=$*
|
||||
|
||||
if [ "`echo ${configdir}.*`" != "${configdir}.*" ]
|
||||
then
|
||||
targetspecificdirs=${configdir}.*
|
||||
else
|
||||
targetspecificdirs=
|
||||
fi
|
||||
|
||||
for i in ${configdir} ${targetspecificdirs}
|
||||
do
|
||||
if [ -r $i/configure ]
|
||||
then
|
||||
(cd $i ;
|
||||
configure +template=${template})
|
||||
else
|
||||
echo No configure script in `pwd`/$i
|
||||
fi
|
||||
done
|
||||
done
|
||||
fi
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Temporarily, we support only direct subdir builds.
|
||||
hostsubdir=Host-$host
|
||||
targetsubdir=Target-$target
|
||||
|
||||
if [ -n "$removing" ]
|
||||
then
|
||||
rm -rf $hostsubdir/$targetsubdir
|
||||
|
||||
if [ -z "`(ls $hostsubdir) 2>&1 | grep Target-`" ]
|
||||
then
|
||||
rm -rf $hostsubdir
|
||||
fi
|
||||
else
|
||||
if [ ! -d $hostsubdir ] ; then mkdir $hostsubdir ; fi
|
||||
cd $hostsubdir
|
||||
|
||||
if [ ! -d $targetsubdir ] ; then mkdir $targetsubdir ; fi
|
||||
cd $targetsubdir
|
||||
|
||||
srcdir=../..
|
||||
|
||||
## Find the source files, if location was not specified.
|
||||
#if [ x$srcdir = x ]
|
||||
#then
|
||||
# srcdirdefaulted=1
|
||||
# srcdir=.
|
||||
# if [ ! -r ${srctrigger} ]
|
||||
# then
|
||||
# srcdir=..
|
||||
# fi
|
||||
#fi
|
||||
#
|
||||
#if [ ! -r ${srcdir}/${srctrigger} ]
|
||||
#then
|
||||
# if [ x$srcdirdefaulted = x ]
|
||||
# then
|
||||
# echo "$progname: Can't find ${srcname} sources in \`${srcdir}'." 1>&2
|
||||
# else
|
||||
# echo "$progname: Can't find ${srcname} sources in \`.' or \`..'." 1>&2
|
||||
# fi
|
||||
# exit 1
|
||||
#fi
|
||||
|
||||
|
||||
|
||||
# Set up the list of links to be made.
|
||||
# $links is the list of link names, and $files is the list of names to link to.
|
||||
|
||||
# Make the links.
|
||||
while [ -n "$files" ]
|
||||
do
|
||||
# set file to car of files, files to cdr of files
|
||||
set $files; file=$1; shift; files=$*
|
||||
set $links; link=$1; shift; links=$*
|
||||
|
||||
if [ ! -r ${srcdir}/config/$file ]
|
||||
then
|
||||
echo "$progname: cannot create a link \`$link'," 1>&2
|
||||
echo "since the file \`config/$file' does not exist." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
$remove -f $link
|
||||
rm -f config.status
|
||||
# Make a symlink if possible, otherwise try a hard link
|
||||
$symbolic_link ${srcdir}/config/$file $link 2>/dev/null || $hard_link ${srcdir}/config/$file $link
|
||||
|
||||
if [ ! -r $link ]
|
||||
then
|
||||
echo "$progname: unable to link \`$link' to \`${srcdir}/config/$file'." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Linked \`$link' to \`${srcdir}/config/$file'."
|
||||
done
|
||||
|
||||
# Install a makefile, and make it set VPATH
|
||||
# if necessary so that the sources are found.
|
||||
# Also change its value of srcdir.
|
||||
# Also create a .gdbinit file which runs the one in srcdir
|
||||
# and tells GDB to look there for source files.
|
||||
case $srcdir in
|
||||
.)
|
||||
;;
|
||||
*)
|
||||
echo "VPATH = ${srcdir}" > x
|
||||
cat x ${srcdir}/Makefile.in | sed "s@^srcdir = \.@srcdir = ${srcdir}@" > Makefile.in
|
||||
rm x
|
||||
echo "dir ." > .gdbinit
|
||||
echo "dir ${srcdir}" >> .gdbinit
|
||||
echo "source ${srcdir}/.gdbinit" >> .gdbinit
|
||||
;;
|
||||
esac
|
||||
|
||||
host_var_file=hmake-${host}
|
||||
target_var_file=tmake-${target}
|
||||
|
||||
# Conditionalize the makefile for this machine.
|
||||
if [ -f ${srcdir}/config/${host_var_file} ]
|
||||
then
|
||||
sed -e "/^####/ r ${srcdir}/config/${host_var_file}" Makefile.in > Makefile.tem
|
||||
else
|
||||
cp Makefile.in Makefile.tem
|
||||
fi
|
||||
|
||||
if [ -f ${srcdir}/config/${target_var_file} ]
|
||||
then
|
||||
sed -e "/^####/ r ${srcdir}/config/${target_var_file}" Makefile.tem > Makefile.tem1
|
||||
mv Makefile.tem1 Makefile.tem
|
||||
fi
|
||||
|
||||
# Remove all formfeeds, since some Makes get confused by them.
|
||||
sed "s///" Makefile.tem >> Makefile.tem1
|
||||
mv Makefile.tem1 Makefile.tem
|
||||
|
||||
# reset SUBDIRS
|
||||
sed "s:^SUBDIRS =.*$:SUBDIRS = ${configdirs}:" Makefile.tem > Makefile.tem1
|
||||
mv Makefile.tem1 Makefile.tem
|
||||
|
||||
# reset NONSUBDIRS
|
||||
sed "s:^NONSUBDIRS =.*$:NONSUBDIRS = ${noconfigdirs}:" Makefile.tem > Makefile.tem1
|
||||
mv Makefile.tem1 Makefile.tem
|
||||
|
||||
# Delete the intermediate files
|
||||
if [ x$srcdir != x. ] ; then rm Makefile.in ; fi
|
||||
|
||||
rm -f Makefile
|
||||
|
||||
# Define macro CROSS_COMPILE in compilation if this is a cross-compiler.
|
||||
if [ x$host != x$target ]
|
||||
then
|
||||
echo "CROSS=-DCROSS_COMPILE" > Makefile
|
||||
echo "ALL=start.encap" >> Makefile
|
||||
else
|
||||
echo "ALL=all.internal" > Makefile
|
||||
fi
|
||||
|
||||
# set target and host
|
||||
echo "host = $host" >> Makefile
|
||||
echo "target = $target" >> Makefile
|
||||
|
||||
cat Makefile.tem >> Makefile
|
||||
rm Makefile.tem
|
||||
|
||||
using=
|
||||
if [ -f ${srcdir}/config/${host_var_file} ]
|
||||
then
|
||||
using=" using \"${host_var_file}\""
|
||||
fi
|
||||
|
||||
if [ -f ${srcdir}/config/${target_var_file} ]
|
||||
then
|
||||
if [ -z "${using}" ]
|
||||
then
|
||||
andusing=" using \"${target_var_file}\""
|
||||
else
|
||||
andusing="${using} and \"${target_var_file}\""
|
||||
fi
|
||||
else
|
||||
andusing=${using}
|
||||
fi
|
||||
|
||||
echo "Created \"Makefile\""${andusing}.
|
||||
|
||||
if [ x$host = x$target ]
|
||||
then
|
||||
echo "Links are now set up for use with a $target." \
|
||||
| tee ${srcdir}/config.status
|
||||
else
|
||||
echo "Links are now set up for host $host and target $target." \
|
||||
| tee ${srcdir}/config.status
|
||||
fi
|
||||
|
||||
cd ${srcdir}
|
||||
fi
|
||||
|
||||
# If there are subdirectories, then recurse.
|
||||
|
||||
if [ x$norecurse != x ] ; then exit 0 ; fi
|
||||
|
||||
while [ -n "$configdirs" ]
|
||||
do
|
||||
# set configdir to car of configdirs, configdirs to cdr of configdirs
|
||||
set $configdirs; configdir=$1; shift; configdirs=$*
|
||||
|
||||
# check for target override
|
||||
targetspecificdir=${configdir}.${target}
|
||||
if [ -d ${targetspecificdir} ]
|
||||
then
|
||||
configdir=${targetspecificdir}
|
||||
fi
|
||||
|
||||
echo Configuring ${configdir}...
|
||||
(cd ${configdir} ;
|
||||
configure +host=${host} ${target} ${removing}) \
|
||||
| sed 's/^/ /'
|
||||
done
|
||||
|
||||
exit 0
|
31
gas/configure.in
Normal file
31
gas/configure.in
Normal file
|
@ -0,0 +1,31 @@
|
|||
# This file is a shell script that supplies the information necessary
|
||||
# to tailor a template configure script into the configure script
|
||||
# appropriate for this directory. For more information, check any
|
||||
# existing configure script.
|
||||
|
||||
srctrigger=as.c
|
||||
srcname="gas"
|
||||
|
||||
case $target in
|
||||
*-coff)
|
||||
obj_format=coff
|
||||
;;
|
||||
*-bout)
|
||||
obj_format=bout
|
||||
;;
|
||||
*)
|
||||
obj_format=aout
|
||||
;;
|
||||
esac
|
||||
|
||||
case $target in
|
||||
vax)
|
||||
atof=vax
|
||||
;;
|
||||
*)
|
||||
atof=ieee
|
||||
;;
|
||||
esac
|
||||
|
||||
files="ho-${host}.h tc-${cpu_type}.c tc-${cpu_type}.h te-generic.h obj-${obj_format}.h obj-${obj_format}.c atof-${atof}.c"
|
||||
links="host.h targ-cpu.c targ-cpu.h targ-env.h obj-format.h obj-format.c atof-targ.c"
|
79
gas/debug.c
Normal file
79
gas/debug.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* Routines for debug use only. Don't link into product.
|
||||
*/
|
||||
|
||||
#include "as.h"
|
||||
#include "subsegs.h"
|
||||
|
||||
dmp_frags()
|
||||
{
|
||||
frchainS *chp;
|
||||
char *p;
|
||||
|
||||
for ( chp=frchain_root; chp; chp = chp->frch_next ){
|
||||
switch ( chp->frch_seg ){
|
||||
case SEG_DATA:
|
||||
p ="Data";
|
||||
break;
|
||||
case SEG_TEXT:
|
||||
p ="Text";
|
||||
break;
|
||||
default:
|
||||
p ="???";
|
||||
break;
|
||||
}
|
||||
printf("\nSEGMENT %s %d\n", p, chp->frch_subseg);
|
||||
dmp_frag( chp->frch_root,"\t");
|
||||
}
|
||||
}
|
||||
|
||||
dmp_frag( fp, indent )
|
||||
struct frag *fp;
|
||||
char *indent;
|
||||
{
|
||||
for ( ; fp; fp = fp->fr_next ){
|
||||
printf("%sFRAGMENT @ 0x%x\n", indent, fp);
|
||||
switch( fp->fr_type ){
|
||||
case rs_align:
|
||||
printf("%srs_align(%d)\n",indent, fp->fr_offset);
|
||||
break;
|
||||
case rs_fill:
|
||||
printf("%srs_fill(%d)\n",indent, fp->fr_offset);
|
||||
printf("%s", indent);
|
||||
var_chars( fp, fp->fr_var + fp->fr_fix );
|
||||
printf("%s\t repeated %d times,",
|
||||
indent, fp->fr_offset);
|
||||
printf(" fixed length if # chars == 0)\n");
|
||||
break;
|
||||
case rs_org:
|
||||
printf("%srs_org(%d+sym @0x%x)\n",indent,
|
||||
fp->fr_offset, fp->fr_symbol);
|
||||
printf("%sfill with ",indent);
|
||||
var_chars( fp, 1 );
|
||||
printf("\n");
|
||||
break;
|
||||
case rs_machine_dependent:
|
||||
printf("%smachine_dep\n",indent);
|
||||
break;
|
||||
default:
|
||||
printf("%sunknown type\n",indent);
|
||||
break;
|
||||
}
|
||||
printf("%saddr=%d(0x%x)\n",indent,fp->fr_address,fp->fr_address);
|
||||
printf("%sfr_fix=%d\n",indent,fp->fr_fix);
|
||||
printf("%sfr_var=%d\n",indent,fp->fr_var);
|
||||
printf("%sfr_offset=%d\n",indent,fp->fr_offset);
|
||||
printf("%schars @ 0x%x\n",indent,fp->fr_literal);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
var_chars( fp, n )
|
||||
struct frag *fp;
|
||||
int n;
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
for ( p=(unsigned char*)fp->fr_literal; n; n-- , p++ ){
|
||||
printf("%02x ", *p );
|
||||
}
|
||||
}
|
3227
gas/doc/as.texinfo
Normal file
3227
gas/doc/as.texinfo
Normal file
File diff suppressed because it is too large
Load diff
966
gas/expr.c
Normal file
966
gas/expr.c
Normal file
|
@ -0,0 +1,966 @@
|
|||
/* expr.c -operands, expressions-
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
/*
|
||||
* 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 <string.h>
|
||||
|
||||
#include "as.h"
|
||||
|
||||
#include "obstack.h"
|
||||
|
||||
#ifdef __STDC__
|
||||
static void clean_up_expression(expressionS *expressionP);
|
||||
#else /* __STDC__ */
|
||||
static void clean_up_expression(); /* Internal. */
|
||||
#endif /* __STDC__ */
|
||||
extern const char EXP_CHARS[]; /* JF hide MD floating pt stuff all the same place */
|
||||
extern const char FLT_CHARS[];
|
||||
|
||||
#ifdef LOCAL_LABELS_DOLLAR
|
||||
extern int local_label_defined[];
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Build any floating-point literal here.
|
||||
* Also build any bignum literal here.
|
||||
*/
|
||||
|
||||
/* LITTLENUM_TYPE generic_buffer [6]; */ /* JF this is a hack */
|
||||
/* Seems atof_machine can backscan through generic_bignum and hit whatever
|
||||
happens to be loaded before it in memory. And its way too complicated
|
||||
for me to fix right. Thus a hack. JF: Just make generic_bignum bigger,
|
||||
and never write into the early words, thus they'll always be zero.
|
||||
I hate Dean's floating-point code. Bleh.
|
||||
*/
|
||||
LITTLENUM_TYPE generic_bignum [SIZE_OF_LARGE_NUMBER+6];
|
||||
FLONUM_TYPE generic_floating_point_number =
|
||||
{
|
||||
& generic_bignum [6], /* low (JF: Was 0) */
|
||||
& generic_bignum [SIZE_OF_LARGE_NUMBER+6 - 1], /* high JF: (added +6) */
|
||||
0, /* leader */
|
||||
0, /* exponent */
|
||||
0 /* sign */
|
||||
};
|
||||
/* If nonzero, we've been asked to assemble nan, +inf or -inf */
|
||||
int generic_floating_point_magic;
|
||||
|
||||
/*
|
||||
* Summary of operand().
|
||||
*
|
||||
* in: Input_line_pointer points to 1st char of operand, which may
|
||||
* be a space.
|
||||
*
|
||||
* out: A expressionS. X_seg determines how to understand the rest of the
|
||||
* expressionS.
|
||||
* The operand may have been empty: in this case X_seg == SEG_ABSENT.
|
||||
* Input_line_pointer->(next non-blank) char after operand.
|
||||
*
|
||||
*/
|
||||
|
||||
static segT
|
||||
operand (expressionP)
|
||||
register expressionS * expressionP;
|
||||
{
|
||||
register char c;
|
||||
register char *name; /* points to name of symbol */
|
||||
register symbolS * symbolP; /* Points to symbol */
|
||||
|
||||
extern char hex_value[]; /* In hex_value.c */
|
||||
|
||||
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; /* 2, 8, 10 or 16 */
|
||||
/* 0 means we saw start of a floating- */
|
||||
/* point constant. */
|
||||
register short int maxdig = 0;/* Highest permitted digit value. */
|
||||
register int too_many_digits = 0; /* If we see >= this number of */
|
||||
/* digits, assume it is a bignum. */
|
||||
register char * digit_2; /*->2nd digit of number. */
|
||||
int small; /* TRUE if fits in 32 bits. */
|
||||
|
||||
if (c == '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 */
|
||||
/* likewise for the b's. xoxorich. */
|
||||
if ((c == 'f' || c == 'b' || c == 'B')
|
||||
&& (!*input_line_pointer ||
|
||||
(!strchr("+-.0123456789",*input_line_pointer) &&
|
||||
!strchr(EXP_CHARS,*input_line_pointer)))) {
|
||||
maxdig = radix = 10;
|
||||
too_many_digits = 11;
|
||||
c = '0';
|
||||
input_line_pointer -= 2;
|
||||
|
||||
} else if (c == 'b' || c == 'B') {
|
||||
c = *input_line_pointer++;
|
||||
maxdig = radix = 2;
|
||||
too_many_digits = 33;
|
||||
|
||||
} else if (c && strchr(FLT_CHARS,c)) {
|
||||
radix = 0; /* Start of floating-point constant. */
|
||||
/* input_line_pointer->1st char of number. */
|
||||
expressionP->X_add_number = -(isupper(c) ? tolower(c) : c);
|
||||
|
||||
} else { /* By elimination, assume octal radix. */
|
||||
radix = maxdig = 8;
|
||||
too_many_digits = 11;
|
||||
}
|
||||
} /* c == char after "0" or "0x" or "0X" or "0e" etc. */
|
||||
} else {
|
||||
maxdig = radix = 10;
|
||||
too_many_digits = 11;
|
||||
} /* if operand starts with a zero */
|
||||
|
||||
if (radix) { /* Fixed-point integer constant. */
|
||||
/* May be bignum, or may fit in 32 bits. */
|
||||
/*
|
||||
* Most numbers fit into 32 bits, and we want this case to be fast.
|
||||
* So we pretend it will fit into 32 bits. If, after making up a 32
|
||||
* bit number, we realise that we have scanned more digits than
|
||||
* comfortably fit into 32 bits, we re-scan the digits coding
|
||||
* them into a bignum. For decimal and octal numbers we are conservative: some
|
||||
* numbers may be assumed bignums when in fact they do fit into 32 bits.
|
||||
* Numbers of any radix can have excess leading zeros: we strive
|
||||
* to recognise this and cast them back into 32 bits.
|
||||
* We must check that the bignum really is more than 32
|
||||
* bits, and change it back to a 32-bit number if it fits.
|
||||
* The number we are looking for is expected to be positive, but
|
||||
* if it fits into 32 bits as an unsigned number, we let it be a 32-bit
|
||||
* number. The cavalier approach is for speed in ordinary cases.
|
||||
*/
|
||||
digit_2 = input_line_pointer;
|
||||
for (number=0; (digit=hex_value[c])<maxdig; c = * input_line_pointer ++)
|
||||
{
|
||||
number = number * radix + digit;
|
||||
}
|
||||
/* C contains character after number. */
|
||||
/* Input_line_pointer->char after C. */
|
||||
small = input_line_pointer - digit_2 < too_many_digits;
|
||||
if (! small)
|
||||
{
|
||||
/*
|
||||
* We saw a lot of digits. Manufacture a bignum the hard way.
|
||||
*/
|
||||
LITTLENUM_TYPE * leader; /*->high order littlenum of the bignum. */
|
||||
LITTLENUM_TYPE * pointer; /*->littlenum we are frobbing now. */
|
||||
long carry;
|
||||
|
||||
leader = generic_bignum;
|
||||
generic_bignum [0] = 0;
|
||||
generic_bignum [1] = 0;
|
||||
/* We could just use digit_2, but lets be mnemonic. */
|
||||
input_line_pointer = -- digit_2; /*->1st digit. */
|
||||
c = *input_line_pointer ++;
|
||||
for (; (carry = hex_value [c]) < maxdig; c = * input_line_pointer ++)
|
||||
{
|
||||
for (pointer = generic_bignum;
|
||||
pointer <= leader;
|
||||
pointer ++)
|
||||
{
|
||||
long work;
|
||||
|
||||
work = carry + radix * * pointer;
|
||||
* pointer = work & LITTLENUM_MASK;
|
||||
carry = work >> LITTLENUM_NUMBER_OF_BITS;
|
||||
}
|
||||
if (carry)
|
||||
{
|
||||
if (leader < generic_bignum + SIZE_OF_LARGE_NUMBER - 1)
|
||||
{ /* Room to grow a longer bignum. */
|
||||
* ++ leader = carry;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Again, C is char after number, */
|
||||
/* input_line_pointer->after C. */
|
||||
know(sizeof (int) * 8 == 32);
|
||||
know(LITTLENUM_NUMBER_OF_BITS == 16);
|
||||
/* Hence the constant "2" in the next line. */
|
||||
if (leader < generic_bignum + 2)
|
||||
{ /* Will fit into 32 bits. */
|
||||
number =
|
||||
((generic_bignum [1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS)
|
||||
| (generic_bignum [0] & LITTLENUM_MASK);
|
||||
small = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
number = leader - generic_bignum + 1; /* Number of littlenums in the bignum. */
|
||||
}
|
||||
}
|
||||
if (small)
|
||||
{
|
||||
/*
|
||||
* Here with number, in correct radix. c is the next char.
|
||||
* Note that unlike Un*x, we allow "011f" "0x9f" to
|
||||
* both mean the same as the (conventional) "9f". This is simply easier
|
||||
* than checking for strict canonical form. Syntax sux!
|
||||
*/
|
||||
if (number<10)
|
||||
{
|
||||
if (0
|
||||
#ifdef LOCAL_LABELS_FB
|
||||
|| c=='b'
|
||||
#endif
|
||||
#ifdef LOCAL_LABELS_DOLLAR
|
||||
|| (c=='$' && local_label_defined[number])
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/*
|
||||
* Backward ref to local label.
|
||||
* Because it is backward, expect it to be DEFINED.
|
||||
*/
|
||||
/*
|
||||
* Construct a local label.
|
||||
*/
|
||||
name = local_label_name ((int)number, 0);
|
||||
if (((symbolP = symbol_find(name)) != NULL) /* seen before */
|
||||
&& (S_IS_DEFINED(symbolP))) /* symbol is defined: OK */
|
||||
{ /* Expected path: symbol defined. */
|
||||
/* Local labels are never absolute. Don't waste time checking absoluteness. */
|
||||
know((S_GET_SEGMENT(symbolP) == SEG_DATA) || (S_GET_SEGMENT(symbolP) == SEG_TEXT));
|
||||
expressionP->X_add_symbol = symbolP;
|
||||
expressionP->X_add_number = 0;
|
||||
expressionP->X_seg = S_GET_SEGMENT(symbolP);
|
||||
}
|
||||
else
|
||||
{ /* Either not seen or not defined. */
|
||||
as_bad("Backw. ref to unknown label \"%d:\", 0 assumed.",
|
||||
number);
|
||||
expressionP->X_add_number = 0;
|
||||
expressionP->X_seg = SEG_ABSOLUTE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0
|
||||
#ifdef LOCAL_LABELS_FB
|
||||
|| c == 'f'
|
||||
#endif
|
||||
#ifdef LOCAL_LABELS_DOLLAR
|
||||
|| (c=='$' && !local_label_defined[number])
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/*
|
||||
* Forward reference. Expect symbol to be undefined or
|
||||
* unknown. Undefined: seen it before. Unknown: never seen
|
||||
* it in this pass.
|
||||
* Construct a local label name, then an undefined symbol.
|
||||
* Don't create a XSEG frag for it: caller may do that.
|
||||
* Just return it as never seen before.
|
||||
*/
|
||||
name = local_label_name((int)number, 1);
|
||||
symbolP = symbol_find_or_make(name);
|
||||
/* We have no need to check symbol properties. */
|
||||
know(S_GET_SEGMENT(symbolP) == SEG_UNKNOWN
|
||||
|| S_GET_SEGMENT(symbolP) == SEG_TEXT
|
||||
|| S_GET_SEGMENT(symbolP) == SEG_DATA);
|
||||
expressionP->X_add_symbol = symbolP;
|
||||
expressionP->X_seg = SEG_UNKNOWN;
|
||||
expressionP->X_subtract_symbol = NULL;
|
||||
expressionP->X_add_number = 0;
|
||||
}
|
||||
else
|
||||
{ /* Really a number, not a local label. */
|
||||
expressionP->X_add_number = number;
|
||||
expressionP->X_seg = SEG_ABSOLUTE;
|
||||
input_line_pointer --; /* Restore following character. */
|
||||
} /* if (c=='f') */
|
||||
} /* if (c=='b') */
|
||||
}
|
||||
else
|
||||
{ /* Really a number. */
|
||||
expressionP->X_add_number = number;
|
||||
expressionP->X_seg = SEG_ABSOLUTE;
|
||||
input_line_pointer --; /* Restore following character. */
|
||||
} /* if (number<10) */
|
||||
}
|
||||
else
|
||||
{
|
||||
expressionP->X_add_number = number;
|
||||
expressionP->X_seg = SEG_BIG;
|
||||
input_line_pointer --; /*->char following number. */
|
||||
} /* if (small) */
|
||||
} /* (If integer constant) */
|
||||
else
|
||||
{ /* input_line_pointer->*/
|
||||
/* floating-point constant. */
|
||||
int error_code;
|
||||
|
||||
error_code = atof_generic
|
||||
(& input_line_pointer, ".", EXP_CHARS,
|
||||
& generic_floating_point_number);
|
||||
|
||||
if (error_code)
|
||||
{
|
||||
if (error_code == ERROR_EXPONENT_OVERFLOW)
|
||||
{
|
||||
as_bad("Bad floating-point constant: exponent overflow, probably assembling junk");
|
||||
}
|
||||
else
|
||||
{
|
||||
as_bad("Bad floating-point constant: unknown error code=%d.", error_code);
|
||||
}
|
||||
}
|
||||
expressionP->X_seg = SEG_BIG;
|
||||
/* input_line_pointer->just after constant, */
|
||||
/* which may point to whitespace. */
|
||||
know(expressionP->X_add_number < 0); /* < 0 means "floating point". */
|
||||
} /* if (not floating-point constant) */
|
||||
}
|
||||
else if(c=='.' && !is_part_of_name(*input_line_pointer)) {
|
||||
extern struct obstack frags;
|
||||
|
||||
/*
|
||||
JF: '.' is pseudo symbol with value of current location in current
|
||||
segment. . .
|
||||
*/
|
||||
symbolP = symbol_new("L0\001",
|
||||
now_seg,
|
||||
(valueT)(obstack_next_free(&frags)-frag_now->fr_literal),
|
||||
frag_now);
|
||||
|
||||
expressionP->X_add_number=0;
|
||||
expressionP->X_add_symbol=symbolP;
|
||||
expressionP->X_seg = now_seg;
|
||||
|
||||
} else if (is_name_beginner(c)) /* here if did not begin with a digit */
|
||||
{
|
||||
/*
|
||||
* Identifier begins here.
|
||||
* This is kludged for speed, so code is repeated.
|
||||
*/
|
||||
name = -- input_line_pointer;
|
||||
c = get_symbol_end();
|
||||
symbolP = symbol_find_or_make(name);
|
||||
/*
|
||||
* If we have an absolute symbol or a reg, then we know its value now.
|
||||
*/
|
||||
expressionP->X_seg = S_GET_SEGMENT(symbolP);
|
||||
switch (expressionP->X_seg)
|
||||
{
|
||||
case SEG_ABSOLUTE:
|
||||
case SEG_REGISTER:
|
||||
expressionP->X_add_number = S_GET_VALUE(symbolP);
|
||||
break;
|
||||
|
||||
default:
|
||||
expressionP->X_add_number = 0;
|
||||
expressionP->X_add_symbol = 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_bad("Missing ')' assumed");
|
||||
input_line_pointer --;
|
||||
}
|
||||
/* here with input_line_pointer->char after "(...)" */
|
||||
}
|
||||
else if (c == '~' || c == '-' || c == '+') {
|
||||
/* unary operator: hope for SEG_ABSOLUTE */
|
||||
switch (operand (expressionP)) {
|
||||
case SEG_ABSOLUTE:
|
||||
/* input_line_pointer->char after operand */
|
||||
if (c=='-') {
|
||||
expressionP->X_add_number = - expressionP->X_add_number;
|
||||
/*
|
||||
* Notice: '-' may overflow: no warning is given. This is compatible
|
||||
* with other people's assemblers. Sigh.
|
||||
*/
|
||||
} else if (c == '~') {
|
||||
expressionP->X_add_number = ~ expressionP->X_add_number;
|
||||
} else if (c != '+') {
|
||||
know(0);
|
||||
} /* switch on unary operator */
|
||||
break;
|
||||
|
||||
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_bad("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_ABSENT;
|
||||
input_line_pointer --;
|
||||
md_operand (expressionP);
|
||||
}
|
||||
/*
|
||||
* It is more 'efficient' to clean up the expressions when they are created.
|
||||
* Doing it here saves lines of code.
|
||||
*/
|
||||
clean_up_expression (expressionP);
|
||||
SKIP_WHITESPACE(); /*->1st char after operand. */
|
||||
know(* input_line_pointer != ' ');
|
||||
return (expressionP->X_seg);
|
||||
} /* operand() */
|
||||
|
||||
/* Internal. Simplify a struct expression for use by expr() */
|
||||
|
||||
/*
|
||||
* In: address of a expressionS.
|
||||
* The X_seg field of the expressionS may only take certain values.
|
||||
* Now, we permit SEG_PASS1 to make code smaller & faster.
|
||||
* Elsewise we waste time special-case testing. Sigh. Ditto SEG_ABSENT.
|
||||
* Out: expressionS may have been modified:
|
||||
* 'foo-foo' symbol references cancelled to 0,
|
||||
* which changes X_seg from SEG_DIFFERENCE to SEG_ABSOLUTE;
|
||||
* Unused fields zeroed to help expr().
|
||||
*/
|
||||
|
||||
static void
|
||||
clean_up_expression (expressionP)
|
||||
register expressionS * expressionP;
|
||||
{
|
||||
switch (expressionP->X_seg)
|
||||
{
|
||||
case SEG_ABSENT:
|
||||
case SEG_PASS1:
|
||||
expressionP->X_add_symbol = NULL;
|
||||
expressionP->X_subtract_symbol = NULL;
|
||||
expressionP->X_add_number = 0;
|
||||
break;
|
||||
|
||||
case SEG_BIG:
|
||||
case SEG_ABSOLUTE:
|
||||
expressionP->X_subtract_symbol = NULL;
|
||||
expressionP->X_add_symbol = NULL;
|
||||
break;
|
||||
|
||||
case SEG_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
|
||||
&& S_GET_VALUE(expressionP->X_subtract_symbol) == S_GET_VALUE(expressionP->X_add_symbol))) {
|
||||
expressionP->X_subtract_symbol = NULL;
|
||||
expressionP->X_add_symbol = NULL;
|
||||
expressionP->X_seg = SEG_ABSOLUTE;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEG_REGISTER:
|
||||
expressionP->X_add_symbol = NULL;
|
||||
expressionP->X_subtract_symbol = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
BAD_CASE (expressionP->X_seg);
|
||||
break;
|
||||
}
|
||||
} /* clean_up_expression() */
|
||||
|
||||
/*
|
||||
* expr_part ()
|
||||
*
|
||||
* Internal. Made a function because this code is used in 2 places.
|
||||
* Generate error or correct X_?????_symbol of expressionS.
|
||||
*/
|
||||
|
||||
/*
|
||||
* symbol_1 += symbol_2 ... well ... sort of.
|
||||
*/
|
||||
|
||||
static segT
|
||||
expr_part (symbol_1_PP, symbol_2_P)
|
||||
symbolS ** symbol_1_PP;
|
||||
symbolS * symbol_2_P;
|
||||
{
|
||||
segT return_value;
|
||||
|
||||
know((* symbol_1_PP) == NULL
|
||||
|| (S_GET_SEGMENT(*symbol_1_PP) == SEG_TEXT)
|
||||
|| (S_GET_SEGMENT(*symbol_1_PP) == SEG_DATA)
|
||||
|| (S_GET_SEGMENT(*symbol_1_PP) == SEG_BSS)
|
||||
|| (!S_IS_DEFINED(* symbol_1_PP)));
|
||||
know(symbol_2_P == NULL
|
||||
|| (S_GET_SEGMENT(symbol_2_P) == SEG_TEXT)
|
||||
|| (S_GET_SEGMENT(symbol_2_P) == SEG_DATA)
|
||||
|| (S_GET_SEGMENT(symbol_2_P) == SEG_BSS)
|
||||
|| (!S_IS_DEFINED(symbol_2_P)));
|
||||
if (* symbol_1_PP)
|
||||
{
|
||||
if (!S_IS_DEFINED(* symbol_1_PP))
|
||||
{
|
||||
if (symbol_2_P)
|
||||
{
|
||||
return_value = SEG_PASS1;
|
||||
* symbol_1_PP = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
know(!S_IS_DEFINED(* symbol_1_PP));
|
||||
return_value = SEG_UNKNOWN;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (symbol_2_P)
|
||||
{
|
||||
if (!S_IS_DEFINED(symbol_2_P))
|
||||
{
|
||||
* symbol_1_PP = NULL;
|
||||
return_value = SEG_PASS1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* {seg1} - {seg2} */
|
||||
as_bad("Expression too complex, 2 symbols forgotten: \"%s\" \"%s\"",
|
||||
S_GET_NAME(* symbol_1_PP), S_GET_NAME(symbol_2_P));
|
||||
* symbol_1_PP = NULL;
|
||||
return_value = SEG_ABSOLUTE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return_value = S_GET_SEGMENT(* symbol_1_PP);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* (* symbol_1_PP) == NULL */
|
||||
if (symbol_2_P)
|
||||
{
|
||||
* symbol_1_PP = symbol_2_P;
|
||||
return_value = S_GET_SEGMENT(symbol_2_P);
|
||||
}
|
||||
else
|
||||
{
|
||||
* symbol_1_PP = NULL;
|
||||
return_value = SEG_ABSOLUTE;
|
||||
}
|
||||
}
|
||||
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
|
||||
|| (S_GET_SEGMENT(* symbol_1_PP) == 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 * / % << >>
|
||||
*/
|
||||
static const operator_rankT
|
||||
op_rank [] = { 0, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1 };
|
||||
|
||||
/* Return resultP->X_seg. */
|
||||
segT expr(rank, resultP)
|
||||
register operator_rankT rank; /* Larger # is higher rank. */
|
||||
register expressionS *resultP; /* Deliver result here. */
|
||||
{
|
||||
expressionS right;
|
||||
register operatorT op_left;
|
||||
register char c_left; /* 1st operator character. */
|
||||
register operatorT op_right;
|
||||
register char c_right;
|
||||
|
||||
know(rank >= 0);
|
||||
(void)operand (resultP);
|
||||
know(* input_line_pointer != ' '); /* Operand() gobbles spaces. */
|
||||
c_left = * input_line_pointer; /* Potential operator character. */
|
||||
op_left = op_encoding [c_left];
|
||||
while (op_left != O_illegal && op_rank [(int) op_left] > rank)
|
||||
{
|
||||
input_line_pointer ++; /*->after 1st character of operator. */
|
||||
/* Operators "<<" and ">>" have 2 characters. */
|
||||
if (* input_line_pointer == c_left && (c_left == '<' || c_left == '>'))
|
||||
{
|
||||
input_line_pointer ++;
|
||||
} /*->after operator. */
|
||||
if (SEG_ABSENT == expr (op_rank[(int) op_left], &right))
|
||||
{
|
||||
as_warn("Missing operand value assumed absolute 0.");
|
||||
resultP->X_add_number = 0;
|
||||
resultP->X_subtract_symbol = NULL;
|
||||
resultP->X_add_symbol = NULL;
|
||||
resultP->X_seg = SEG_ABSOLUTE;
|
||||
}
|
||||
know(* input_line_pointer != ' ');
|
||||
c_right = * input_line_pointer;
|
||||
op_right = op_encoding [c_right];
|
||||
if (* input_line_pointer == c_right && (c_right == '<' || c_right == '>'))
|
||||
{
|
||||
input_line_pointer ++;
|
||||
} /*->after operator. */
|
||||
know((int) op_right == 0
|
||||
|| op_rank [(int) op_right] <= op_rank[(int) op_left]);
|
||||
/* input_line_pointer->after right-hand quantity. */
|
||||
/* left-hand quantity in resultP */
|
||||
/* right-hand quantity in right. */
|
||||
/* operator in op_left. */
|
||||
if (resultP->X_seg == SEG_PASS1 || right . X_seg == SEG_PASS1)
|
||||
{
|
||||
resultP->X_seg = SEG_PASS1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (resultP->X_seg == SEG_BIG)
|
||||
{
|
||||
as_warn("Left operand of %c is a %s. Integer 0 assumed.",
|
||||
c_left, resultP->X_add_number > 0 ? "bignum" : "float");
|
||||
resultP->X_seg = SEG_ABSOLUTE;
|
||||
resultP->X_add_symbol = 0;
|
||||
resultP->X_subtract_symbol = 0;
|
||||
resultP->X_add_number = 0;
|
||||
}
|
||||
if (right . X_seg == SEG_BIG)
|
||||
{
|
||||
as_warn("Right operand of %c is a %s. Integer 0 assumed.",
|
||||
c_left, right . X_add_number > 0 ? "bignum" : "float");
|
||||
right . X_seg = SEG_ABSOLUTE;
|
||||
right . X_add_symbol = 0;
|
||||
right . X_subtract_symbol = 0;
|
||||
right . X_add_number = 0;
|
||||
}
|
||||
if (op_left == O_subtract)
|
||||
{
|
||||
/*
|
||||
* Convert - into + by exchanging symbols and negating number.
|
||||
* I know -infinity can't be negated in 2's complement:
|
||||
* but then it can't be subtracted either. This trick
|
||||
* does not cause any further inaccuracy.
|
||||
*/
|
||||
|
||||
register symbolS * symbolP;
|
||||
|
||||
right . X_add_number = - right . X_add_number;
|
||||
symbolP = right . X_add_symbol;
|
||||
right . X_add_symbol = right . X_subtract_symbol;
|
||||
right . X_subtract_symbol = symbolP;
|
||||
if (symbolP)
|
||||
{
|
||||
right . X_seg = SEG_DIFFERENCE;
|
||||
}
|
||||
op_left = O_add;
|
||||
}
|
||||
|
||||
if (op_left == O_add)
|
||||
{
|
||||
segT seg1;
|
||||
segT seg2;
|
||||
|
||||
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 = 1;
|
||||
resultP->X_seg = SEG_PASS1;
|
||||
} else if (seg2 == SEG_ABSOLUTE)
|
||||
resultP->X_seg = seg1;
|
||||
else if (seg1 != SEG_UNKNOWN
|
||||
&& seg1 != SEG_ABSOLUTE
|
||||
&& seg2 != SEG_UNKNOWN
|
||||
&& seg1 != seg2) {
|
||||
know(seg2 != SEG_ABSOLUTE);
|
||||
know(resultP->X_subtract_symbol);
|
||||
|
||||
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_bad("Expression too complex: forgetting %s - %s",
|
||||
S_GET_NAME(resultP->X_add_symbol),
|
||||
S_GET_NAME(resultP->X_subtract_symbol));
|
||||
resultP->X_seg = SEG_ABSOLUTE;
|
||||
/* Clean_up_expression() will do the rest. */
|
||||
} else
|
||||
resultP->X_seg = SEG_DIFFERENCE;
|
||||
|
||||
resultP->X_add_number += right . X_add_number;
|
||||
clean_up_expression (resultP);
|
||||
}
|
||||
else
|
||||
{ /* Not +. */
|
||||
if (resultP->X_seg == SEG_UNKNOWN || right . X_seg == SEG_UNKNOWN)
|
||||
{
|
||||
resultP->X_seg = SEG_PASS1;
|
||||
need_pass_2 = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
resultP->X_subtract_symbol = NULL;
|
||||
resultP->X_add_symbol = NULL;
|
||||
/* Will be SEG_ABSOLUTE. */
|
||||
if (resultP->X_seg != SEG_ABSOLUTE || right . X_seg != SEG_ABSOLUTE)
|
||||
{
|
||||
as_bad("Relocation error. Absolute 0 assumed.");
|
||||
resultP->X_seg = SEG_ABSOLUTE;
|
||||
resultP->X_add_number = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (op_left)
|
||||
{
|
||||
case O_bit_inclusive_or:
|
||||
resultP->X_add_number |= right . X_add_number;
|
||||
break;
|
||||
|
||||
case O_modulus:
|
||||
if (right . X_add_number)
|
||||
{
|
||||
resultP->X_add_number %= right . X_add_number;
|
||||
}
|
||||
else
|
||||
{
|
||||
as_warn("Division by 0. 0 assumed.");
|
||||
resultP->X_add_number = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case O_bit_and:
|
||||
resultP->X_add_number &= right . X_add_number;
|
||||
break;
|
||||
|
||||
case O_multiply:
|
||||
resultP->X_add_number *= right . X_add_number;
|
||||
break;
|
||||
|
||||
case O_divide:
|
||||
if (right . X_add_number)
|
||||
{
|
||||
resultP->X_add_number /= right . X_add_number;
|
||||
}
|
||||
else
|
||||
{
|
||||
as_warn("Division by 0. 0 assumed.");
|
||||
resultP->X_add_number = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case O_left_shift:
|
||||
resultP->X_add_number <<= right . X_add_number;
|
||||
break;
|
||||
|
||||
case O_right_shift:
|
||||
resultP->X_add_number >>= right . X_add_number;
|
||||
break;
|
||||
|
||||
case O_bit_exclusive_or:
|
||||
resultP->X_add_number ^= right . X_add_number;
|
||||
break;
|
||||
|
||||
case O_bit_or_not:
|
||||
resultP->X_add_number |= ~ right . X_add_number;
|
||||
break;
|
||||
|
||||
default:
|
||||
BAD_CASE(op_left);
|
||||
break;
|
||||
} /* switch(operator) */
|
||||
}
|
||||
} /* If we have to force need_pass_2. */
|
||||
} /* If operator was +. */
|
||||
} /* If we didn't set need_pass_2. */
|
||||
op_left = op_right;
|
||||
} /* While next operator is >= this rank. */
|
||||
return (resultP->X_seg);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end: expr.c */
|
79
gas/expr.h
Normal file
79
gas/expr.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* 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 X_add_number; /* 42. Must be signed. */
|
||||
segT X_seg; /* What segment (expr type)? */
|
||||
}
|
||||
expressionS;
|
||||
|
||||
/* result should be type (expressionS *). */
|
||||
#define expression(result) expr(0,result)
|
||||
|
||||
/* If an expression is SEG_BIG, look here */
|
||||
/* for its value. These common data may */
|
||||
/* be clobbered whenever expr() is called. */
|
||||
extern FLONUM_TYPE generic_floating_point_number; /* Flonums returned here. */
|
||||
/* Enough to hold most precise flonum. */
|
||||
extern LITTLENUM_TYPE generic_bignum []; /* Bignums returned here. */
|
||||
#define SIZE_OF_LARGE_NUMBER (20) /* Number of littlenums in above. */
|
||||
|
||||
typedef char operator_rankT;
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
char get_symbol_end(void);
|
||||
segT expr(int rank, expressionS *resultP);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
char get_symbol_end();
|
||||
segT expr();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
/* end: expr.h */
|
79
gas/flonum-copy.c
Normal file
79
gas/flonum-copy.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* flonum_copy.c - copy a flonum
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
#include "as.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 */
|
201
gas/flonum-mult.c
Normal file
201
gas/flonum-mult.c
Normal file
|
@ -0,0 +1,201 @@
|
|||
/* flonum_multip.c - multiply two flonums
|
||||
Copyright (C) 1987, 1990, 1991 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. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
#include "flonum.h"
|
||||
|
||||
/* plan for a . b => p(roduct)
|
||||
|
||||
|
||||
+-------+-------+-/ /-+-------+-------+
|
||||
| a | a | ... | a | a |
|
||||
| A | A-1 | | 1 | 0 |
|
||||
+-------+-------+-/ /-+-------+-------+
|
||||
|
||||
|
||||
+-------+-------+-/ /-+-------+-------+
|
||||
| b | b | ... | b | b |
|
||||
| B | B-1 | | 1 | 0 |
|
||||
+-------+-------+-/ /-+-------+-------+
|
||||
|
||||
|
||||
+-------+-------+-/ /-+-------+-/ /-+-------+-------+
|
||||
| p | p | ... | p | ... | p | p |
|
||||
| A+B+1| A+B | | N | | 1 | 0 |
|
||||
+-------+-------+-/ /-+-------+-/ /-+-------+-------+
|
||||
|
||||
/^\
|
||||
(carry) a .b ... | ... a .b a .b
|
||||
A B | 0 1 0 0
|
||||
|
|
||||
... | ... a .b
|
||||
| 1 0
|
||||
|
|
||||
| ...
|
||||
|
|
||||
|
|
||||
|
|
||||
| ___
|
||||
| \
|
||||
+----- P = > a .b
|
||||
N /__ i j
|
||||
|
||||
N = 0 ... A+B
|
||||
|
||||
for all i,j where i+j=N
|
||||
[i,j integers > 0]
|
||||
|
||||
a[], b[], p[] may not intersect.
|
||||
Zero length factors signify 0 significant bits: treat as 0.0.
|
||||
0.0 factors do the right thing.
|
||||
Zero length product OK.
|
||||
|
||||
I chose the ForTran accent "foo[bar]" instead of the C accent "*garply"
|
||||
because I felt the ForTran way was more intuitive. The C way would
|
||||
probably yield better code on most C compilers. Dean Elsner.
|
||||
(C style also gives deeper insight [to me] ... oh well ...)
|
||||
*/
|
||||
|
||||
void flonum_multip (a, b, product)
|
||||
const FLONUM_TYPE *a;
|
||||
const FLONUM_TYPE *b;
|
||||
FLONUM_TYPE *product;
|
||||
{
|
||||
int size_of_a; /* 0 origin */
|
||||
int size_of_b; /* 0 origin */
|
||||
int size_of_product; /* 0 origin */
|
||||
int size_of_sum; /* 0 origin */
|
||||
int extra_product_positions;/* 1 origin */
|
||||
unsigned long work;
|
||||
unsigned long carry;
|
||||
long exponent;
|
||||
LITTLENUM_TYPE * q;
|
||||
long significant; /* TRUE when we emit a non-0 littlenum */
|
||||
/* ForTran accent follows. */
|
||||
int P; /* Scan product low-order -> high. */
|
||||
int N; /* As in sum above. */
|
||||
int A; /* Which [] of a? */
|
||||
int B; /* Which [] of b? */
|
||||
|
||||
if((a->sign!='-' && a->sign!='+') || (b->sign!='-' && b->sign!='+')) {
|
||||
/* ...
|
||||
Got to fail somehow. Any suggestions? */
|
||||
product->sign=0;
|
||||
return;
|
||||
}
|
||||
product -> sign = (a->sign == b->sign) ? '+' : '-';
|
||||
size_of_a = a -> leader - a -> low;
|
||||
size_of_b = b -> leader - b -> low;
|
||||
exponent = a -> exponent + b -> exponent;
|
||||
size_of_product = product -> high - product -> low;
|
||||
size_of_sum = size_of_a + size_of_b;
|
||||
extra_product_positions = size_of_product - size_of_sum;
|
||||
if (extra_product_positions < 0)
|
||||
{
|
||||
P = extra_product_positions; /* P < 0 */
|
||||
exponent -= extra_product_positions; /* Increases exponent. */
|
||||
}
|
||||
else
|
||||
{
|
||||
P = 0;
|
||||
}
|
||||
carry = 0;
|
||||
significant = 0;
|
||||
for (N = 0;
|
||||
N <= size_of_sum;
|
||||
N++)
|
||||
{
|
||||
work = carry;
|
||||
carry = 0;
|
||||
for (A = 0;
|
||||
A <= N;
|
||||
A ++)
|
||||
{
|
||||
B = N - A;
|
||||
if (A <= size_of_a && B <= size_of_b && B >= 0)
|
||||
{
|
||||
#ifdef TRACE
|
||||
printf("a:low[%d.]=%04x b:low[%d.]=%04x work_before=%08x\n", A, a->low[A], B, b->low[B], work);
|
||||
#endif
|
||||
work += a -> low [A] * b -> low [B];
|
||||
carry += work >> LITTLENUM_NUMBER_OF_BITS;
|
||||
work &= LITTLENUM_MASK;
|
||||
#ifdef TRACE
|
||||
printf("work=%08x carry=%04x\n", work, carry);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
significant |= work;
|
||||
if (significant || P<0)
|
||||
{
|
||||
if (P >= 0)
|
||||
{
|
||||
product -> low [P] = work;
|
||||
#ifdef TRACE
|
||||
printf("P=%d. work[p]:=%04x\n", P, work);
|
||||
#endif
|
||||
}
|
||||
P ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
extra_product_positions ++;
|
||||
exponent ++;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* [P]-> position # size_of_sum + 1.
|
||||
* This is where 'carry' should go.
|
||||
*/
|
||||
#ifdef TRACE
|
||||
printf("final carry =%04x\n", carry);
|
||||
#endif
|
||||
if (carry)
|
||||
{
|
||||
if (extra_product_positions > 0)
|
||||
{
|
||||
product -> low [P] = carry;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No room at high order for carry littlenum. */
|
||||
/* Shift right 1 to make room for most significant littlenum. */
|
||||
exponent ++;
|
||||
P --;
|
||||
for (q = product -> low + P;
|
||||
q >= product -> low;
|
||||
q --)
|
||||
{
|
||||
work = * q;
|
||||
* q = carry;
|
||||
carry = work;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
P --;
|
||||
}
|
||||
product -> leader = product -> low + P;
|
||||
product -> exponent = exponent;
|
||||
}
|
||||
|
||||
/* end: flonum_multip.c */
|
122
gas/flonum.h
Normal file
122
gas/flonum.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
/* flonum.h - Floating point package
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/***********************************************************************\
|
||||
* *
|
||||
* 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 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. *
|
||||
* *
|
||||
\***********************************************************************/
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
int atof_generic(char **address_of_string_pointer,
|
||||
const char *string_of_decimal_marks,
|
||||
const char *string_of_decimal_exponent_marks,
|
||||
FLONUM_TYPE *address_of_generic_floating_point_number);
|
||||
|
||||
void flonum_copy(FLONUM_TYPE *in, FLONUM_TYPE *out);
|
||||
void flonum_multip(const FLONUM_TYPE *a, const FLONUM_TYPE *b, FLONUM_TYPE *product);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
int atof_generic();
|
||||
void flonum_copy();
|
||||
void flonum_multip();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
/***********************************************************************\
|
||||
* *
|
||||
* Declare error codes. *
|
||||
* *
|
||||
\***********************************************************************/
|
||||
|
||||
#define ERROR_EXPONENT_OVERFLOW (2)
|
||||
|
||||
/* end: flonum.h */
|
285
gas/frags.c
Normal file
285
gas/frags.c
Normal file
|
@ -0,0 +1,285 @@
|
|||
/* frags.c - manage frags -
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
#include "as.h"
|
||||
#include "subsegs.h"
|
||||
#include "obstack.h"
|
||||
|
||||
struct obstack frags; /* All, and only, frags live here. */
|
||||
|
||||
fragS zero_address_frag = {
|
||||
0, /* fr_address */
|
||||
NULL, /* fr_next */
|
||||
0, /* fr_fix */
|
||||
0, /* fr_var */
|
||||
0, /* fr_symbol */
|
||||
0, /* fr_offset */
|
||||
NULL, /* fr_opcode */
|
||||
rs_fill, /* fr_type */
|
||||
0, /* fr_subtype */
|
||||
0, /* fr_pcrel_adjust */
|
||||
0, /* fr_bsr */
|
||||
0 /* fr_literal [0] */
|
||||
};
|
||||
|
||||
fragS bss_address_frag = {
|
||||
0, /* fr_address. Gets filled in to make up
|
||||
sy_value-s. */
|
||||
NULL, /* fr_next */
|
||||
0, /* fr_fix */
|
||||
0, /* fr_var */
|
||||
0, /* fr_symbol */
|
||||
0, /* fr_offset */
|
||||
NULL, /* fr_opcode */
|
||||
rs_fill, /* fr_type */
|
||||
0, /* fr_subtype */
|
||||
0, /* fr_pcrel_adjust */
|
||||
0, /* fr_bsr */
|
||||
0 /* fr_literal [0] */
|
||||
};
|
||||
|
||||
/*
|
||||
* frag_grow()
|
||||
*
|
||||
* Internal.
|
||||
* Try to augment current frag by nchars chars.
|
||||
* If there is no room, close of the current frag with a ".fill 0"
|
||||
* and begin a new frag. Unless the new frag has nchars chars available
|
||||
* do not return. Do not set up any fields of *now_frag.
|
||||
*/
|
||||
static void frag_grow(nchars)
|
||||
unsigned int nchars;
|
||||
{
|
||||
if (obstack_room (&frags) < nchars) {
|
||||
unsigned int n,oldn;
|
||||
long oldc;
|
||||
|
||||
frag_wane(frag_now);
|
||||
frag_new(0);
|
||||
oldn=(unsigned)-1;
|
||||
oldc=frags.chunk_size;
|
||||
frags.chunk_size=2*nchars;
|
||||
while((n=obstack_room(&frags))<nchars && n<oldn) {
|
||||
frag_wane(frag_now);
|
||||
frag_new(0);
|
||||
oldn=n;
|
||||
}
|
||||
frags.chunk_size=oldc;
|
||||
}
|
||||
if (obstack_room (&frags) < nchars)
|
||||
as_fatal("Can't extend frag %d. chars", nchars);
|
||||
} /* frag_grow() */
|
||||
|
||||
/*
|
||||
* frag_new()
|
||||
*
|
||||
* Call this to close off a completed frag, and start up a new (empty)
|
||||
* frag, in the same subsegment as the old frag.
|
||||
* [frchain_now remains the same but frag_now is updated.]
|
||||
* Because this calculates the correct value of fr_fix by
|
||||
* looking at the obstack 'frags', it needs to know how many
|
||||
* characters at the end of the old frag belong to (the maximal)
|
||||
* fr_var: the rest must belong to fr_fix.
|
||||
* It doesn't actually set up the old frag's fr_var: you may have
|
||||
* set fr_var == 1, but allocated 10 chars to the end of the frag:
|
||||
* in this case you pass old_frags_var_max_size == 10.
|
||||
*
|
||||
* Make a new frag, initialising some components. Link new frag at end
|
||||
* of frchain_now.
|
||||
*/
|
||||
void frag_new(old_frags_var_max_size)
|
||||
int old_frags_var_max_size; /* Number of chars (already allocated on
|
||||
obstack frags) */
|
||||
/* in variable_length part of frag. */
|
||||
{
|
||||
register fragS * former_last_fragP;
|
||||
/* char *throw_away_pointer; JF unused */
|
||||
register frchainS * frchP;
|
||||
long tmp; /* JF */
|
||||
|
||||
frag_now->fr_fix = (char *) (obstack_next_free (&frags)) -
|
||||
(frag_now->fr_literal) - old_frags_var_max_size;
|
||||
/* Fix up old frag's fr_fix. */
|
||||
|
||||
obstack_finish (&frags);
|
||||
/* This will align the obstack so the */
|
||||
/* next struct we allocate on it will */
|
||||
/* begin at a correct boundary. */
|
||||
frchP = frchain_now;
|
||||
know (frchP);
|
||||
former_last_fragP = frchP->frch_last;
|
||||
know (former_last_fragP);
|
||||
know (former_last_fragP == frag_now);
|
||||
obstack_blank (&frags, SIZEOF_STRUCT_FRAG);
|
||||
/* We expect this will begin at a correct */
|
||||
/* boundary for a struct. */
|
||||
tmp=obstack_alignment_mask(&frags);
|
||||
obstack_alignment_mask(&frags)=0; /* Turn off alignment */
|
||||
/* If we ever hit a machine
|
||||
where strings must be
|
||||
aligned, we Lose Big */
|
||||
frag_now=(fragS *)obstack_finish(&frags);
|
||||
obstack_alignment_mask(&frags)=tmp; /* Restore alignment */
|
||||
|
||||
/* Just in case we don't get zero'd bytes */
|
||||
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 offset;
|
||||
char *opcode;
|
||||
{
|
||||
register char *retval;
|
||||
|
||||
frag_grow (max_chars);
|
||||
retval = obstack_next_free (&frags);
|
||||
obstack_blank_fast (&frags, max_chars);
|
||||
frag_now->fr_var = var;
|
||||
frag_now->fr_type = type;
|
||||
frag_now->fr_subtype = subtype;
|
||||
frag_now->fr_symbol = symbol;
|
||||
frag_now->fr_offset = offset;
|
||||
frag_now->fr_opcode = opcode;
|
||||
/* default these to zero. */
|
||||
frag_now->fr_pcrel_adjust = 0;
|
||||
frag_now->fr_bsr = 0;
|
||||
frag_new (max_chars);
|
||||
return (retval);
|
||||
} /* frag_var() */
|
||||
|
||||
/*
|
||||
* frag_variant()
|
||||
*
|
||||
* OVE: This variant of frag_var assumes that space for the tail has been
|
||||
* allocated by caller.
|
||||
* No call to frag_grow is done.
|
||||
* Two new arguments have been added.
|
||||
*/
|
||||
|
||||
char *frag_variant(type, max_chars, var, subtype, symbol, offset, opcode, pcrel_adjust,bsr)
|
||||
relax_stateT type;
|
||||
int max_chars;
|
||||
int var;
|
||||
relax_substateT subtype;
|
||||
symbolS *symbol;
|
||||
long offset;
|
||||
char *opcode;
|
||||
int pcrel_adjust;
|
||||
char bsr;
|
||||
{
|
||||
register char *retval;
|
||||
|
||||
/* frag_grow (max_chars); */
|
||||
retval = obstack_next_free (&frags);
|
||||
/* obstack_blank_fast (&frags, max_chars); */ /* OVE: so far the only diff */
|
||||
frag_now->fr_var = var;
|
||||
frag_now->fr_type = type;
|
||||
frag_now->fr_subtype = subtype;
|
||||
frag_now->fr_symbol = symbol;
|
||||
frag_now->fr_offset = offset;
|
||||
frag_now->fr_opcode = opcode;
|
||||
frag_now->fr_pcrel_adjust = pcrel_adjust;
|
||||
frag_now->fr_bsr = bsr;
|
||||
frag_new (max_chars);
|
||||
return (retval);
|
||||
} /* frag_variant() */
|
||||
|
||||
/*
|
||||
* frag_wane()
|
||||
*
|
||||
* Reduce the variable end of a frag to a harmless state.
|
||||
*/
|
||||
void frag_wane(fragP)
|
||||
register fragS * fragP;
|
||||
{
|
||||
fragP->fr_type = rs_fill;
|
||||
fragP->fr_offset = 0;
|
||||
fragP->fr_var = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* frag_align()
|
||||
*
|
||||
* Make a frag for ".align foo,bar". Call is "frag_align (foo,bar);".
|
||||
* Foo & bar are absolute integers.
|
||||
*
|
||||
* Call to close off the current frag with a ".align", then start a new
|
||||
* (so far empty) frag, in the same subsegment as the last frag.
|
||||
*/
|
||||
|
||||
void frag_align(alignment, fill_character)
|
||||
int alignment;
|
||||
int fill_character;
|
||||
{
|
||||
*(frag_var (rs_align, 1, 1, (relax_substateT)0, (symbolS *)0,
|
||||
(long)alignment, (char *)0)) = fill_character;
|
||||
} /* frag_align() */
|
||||
|
||||
/* end: frags.c */
|
84
gas/frags.h
Normal file
84
gas/frags.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/* 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 ); \
|
||||
}
|
||||
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
char *frag_more(int nchars);
|
||||
void frag_align(int alignment, int fill_character);
|
||||
void frag_new(int old_frags_var_max_size);
|
||||
void frag_wane(fragS *fragP);
|
||||
|
||||
char *frag_variant(relax_stateT type,
|
||||
int max_chars,
|
||||
int var,
|
||||
relax_substateT subtype,
|
||||
symbolS *symbol,
|
||||
long offset,
|
||||
char *opcode,
|
||||
int pcrel_adjust,
|
||||
int bsr);
|
||||
|
||||
char *frag_var(relax_stateT type,
|
||||
int max_chars,
|
||||
int var,
|
||||
relax_substateT subtype,
|
||||
symbolS *symbol,
|
||||
long offset,
|
||||
char *opcode);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
char *frag_more();
|
||||
char *frag_var();
|
||||
char *frag_variant();
|
||||
void frag_align();
|
||||
void frag_new();
|
||||
void frag_wane();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end: frags.h */
|
990
gas/hash.c
Normal file
990
gas/hash.c
Normal file
|
@ -0,0 +1,990 @@
|
|||
/* hash.c - hash table lookup strings -
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE (0)
|
||||
#define TRUE (!FALSE)
|
||||
#endif /* no FALSE yet */
|
||||
|
||||
#include <ctype.h>
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#include "as.h"
|
||||
|
||||
#define error as_fatal
|
||||
|
||||
#define DELETED ((char *)1) /* guarenteed invalid address */
|
||||
#define START_POWER (11) /* power of two: size of new hash table *//* JF was 6 */
|
||||
/* JF These next two aren't used any more. */
|
||||
/* #define START_SIZE (64) / * 2 ** START_POWER */
|
||||
/* #define START_FULL (32) / * number of entries before table expands */
|
||||
#define islive(ptr) (ptr->hash_string && ptr->hash_string!=DELETED)
|
||||
/* above TRUE if a symbol is in entry @ ptr */
|
||||
|
||||
#define STAT_SIZE (0) /* number of slots in hash table */
|
||||
/* the wall does not count here */
|
||||
/* we expect this is always a power of 2 */
|
||||
#define STAT_ACCESS (1) /* number of hash_ask()s */
|
||||
#define STAT__READ (0) /* reading */
|
||||
#define STAT__WRITE (1) /* writing */
|
||||
#define STAT_COLLIDE (3) /* number of collisions (total) */
|
||||
/* this may exceed STAT_ACCESS if we have */
|
||||
/* lots of collisions/access */
|
||||
#define STAT_USED (5) /* slots used right now */
|
||||
#define STATLENGTH (6) /* size of statistics block */
|
||||
#if STATLENGTH != HASH_STATLENGTH
|
||||
Panic! Please make #include "stat.h" agree with previous definitions!
|
||||
#endif
|
||||
|
||||
/* #define SUSPECT to do runtime checks */
|
||||
/* #define TEST to be a test jig for hash...() */
|
||||
|
||||
#ifdef TEST /* TEST: use smaller hash table */
|
||||
#undef START_POWER
|
||||
#define START_POWER (3)
|
||||
#undef START_SIZE
|
||||
#define START_SIZE (8)
|
||||
#undef START_FULL
|
||||
#define START_FULL (4)
|
||||
#endif
|
||||
|
||||
/*------------------ plan ---------------------------------- i = internal
|
||||
|
||||
struct hash_control * c;
|
||||
struct hash_entry * e; i
|
||||
int b[z]; buffer for statistics
|
||||
z size of b
|
||||
char * s; symbol string (address) [ key ]
|
||||
char * v; value string (address) [datum]
|
||||
boolean f; TRUE if we found s in hash table i
|
||||
char * t; error string; "" means OK
|
||||
int a; access type [0...n) i
|
||||
|
||||
c=hash_new () create new hash_control
|
||||
|
||||
hash_die (c) destroy hash_control (and hash table)
|
||||
table should be empty.
|
||||
doesn't check if table is empty.
|
||||
c has no meaning after this.
|
||||
|
||||
hash_say (c,b,z) report statistics of hash_control.
|
||||
also report number of available statistics.
|
||||
|
||||
v=hash_delete (c,s) delete symbol, return old value if any.
|
||||
ask() NULL means no old value.
|
||||
f
|
||||
|
||||
v=hash_replace (c,s,v) replace old value of s with v.
|
||||
ask() NULL means no old value: no table change.
|
||||
f
|
||||
|
||||
t=hash_insert (c,s,v) insert (s,v) in c.
|
||||
ask() return error string.
|
||||
f it is an error to insert if s is already
|
||||
in table.
|
||||
if any error, c is unchanged.
|
||||
|
||||
t=hash_jam (c,s,v) assert that new value of s will be v. i
|
||||
ask() it may decide to GROW the table. i
|
||||
f i
|
||||
grow() i
|
||||
t=hash_grow (c) grow the hash table. i
|
||||
jam() will invoke JAM. i
|
||||
|
||||
?=hash_apply (c,y) apply y() to every symbol in c.
|
||||
y evtries visited in 'unspecified' order.
|
||||
|
||||
v=hash_find (c,s) return value of s, or NULL if s not in c.
|
||||
ask()
|
||||
f
|
||||
|
||||
f,e=hash_ask() (c,s,a) return slot where s SHOULD live. i
|
||||
code() maintain collision stats in c. i
|
||||
|
||||
.=hash_code (c,s) compute hash-code for s, i
|
||||
from parameters of c. i
|
||||
|
||||
*/
|
||||
|
||||
static char hash_found; /* returned by hash_ask() to stop extra */
|
||||
/* testing. hash_ask() wants to return both */
|
||||
/* a slot and a status. This is the status. */
|
||||
/* TRUE: found symbol */
|
||||
/* FALSE: absent: empty or deleted slot */
|
||||
/* Also returned by hash_jam(). */
|
||||
/* TRUE: we replaced a value */
|
||||
/* FALSE: we inserted a value */
|
||||
|
||||
static struct hash_entry * hash_ask();
|
||||
static int hash_code ();
|
||||
static char * hash_grow();
|
||||
|
||||
/*
|
||||
* h a s h _ n e w ( )
|
||||
*
|
||||
*/
|
||||
struct hash_control *
|
||||
hash_new() /* create a new hash table */
|
||||
/* return NULL if failed */
|
||||
/* return handle (address of struct hash) */
|
||||
{
|
||||
register struct hash_control * retval;
|
||||
register struct hash_entry * room; /* points to hash table */
|
||||
register struct hash_entry * wall;
|
||||
register struct hash_entry * entry;
|
||||
register int * ip; /* scan stats block of struct hash_control */
|
||||
register int * nd; /* limit of stats block */
|
||||
|
||||
if (( room = (struct hash_entry *) malloc( sizeof(struct
|
||||
hash_entry)*((1<<START_POWER) + 1) ) ) != NULL)
|
||||
/* +1 for the wall entry */
|
||||
{
|
||||
if (( retval = (struct hash_control *) malloc(sizeof(struct
|
||||
hash_control)) ) != NULL)
|
||||
{
|
||||
nd = retval->hash_stat + STATLENGTH;
|
||||
for (ip=retval->hash_stat; ip<nd; ip++)
|
||||
{
|
||||
*ip = 0;
|
||||
}
|
||||
|
||||
retval -> hash_stat[STAT_SIZE] = 1<<START_POWER;
|
||||
retval -> hash_mask = (1<<START_POWER) - 1;
|
||||
retval -> hash_sizelog = START_POWER;
|
||||
/* works for 1's compl ok */
|
||||
retval -> hash_where = room;
|
||||
retval -> hash_wall =
|
||||
wall = room + (1<<START_POWER);
|
||||
retval -> hash_full = (1<<START_POWER)/2;
|
||||
for (entry=room; entry<=wall; entry++)
|
||||
{
|
||||
entry->hash_string = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = NULL; /* no room for table: fake a failure */
|
||||
}
|
||||
return(retval); /* return NULL or set-up structs */
|
||||
}
|
||||
|
||||
/*
|
||||
* h a s h _ d i e ( )
|
||||
*
|
||||
* Table should be empty, but this is not checked.
|
||||
* To empty the table, try hash_apply()ing a symbol deleter.
|
||||
* Return to free memory both the hash table and it's control
|
||||
* block.
|
||||
* 'handle' has no meaning after this function.
|
||||
* No errors are recoverable.
|
||||
*/
|
||||
void
|
||||
hash_die(handle)
|
||||
struct hash_control * handle;
|
||||
{
|
||||
free((char *)handle->hash_where);
|
||||
free((char *)handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* h a s h _ s a y ( )
|
||||
*
|
||||
* Return the size of the statistics table, and as many statistics as
|
||||
* we can until either (a) we have run out of statistics or (b) caller
|
||||
* has run out of buffer.
|
||||
* NOTE: hash_say treats all statistics alike.
|
||||
* These numbers may change with time, due to insertions, deletions
|
||||
* and expansions of the table.
|
||||
* The first "statistic" returned is the length of hash_stat[].
|
||||
* Then contents of hash_stat[] are read out (in ascending order)
|
||||
* until your buffer or hash_stat[] is exausted.
|
||||
*/
|
||||
void
|
||||
hash_say(handle,buffer,bufsiz)
|
||||
register struct hash_control * handle;
|
||||
register int buffer[/*bufsiz*/];
|
||||
register int bufsiz;
|
||||
{
|
||||
register int * nd; /* limit of statistics block */
|
||||
register int * ip; /* scan statistics */
|
||||
|
||||
ip = handle -> hash_stat;
|
||||
nd = ip + min(bufsiz-1,STATLENGTH);
|
||||
if (bufsiz>0) /* trust nothing! bufsiz<=0 is dangerous */
|
||||
{
|
||||
*buffer++ = STATLENGTH;
|
||||
for (; ip<nd; ip++,buffer++)
|
||||
{
|
||||
*buffer = *ip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* h a s h _ d e l e t e ( )
|
||||
*
|
||||
* Try to delete a symbol from the table.
|
||||
* If it was there, return its value (and adjust STAT_USED).
|
||||
* Otherwise, return NULL.
|
||||
* Anyway, the symbol is not present after this function.
|
||||
*
|
||||
*/
|
||||
char * /* NULL if string not in table, else */
|
||||
/* returns value of deleted symbol */
|
||||
hash_delete(handle,string)
|
||||
register struct hash_control * handle;
|
||||
register char * string;
|
||||
{
|
||||
register char * retval; /* NULL if string not in table */
|
||||
register struct hash_entry * entry; /* NULL or entry of this symbol */
|
||||
|
||||
entry = hash_ask(handle,string,STAT__WRITE);
|
||||
if (hash_found)
|
||||
{
|
||||
retval = entry -> hash_value;
|
||||
entry -> hash_string = DELETED; /* mark as deleted */
|
||||
handle -> hash_stat[STAT_USED] -= 1; /* slots-in-use count */
|
||||
#ifdef SUSPECT
|
||||
if (handle->hash_stat[STAT_USED]<0)
|
||||
{
|
||||
error("hash_delete");
|
||||
}
|
||||
#endif /* def SUSPECT */
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = NULL;
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* h a s h _ r e p l a c e ( )
|
||||
*
|
||||
* Try to replace the old value of a symbol with a new value.
|
||||
* Normally return the old value.
|
||||
* Return NULL and don't change the table if the symbol is not already
|
||||
* in the table.
|
||||
*/
|
||||
char *
|
||||
hash_replace(handle,string,value)
|
||||
register struct hash_control * handle;
|
||||
register char * string;
|
||||
register char * value;
|
||||
{
|
||||
register struct hash_entry * entry;
|
||||
register char * retval;
|
||||
|
||||
entry = hash_ask(handle,string,STAT__WRITE);
|
||||
if (hash_found)
|
||||
{
|
||||
retval = entry -> hash_value;
|
||||
entry -> hash_value = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = NULL;
|
||||
}
|
||||
;
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* h a s h _ i n s e r t ( )
|
||||
*
|
||||
* Insert a (symbol-string, value) into the hash table.
|
||||
* Return an error string, "" means OK.
|
||||
* It is an 'error' to insert an existing symbol.
|
||||
*/
|
||||
|
||||
char * /* return error string */
|
||||
hash_insert(handle,string,value)
|
||||
register struct hash_control * handle;
|
||||
register char * string;
|
||||
register char * value;
|
||||
{
|
||||
register struct hash_entry * entry;
|
||||
register char * retval;
|
||||
|
||||
retval = "";
|
||||
if (handle->hash_stat[STAT_USED] > handle->hash_full)
|
||||
{
|
||||
retval = hash_grow(handle);
|
||||
}
|
||||
if ( ! * retval)
|
||||
{
|
||||
entry = hash_ask(handle,string,STAT__WRITE);
|
||||
if (hash_found)
|
||||
{
|
||||
retval = "exists";
|
||||
}
|
||||
else
|
||||
{
|
||||
entry -> hash_value = value;
|
||||
entry -> hash_string = string;
|
||||
handle-> hash_stat[STAT_USED] += 1;
|
||||
}
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* h a s h _ j a m ( )
|
||||
*
|
||||
* Regardless of what was in the symbol table before, after hash_jam()
|
||||
* the named symbol has the given value. The symbol is either inserted or
|
||||
* (its value is) relpaced.
|
||||
* An error message string is returned, "" means OK.
|
||||
*
|
||||
* WARNING: this may decide to grow the hashed symbol table.
|
||||
* To do this, we call hash_grow(), WHICH WILL recursively CALL US.
|
||||
*
|
||||
* We report status internally: hash_found is TRUE if we replaced, but
|
||||
* false if we inserted.
|
||||
*/
|
||||
char *
|
||||
hash_jam(handle,string,value)
|
||||
register struct hash_control * handle;
|
||||
register char * string;
|
||||
register char * value;
|
||||
{
|
||||
register char * retval;
|
||||
register struct hash_entry * entry;
|
||||
|
||||
retval = "";
|
||||
if (handle->hash_stat[STAT_USED] > handle->hash_full)
|
||||
{
|
||||
retval = hash_grow(handle);
|
||||
}
|
||||
if (! * retval)
|
||||
{
|
||||
entry = hash_ask(handle,string,STAT__WRITE);
|
||||
if ( ! hash_found)
|
||||
{
|
||||
entry -> hash_string = string;
|
||||
handle->hash_stat[STAT_USED] += 1;
|
||||
}
|
||||
entry -> hash_value = value;
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* h a s h _ g r o w ( )
|
||||
*
|
||||
* Grow a new (bigger) hash table from the old one.
|
||||
* We choose to double the hash table's size.
|
||||
* Return a human-scrutible error string: "" if OK.
|
||||
* Warning! This uses hash_jam(), which had better not recurse
|
||||
* back here! Hash_jam() conditionally calls us, but we ALWAYS
|
||||
* call hash_jam()!
|
||||
* Internal.
|
||||
*/
|
||||
static char *
|
||||
hash_grow(handle) /* make a hash table grow */
|
||||
struct hash_control * handle;
|
||||
{
|
||||
register struct hash_entry * newwall;
|
||||
register struct hash_entry * newwhere;
|
||||
struct hash_entry * newtrack;
|
||||
register struct hash_entry * oldtrack;
|
||||
register struct hash_entry * oldwhere;
|
||||
register struct hash_entry * oldwall;
|
||||
register int temp;
|
||||
int newsize;
|
||||
char * string;
|
||||
char * retval;
|
||||
#ifdef SUSPECT
|
||||
int oldused;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* capture info about old hash table
|
||||
*/
|
||||
oldwhere = handle -> hash_where;
|
||||
oldwall = handle -> hash_wall;
|
||||
#ifdef SUSPECT
|
||||
oldused = handle -> hash_stat[STAT_USED];
|
||||
#endif
|
||||
/*
|
||||
* attempt to get enough room for a hash table twice as big
|
||||
*/
|
||||
temp = handle->hash_stat[STAT_SIZE];
|
||||
if (( newwhere = (struct hash_entry *)
|
||||
xmalloc((long)((temp+temp+1)*sizeof(struct hash_entry)))) != NULL)
|
||||
/* +1 for wall slot */
|
||||
{
|
||||
retval = ""; /* assume success until proven otherwise */
|
||||
/*
|
||||
* have enough room: now we do all the work.
|
||||
* double the size of everything in handle,
|
||||
* note: hash_mask frob works for 1's & for 2's complement machines
|
||||
*/
|
||||
handle->hash_mask = handle->hash_mask + handle->hash_mask + 1;
|
||||
handle->hash_stat[STAT_SIZE] <<= 1;
|
||||
newsize = handle->hash_stat[STAT_SIZE];
|
||||
handle->hash_where = newwhere;
|
||||
handle->hash_full <<= 1;
|
||||
handle->hash_sizelog += 1;
|
||||
handle->hash_stat[STAT_USED] = 0;
|
||||
handle->hash_wall =
|
||||
newwall = newwhere + newsize;
|
||||
/*
|
||||
* set all those pesky new slots to vacant.
|
||||
*/
|
||||
for (newtrack=newwhere; newtrack <= newwall; newtrack++)
|
||||
{
|
||||
newtrack -> hash_string = NULL;
|
||||
}
|
||||
/*
|
||||
* we will do a scan of the old table, the hard way, using the
|
||||
* new control block to re-insert the data into new hash table.
|
||||
*/
|
||||
handle -> hash_stat[STAT_USED] = 0; /* inserts will bump it up to correct */
|
||||
for (oldtrack=oldwhere; oldtrack < oldwall; oldtrack++)
|
||||
{
|
||||
if ( ((string=oldtrack->hash_string) != NULL) && string!=DELETED )
|
||||
{
|
||||
if ( * (retval = hash_jam(handle,string,oldtrack->hash_value) ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef SUSPECT
|
||||
if ( !*retval && handle->hash_stat[STAT_USED] != oldused)
|
||||
{
|
||||
retval = "hash_used";
|
||||
}
|
||||
#endif
|
||||
if (!*retval)
|
||||
{
|
||||
/*
|
||||
* we have a completely faked up control block.
|
||||
* return the old hash table.
|
||||
*/
|
||||
free((char *)oldwhere);
|
||||
/*
|
||||
* Here with success. retval is already "".
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = "no room";
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* h a s h _ a p p l y ( )
|
||||
*
|
||||
* Use this to scan each entry in symbol table.
|
||||
* For each symbol, this calls (applys) a nominated function supplying the
|
||||
* symbol's value (and the symbol's name).
|
||||
* The idea is you use this to destroy whatever is associted with
|
||||
* any values in the table BEFORE you destroy the table with hash_die.
|
||||
* Of course, you can use it for other jobs; whenever you need to
|
||||
* visit all extant symbols in the table.
|
||||
*
|
||||
* We choose to have a call-you-back idea for two reasons:
|
||||
* asthetic: it is a neater idea to use apply than an explicit loop
|
||||
* sensible: if we ever had to grow the symbol table (due to insertions)
|
||||
* then we would lose our place in the table when we re-hashed
|
||||
* symbols into the new table in a different order.
|
||||
*
|
||||
* The order symbols are visited depends entirely on the hashing function.
|
||||
* Whenever you insert a (symbol, value) you risk expanding the table. If
|
||||
* you do expand the table, then the hashing function WILL change, so you
|
||||
* MIGHT get a different order of symbols visited. In other words, if you
|
||||
* want the same order of visiting symbols as the last time you used
|
||||
* hash_apply() then you better not have done any hash_insert()s or
|
||||
* hash_jam()s since the last time you used hash_apply().
|
||||
*
|
||||
* In future we may use the value returned by your nominated function.
|
||||
* One idea is to abort the scan if, after applying the function to a
|
||||
* certain node, the function returns a certain code.
|
||||
* To be safe, please make your functions of type char *. If you always
|
||||
* return NULL, then the scan will complete, visiting every symbol in
|
||||
* the table exactly once. ALL OTHER RETURNED VALUES have no meaning yet!
|
||||
* Caveat Actor!
|
||||
*
|
||||
* The function you supply should be of the form:
|
||||
* char * myfunct(string,value)
|
||||
* char * string; |* the symbol's name *|
|
||||
* char * value; |* the symbol's value *|
|
||||
* {
|
||||
* |* ... *|
|
||||
* return(NULL);
|
||||
* }
|
||||
*
|
||||
* The returned value of hash_apply() is (char*)NULL. In future it may return
|
||||
* other values. NULL means "completed scan OK". Other values have no meaning
|
||||
* yet. (The function has no graceful failures.)
|
||||
*/
|
||||
char *
|
||||
hash_apply(handle,function)
|
||||
struct hash_control * handle;
|
||||
char* (*function)();
|
||||
{
|
||||
register struct hash_entry * entry;
|
||||
register struct hash_entry * wall;
|
||||
|
||||
wall = handle->hash_wall;
|
||||
for (entry = handle->hash_where; entry < wall; entry++)
|
||||
{
|
||||
if (islive(entry)) /* silly code: tests entry->string twice! */
|
||||
{
|
||||
(*function)(entry->hash_string,entry->hash_value);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* h a s h _ f i n d ( )
|
||||
*
|
||||
* Given symbol string, find value (if any).
|
||||
* Return found value or NULL.
|
||||
*/
|
||||
char *
|
||||
hash_find(handle,string) /* return char* or NULL */
|
||||
struct hash_control * handle;
|
||||
char * string;
|
||||
{
|
||||
register struct hash_entry * entry;
|
||||
register char * retval;
|
||||
|
||||
entry = hash_ask(handle,string,STAT__READ);
|
||||
if (hash_found)
|
||||
{
|
||||
retval = entry->hash_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = NULL;
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* h a s h _ a s k ( )
|
||||
*
|
||||
* Searches for given symbol string.
|
||||
* Return the slot where it OUGHT to live. It may be there.
|
||||
* Return hash_found: TRUE only if symbol is in that slot.
|
||||
* Access argument is to help keep statistics in control block.
|
||||
* Internal.
|
||||
*/
|
||||
static struct hash_entry * /* string slot, may be empty or deleted */
|
||||
hash_ask(handle,string,access)
|
||||
struct hash_control * handle;
|
||||
char * string;
|
||||
int access; /* access type */
|
||||
{
|
||||
register char *string1; /* JF avoid strcmp calls */
|
||||
register char * s;
|
||||
register int c;
|
||||
register struct hash_entry * slot;
|
||||
register int collision; /* count collisions */
|
||||
|
||||
slot = handle->hash_where + hash_code(handle,string); /* start looking here */
|
||||
handle->hash_stat[STAT_ACCESS+access] += 1;
|
||||
collision = 0;
|
||||
hash_found = FALSE;
|
||||
while ( ((s = slot->hash_string) != NULL) && s!=DELETED )
|
||||
{
|
||||
for(string1=string;;) {
|
||||
if((c= *s++) == 0) {
|
||||
if(!*string1)
|
||||
hash_found = TRUE;
|
||||
break;
|
||||
}
|
||||
if(*string1++!=c)
|
||||
break;
|
||||
}
|
||||
if(hash_found)
|
||||
break;
|
||||
collision++;
|
||||
slot++;
|
||||
}
|
||||
/*
|
||||
* slot: return:
|
||||
* in use: we found string slot
|
||||
* at empty:
|
||||
* at wall: we fell off: wrap round ????
|
||||
* in table: dig here slot
|
||||
* at DELETED: dig here slot
|
||||
*/
|
||||
if (slot==handle->hash_wall)
|
||||
{
|
||||
slot = handle->hash_where; /* now look again */
|
||||
while( ((s = slot->hash_string) != NULL) && s!=DELETED )
|
||||
{
|
||||
for(string1=string;*s;string1++,s++) {
|
||||
if(*string1!=*s)
|
||||
break;
|
||||
}
|
||||
if(*s==*string1) {
|
||||
hash_found = TRUE;
|
||||
break;
|
||||
}
|
||||
collision++;
|
||||
slot++;
|
||||
}
|
||||
/*
|
||||
* slot: return:
|
||||
* in use: we found it slot
|
||||
* empty: wall: ERROR IMPOSSIBLE !!!!
|
||||
* in table: dig here slot
|
||||
* DELETED:dig here slot
|
||||
*/
|
||||
}
|
||||
/* fprintf(stderr,"hash_ask(%s)->%d(%d)\n",string,hash_code(handle,string),collision); */
|
||||
handle -> hash_stat[STAT_COLLIDE+access] += collision;
|
||||
return(slot); /* also return hash_found */
|
||||
}
|
||||
|
||||
/*
|
||||
* h a s h _ c o d e
|
||||
*
|
||||
* Does hashing of symbol string to hash number.
|
||||
* Internal.
|
||||
*/
|
||||
static int
|
||||
hash_code(handle,string)
|
||||
struct hash_control * handle;
|
||||
register char * string;
|
||||
{
|
||||
register long h; /* hash code built here */
|
||||
register long c; /* each character lands here */
|
||||
register int n; /* Amount to shift h by */
|
||||
|
||||
n = (handle->hash_sizelog - 3);
|
||||
h = 0;
|
||||
while ((c = *string++) != 0)
|
||||
{
|
||||
h += c;
|
||||
h = (h<<3) + (h>>n) + c;
|
||||
}
|
||||
return (h & handle->hash_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* Here is a test program to exercise above.
|
||||
*/
|
||||
#ifdef TEST
|
||||
|
||||
#define TABLES (6) /* number of hash tables to maintain */
|
||||
/* (at once) in any testing */
|
||||
#define STATBUFSIZE (12) /* we can have 12 statistics */
|
||||
|
||||
int statbuf[STATBUFSIZE]; /* display statistics here */
|
||||
char answer[100]; /* human farts here */
|
||||
char * hashtable[TABLES]; /* we test many hash tables at once */
|
||||
char * h; /* points to curent hash_control */
|
||||
char ** pp;
|
||||
char * p;
|
||||
char * name;
|
||||
char * value;
|
||||
int size;
|
||||
int used;
|
||||
char command;
|
||||
int number; /* number 0:TABLES-1 of current hashed */
|
||||
/* symbol table */
|
||||
|
||||
main()
|
||||
{
|
||||
char (*applicatee());
|
||||
char * hash_find();
|
||||
char * destroy();
|
||||
char * what();
|
||||
struct hash_control * hash_new();
|
||||
char * hash_replace();
|
||||
int * ip;
|
||||
|
||||
number = 0;
|
||||
h = 0;
|
||||
printf("type h <RETURN> for help\n");
|
||||
for(;;)
|
||||
{
|
||||
printf("hash_test command: ");
|
||||
gets(answer);
|
||||
command = answer[0];
|
||||
if (isupper(command)) command = tolower(command); /* ecch! */
|
||||
switch (command)
|
||||
{
|
||||
case '#':
|
||||
printf("old hash table #=%d.\n",number);
|
||||
whattable();
|
||||
break;
|
||||
case '?':
|
||||
for (pp=hashtable; pp<hashtable+TABLES; pp++)
|
||||
{
|
||||
printf("address of hash table #%d control block is %xx\n"
|
||||
,pp-hashtable,*pp);
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
hash_apply(h,applicatee);
|
||||
break;
|
||||
case 'd':
|
||||
hash_apply(h,destroy);
|
||||
hash_die(h);
|
||||
break;
|
||||
case 'f':
|
||||
p = hash_find(h,name=what("symbol"));
|
||||
printf("value of \"%s\" is \"%s\"\n",name,p?p:"NOT-PRESENT");
|
||||
break;
|
||||
case 'h':
|
||||
printf("# show old, select new default hash table number\n");
|
||||
printf("? display all hashtable control block addresses\n");
|
||||
printf("a apply a simple display-er to each symbol in table\n");
|
||||
printf("d die: destroy hashtable\n");
|
||||
printf("f find value of nominated symbol\n");
|
||||
printf("h this help\n");
|
||||
printf("i insert value into symbol\n");
|
||||
printf("j jam value into symbol\n");
|
||||
printf("n new hashtable\n");
|
||||
printf("r replace a value with another\n");
|
||||
printf("s say what %% of table is used\n");
|
||||
printf("q exit this program\n");
|
||||
printf("x delete a symbol from table, report its value\n");
|
||||
break;
|
||||
case 'i':
|
||||
p = hash_insert(h,name=what("symbol"),value=what("value"));
|
||||
if (*p)
|
||||
{
|
||||
printf("symbol=\"%s\" value=\"%s\" error=%s\n",name,value,p);
|
||||
}
|
||||
break;
|
||||
case 'j':
|
||||
p = hash_jam(h,name=what("symbol"),value=what("value"));
|
||||
if (*p)
|
||||
{
|
||||
printf("symbol=\"%s\" value=\"%s\" error=%s\n",name,value,p);
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
h = hashtable[number] = (char *) hash_new();
|
||||
break;
|
||||
case 'q':
|
||||
exit();
|
||||
case 'r':
|
||||
p = hash_replace(h,name=what("symbol"),value=what("value"));
|
||||
printf("old value was \"%s\"\n",p?p:"{}");
|
||||
break;
|
||||
case 's':
|
||||
hash_say(h,statbuf,STATBUFSIZE);
|
||||
for (ip=statbuf; ip<statbuf+STATBUFSIZE; ip++)
|
||||
{
|
||||
printf("%d ",*ip);
|
||||
}
|
||||
printf("\n");
|
||||
break;
|
||||
case 'x':
|
||||
p = hash_delete(h,name=what("symbol"));
|
||||
printf("old value was \"%s\"\n",p?p:"{}");
|
||||
break;
|
||||
default:
|
||||
printf("I can't understand command \"%c\"\n",command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
what(description)
|
||||
char * description;
|
||||
{
|
||||
char * retval;
|
||||
char * malloc();
|
||||
|
||||
printf(" %s : ",description);
|
||||
gets(answer);
|
||||
/* will one day clean up answer here */
|
||||
retval = malloc(strlen(answer)+1);
|
||||
if (!retval)
|
||||
{
|
||||
error("room");
|
||||
}
|
||||
(void)strcpy(retval,answer);
|
||||
return(retval);
|
||||
}
|
||||
|
||||
char *
|
||||
destroy(string,value)
|
||||
char * string;
|
||||
char * value;
|
||||
{
|
||||
free(string);
|
||||
free(value);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
applicatee(string,value)
|
||||
char * string;
|
||||
char * value;
|
||||
{
|
||||
printf("%.20s-%.20s\n",string,value);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
whattable() /* determine number: what hash table to use */
|
||||
/* also determine h: points to hash_control */
|
||||
{
|
||||
|
||||
for (;;)
|
||||
{
|
||||
printf(" what hash table (%d:%d) ? ",0,TABLES-1);
|
||||
gets(answer);
|
||||
sscanf(answer,"%d",&number);
|
||||
if (number>=0 && number<TABLES)
|
||||
{
|
||||
h = hashtable[number];
|
||||
if (!h)
|
||||
{
|
||||
printf("warning: current hash-table-#%d. has no hash-control\n",number);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("invalid hash table number: %d\n",number);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* #ifdef TEST */
|
||||
|
||||
/* end: hash.c */
|
59
gas/hash.h
Normal file
59
gas/hash.h
Normal file
|
@ -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 */
|
322
gas/input-file.c
Normal file
322
gas/input-file.c
Normal file
|
@ -0,0 +1,322 @@
|
|||
/* input_file.c - Deal with Input Files -
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
#ifdef USG
|
||||
#define setbuffer(stream, buf, size) setvbuf((stream), (buf), _IOFBF, (size))
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "as.h"
|
||||
#include "input-file.h"
|
||||
|
||||
/* This variable is non-zero if the file currently being read should be
|
||||
preprocessed by app. It is zero if the file can be read straight in.
|
||||
*/
|
||||
int preprocess = 0;
|
||||
|
||||
/*
|
||||
* This code opens a file, then delivers BUFFER_SIZE character
|
||||
* chunks of the file on demand.
|
||||
* BUFFER_SIZE is supposed to be a number chosen for speed.
|
||||
* The caller only asks once what BUFFER_SIZE is, and asks before
|
||||
* the nature of the input files (if any) is known.
|
||||
*/
|
||||
|
||||
#define BUFFER_SIZE (32 * 1024)
|
||||
|
||||
/*
|
||||
* We use static data: the data area is not sharable.
|
||||
*/
|
||||
|
||||
FILE *f_in;
|
||||
/* static JF remove static so app.c can use file_name */
|
||||
char * file_name;
|
||||
|
||||
/* Struct for saving the state of this module for file includes. */
|
||||
struct saved_file {
|
||||
FILE *f_in;
|
||||
char *file_name;
|
||||
int preprocess;
|
||||
char *app_save;
|
||||
};
|
||||
|
||||
/* These hooks accomodate most operating systems. */
|
||||
|
||||
void input_file_begin() {
|
||||
f_in = (FILE *)0;
|
||||
}
|
||||
|
||||
void input_file_end () { }
|
||||
|
||||
/* Return BUFFER_SIZE. */
|
||||
int input_file_buffer_size() {
|
||||
return (BUFFER_SIZE);
|
||||
}
|
||||
|
||||
int input_file_is_open() {
|
||||
return f_in!=(FILE *)0;
|
||||
}
|
||||
|
||||
/* Push the state of our input, returning a pointer to saved info that
|
||||
can be restored with input_file_pop (). */
|
||||
char *input_file_push () {
|
||||
register struct saved_file *saved;
|
||||
|
||||
saved = (struct saved_file *)xmalloc (sizeof *saved);
|
||||
|
||||
saved->f_in = f_in;
|
||||
saved->file_name = file_name;
|
||||
saved->preprocess = preprocess;
|
||||
if (preprocess)
|
||||
saved->app_save = app_push ();
|
||||
|
||||
input_file_begin (); /* Initialize for new file */
|
||||
|
||||
return (char *)saved;
|
||||
}
|
||||
|
||||
void
|
||||
input_file_pop (arg)
|
||||
char *arg;
|
||||
{
|
||||
register struct saved_file *saved = (struct saved_file *)arg;
|
||||
|
||||
input_file_end (); /* Close out old file */
|
||||
|
||||
f_in = saved->f_in;
|
||||
file_name = saved->file_name;
|
||||
preprocess = saved->preprocess;
|
||||
if (preprocess)
|
||||
app_pop (saved->app_save);
|
||||
|
||||
free(arg);
|
||||
}
|
||||
|
||||
#ifdef DONTDEF /* JF save old version in case we need it */
|
||||
void
|
||||
input_file_open (filename, preprocess, debugging)
|
||||
char * filename; /* "" means use stdin. Must not be 0. */
|
||||
int preprocess; /* TRUE if needs app. */
|
||||
int debugging; /* TRUE if we are debugging assembler. */
|
||||
{
|
||||
assert( filename != 0 ); /* Filename may not be NULL. */
|
||||
if (filename [0])
|
||||
{ /* We have a file name. Suck it and see. */
|
||||
file_handle = open (filename, O_RDONLY, 0);
|
||||
file_name = filename;
|
||||
}
|
||||
else
|
||||
{ /* use stdin for the input file. */
|
||||
file_handle = fileno (stdin);
|
||||
file_name = "{standard input}"; /* For error messages. */
|
||||
}
|
||||
if (file_handle < 0)
|
||||
as_perror ("Can't open %s for reading", file_name);
|
||||
if ( preprocess )
|
||||
{
|
||||
/*
|
||||
* This code was written in haste for a frobbed BSD 4.2.
|
||||
* I have a flight to catch: will someone please do proper
|
||||
* error checks? - Dean.
|
||||
*/
|
||||
int pid;
|
||||
char temporary_file_name [12];
|
||||
int fd;
|
||||
union wait status;
|
||||
|
||||
(void)strcpy (temporary_file_name, "#appXXXXXX");
|
||||
(void)mktemp (temporary_file_name);
|
||||
pid = vfork ();
|
||||
if (pid == -1)
|
||||
{
|
||||
as_perror ("Vfork failed", file_name);
|
||||
_exit (144);
|
||||
}
|
||||
if (pid == 0)
|
||||
{
|
||||
(void)dup2 (file_handle, fileno(stdin));
|
||||
fd = open (temporary_file_name, O_WRONLY + O_TRUNC + O_CREAT, 0666);
|
||||
if (fd == -1)
|
||||
{
|
||||
(void)write(2,"Can't open temporary\n",21);
|
||||
_exit (99);
|
||||
}
|
||||
(void)dup2 (fd, fileno(stdout));
|
||||
/* JF for testing #define PREPROCESSOR "/lib/app" */
|
||||
#define PREPROCESSOR "./app"
|
||||
execl (PREPROCESSOR, PREPROCESSOR, 0);
|
||||
execl ("app","app",0);
|
||||
(void)write(2,"Exec of app failed. Get help.\n",31);
|
||||
(void)unlink(temporary_file_name);
|
||||
_exit (11);
|
||||
}
|
||||
(void)wait (& status);
|
||||
if (status.w_status & 0xFF00) /* JF was 0xF000, was wrong */
|
||||
{
|
||||
file_handle = -1;
|
||||
as_bad( "Can't preprocess file \"%s\", status = %xx", file_name, status.w_status );
|
||||
}
|
||||
else
|
||||
{
|
||||
file_handle = open (temporary_file_name, O_RDONLY, 0);
|
||||
if ( ! debugging && unlink(temporary_file_name))
|
||||
as_perror ("Can't delete temp file %s", temporary_file_name);
|
||||
}
|
||||
if (file_handle == -1)
|
||||
as_perror ("Can't retrieve temp file %s", temporary_file_name);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
void
|
||||
input_file_open (filename,pre)
|
||||
char * filename; /* "" means use stdin. Must not be 0. */
|
||||
int pre;
|
||||
{
|
||||
int c;
|
||||
char buf[80];
|
||||
|
||||
preprocess = pre;
|
||||
|
||||
assert( filename != 0 ); /* Filename may not be NULL. */
|
||||
if (filename [0]) { /* We have a file name. Suck it and see. */
|
||||
f_in=fopen(filename,"r");
|
||||
file_name=filename;
|
||||
} else { /* use stdin for the input file. */
|
||||
f_in = stdin;
|
||||
file_name = "{standard input}"; /* For error messages. */
|
||||
}
|
||||
if (f_in==(FILE *)0) {
|
||||
as_perror ("Can't open %s for reading", file_name);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef VMS
|
||||
/* Ask stdio to buffer our input at BUFFER_SIZE, with a dynamically
|
||||
allocated buffer. */
|
||||
setvbuf(f_in, (char *)NULL, _IOFBF, 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 (!strchr(buf,'\n'))
|
||||
ungetc('#',f_in); /* It was longer */
|
||||
else
|
||||
ungetc('\n',f_in);
|
||||
} else if(c=='\n')
|
||||
ungetc('\n',f_in);
|
||||
else
|
||||
ungetc('#',f_in);
|
||||
} else
|
||||
ungetc(c,f_in);
|
||||
|
||||
#ifdef DONTDEF
|
||||
if ( preprocess ) {
|
||||
char temporary_file_name [17];
|
||||
FILE *f_out;
|
||||
|
||||
(void)strcpy (temporary_file_name, "/tmp/#appXXXXXX");
|
||||
(void)mktemp (temporary_file_name);
|
||||
f_out=fopen(temporary_file_name,"w+");
|
||||
if(f_out==(FILE *)0)
|
||||
as_perror("Can't open temp file %s",temporary_file_name);
|
||||
|
||||
/* JF this will have to be moved on any system that
|
||||
does not support removal of open files. */
|
||||
(void)unlink(temporary_file_name);/* JF do it NOW */
|
||||
do_scrub(f_in,f_out);
|
||||
(void)fclose(f_in); /* All done with it */
|
||||
(void)rewind(f_out);
|
||||
f_in=f_out;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Close input file. */
|
||||
void input_file_close() {
|
||||
fclose (f_in);
|
||||
f_in = 0;
|
||||
}
|
||||
|
||||
char *
|
||||
input_file_give_next_buffer (where)
|
||||
char * where; /* Where to place 1st character of new buffer. */
|
||||
{
|
||||
char * return_value; /* -> Last char of what we read, + 1. */
|
||||
register int size;
|
||||
|
||||
if (f_in == (FILE *)0)
|
||||
return 0;
|
||||
/*
|
||||
* fflush (stdin); could be done here if you want to synchronise
|
||||
* stdin and stdout, for the case where our input file is stdin.
|
||||
* Since the assembler shouldn't do any output to stdout, we
|
||||
* don't bother to synch output and input.
|
||||
*/
|
||||
if(preprocess) {
|
||||
char *p;
|
||||
int n;
|
||||
int ch;
|
||||
extern FILE *scrub_file;
|
||||
|
||||
scrub_file=f_in;
|
||||
for (p = where, n = BUFFER_SIZE; n; --n) {
|
||||
|
||||
ch = do_scrub_next_char(scrub_from_file, scrub_to_file);
|
||||
if (ch == EOF)
|
||||
break;
|
||||
*p++=ch;
|
||||
}
|
||||
size=BUFFER_SIZE-n;
|
||||
} else
|
||||
size= fread(where,sizeof(char),BUFFER_SIZE,f_in);
|
||||
if (size < 0)
|
||||
{
|
||||
as_perror ("Can't read from %s", file_name);
|
||||
size = 0;
|
||||
}
|
||||
if (size)
|
||||
return_value = where + size;
|
||||
else
|
||||
{
|
||||
if (fclose (f_in))
|
||||
as_perror ("Can't close %s", file_name);
|
||||
f_in = (FILE *)0;
|
||||
return_value = 0;
|
||||
}
|
||||
return (return_value);
|
||||
}
|
84
gas/input-file.h
Normal file
84
gas/input-file.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/* 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.
|
||||
*
|
||||
* input_file_push() Push state, which can be restored
|
||||
* later. Does implicit input_file_begin.
|
||||
* Returns char * to saved state.
|
||||
*
|
||||
* input_file_pop (arg) Pops previously saved state.
|
||||
*
|
||||
* input_file_close () Closes opened file.
|
||||
*
|
||||
* All errors are reported (using as_perror) so caller doesn't have to think
|
||||
* about I/O errors. No I/O errors are fatal: an end-of-file may be faked.
|
||||
*/
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
char *input_file_give_next_buffer(char *where);
|
||||
char *input_file_push(void);
|
||||
int input_file_buffer_size(void);
|
||||
int input_file_is_open(void);
|
||||
void input_file_begin(void);
|
||||
void input_file_close(void);
|
||||
void input_file_end(void);
|
||||
void input_file_open(char *filename, int pre);
|
||||
void input_file_pop(char *arg);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
char *input_file_give_next_buffer();
|
||||
char *input_file_push();
|
||||
int input_file_buffer_size();
|
||||
int input_file_is_open();
|
||||
void input_file_begin();
|
||||
void input_file_close();
|
||||
void input_file_end();
|
||||
void input_file_open();
|
||||
void input_file_pop();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
/* end: input_file.h */
|
478
gas/input-scrub.c
Normal file
478
gas/input-scrub.c
Normal file
|
@ -0,0 +1,478 @@
|
|||
/* input_scrub.c - Break up input buffers into whole numbers of lines.
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
#include <errno.h> /* Need this to make errno declaration right */
|
||||
#include "as.h"
|
||||
#include "input-file.h"
|
||||
|
||||
/*
|
||||
* O/S independent module to supply buffers of sanitised source code
|
||||
* to rest of assembler. We get sanitized input data of arbitrary length.
|
||||
* We break these buffers on line boundaries, recombine pieces that
|
||||
* were broken across buffers, and return a buffer of full lines to
|
||||
* the caller.
|
||||
* The last partial line begins the next buffer we build and return to caller.
|
||||
* The buffer returned to caller is preceeded by BEFORE_STRING and followed
|
||||
* by AFTER_STRING, as sentinels. The last character before AFTER_STRING
|
||||
* is a newline.
|
||||
* Also looks after line numbers, for e.g. error messages.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We don't care how filthy our buffers are, but our callers assume
|
||||
* that the following sanitation has already been done.
|
||||
*
|
||||
* No comments, reduce a comment to a space.
|
||||
* Reduce a tab to a space unless it is 1st char of line.
|
||||
* All multiple tabs and spaces collapsed into 1 char. Tab only
|
||||
* legal if 1st char of line.
|
||||
* # line file statements converted to .line x;.file y; statements.
|
||||
* Escaped newlines at end of line: remove them but add as many newlines
|
||||
* to end of statement as you removed in the middle, to synch line numbers.
|
||||
*/
|
||||
|
||||
#define BEFORE_STRING ("\n")
|
||||
#define AFTER_STRING ("\0") /* 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? */
|
||||
|
||||
/* Saved information about the file that .include'd this one. When we
|
||||
hit EOF, we automatically pop to that file. */
|
||||
|
||||
static char *next_saved_file;
|
||||
|
||||
/*
|
||||
We can have more than one source file open at once, though the info for
|
||||
all but the latest one are saved off in a struct input_save. These
|
||||
files remain open, so we are limited by the number of open files allowed
|
||||
by the underlying OS.
|
||||
We may also sequentially read more than one source file in an assembly.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
We must track the physical file and line number for error messages.
|
||||
We also track a "logical" file and line number corresponding to (C?)
|
||||
compiler source line numbers.
|
||||
Whenever we open a file we must fill in physical_input_file. So if it is NULL
|
||||
we have not opened any files yet.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/* Struct used to save the state of the input handler during include files */
|
||||
struct input_save {
|
||||
char *buffer_start;
|
||||
char *partial_where;
|
||||
int partial_size;
|
||||
char save_source [AFTER_SIZE];
|
||||
int buffer_length;
|
||||
char *physical_input_file;
|
||||
char *logical_input_file;
|
||||
line_numberT physical_input_line;
|
||||
line_numberT logical_input_line;
|
||||
char *next_saved_file; /* Chain of input_saves */
|
||||
char *input_file_save; /* Saved state of input routines */
|
||||
char *saved_position; /* Caller's saved position in buf */
|
||||
};
|
||||
|
||||
#ifdef __STDC__
|
||||
static void as_1_char(unsigned int c, FILE *stream);
|
||||
#else /* __STDC__ */
|
||||
static void as_1_char();
|
||||
#endif /* __STDC__ */
|
||||
|
||||
/* Push the state of input reading and scrubbing so that we can #include.
|
||||
The return value is a 'void *' (fudged for old compilers) to a save
|
||||
area, which can be restored by passing it to input_scrub_pop(). */
|
||||
char *
|
||||
input_scrub_push(saved_position)
|
||||
char *saved_position;
|
||||
{
|
||||
register struct input_save *saved;
|
||||
|
||||
saved = (struct input_save *) xmalloc(sizeof *saved);
|
||||
|
||||
saved->saved_position = saved_position;
|
||||
saved->buffer_start = buffer_start;
|
||||
saved->partial_where = partial_where;
|
||||
saved->partial_size = partial_size;
|
||||
saved->buffer_length = buffer_length;
|
||||
saved->physical_input_file = physical_input_file;
|
||||
saved->logical_input_file = logical_input_file;
|
||||
saved->physical_input_line = physical_input_line;
|
||||
saved->logical_input_line = logical_input_line;
|
||||
bcopy (saved->save_source, save_source, sizeof (save_source));
|
||||
saved->next_saved_file = next_saved_file;
|
||||
saved->input_file_save = input_file_push ();
|
||||
|
||||
input_scrub_begin (); /* Reinitialize! */
|
||||
|
||||
return (char *)saved;
|
||||
}
|
||||
|
||||
char *
|
||||
input_scrub_pop (arg)
|
||||
char *arg;
|
||||
{
|
||||
register struct input_save *saved;
|
||||
char *saved_position;
|
||||
|
||||
input_scrub_end (); /* Finish off old buffer */
|
||||
|
||||
saved = (struct input_save *)arg;
|
||||
|
||||
input_file_pop (saved->input_file_save);
|
||||
saved_position = saved->saved_position;
|
||||
buffer_start = saved->buffer_start;
|
||||
buffer_length = saved->buffer_length;
|
||||
physical_input_file = saved->physical_input_file;
|
||||
logical_input_file = saved->logical_input_file;
|
||||
physical_input_line = saved->physical_input_line;
|
||||
logical_input_line = saved->logical_input_line;
|
||||
partial_where = saved->partial_where;
|
||||
partial_size = saved->partial_size;
|
||||
next_saved_file = saved->next_saved_file;
|
||||
bcopy (save_source, saved->save_source, sizeof (save_source));
|
||||
|
||||
free(arg);
|
||||
return saved_position;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
input_scrub_begin ()
|
||||
{
|
||||
know(strlen(BEFORE_STRING) == BEFORE_SIZE);
|
||||
know(strlen(AFTER_STRING) == AFTER_SIZE
|
||||
|| (AFTER_STRING[0] == '\0' && AFTER_SIZE == 1));
|
||||
|
||||
input_file_begin ();
|
||||
|
||||
buffer_length = input_file_buffer_size ();
|
||||
|
||||
buffer_start = xmalloc((long)(BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE));
|
||||
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. */
|
||||
next_saved_file = NULL; /* At EOF, don't pop to any other file */
|
||||
do_scrub_begin();
|
||||
}
|
||||
|
||||
void
|
||||
input_scrub_end ()
|
||||
{
|
||||
if (buffer_start)
|
||||
{
|
||||
free (buffer_start);
|
||||
buffer_start = 0;
|
||||
input_file_end ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Start reading input from a new file. */
|
||||
|
||||
char * /* Return start of caller's part of buffer. */
|
||||
input_scrub_new_file (filename)
|
||||
char * filename;
|
||||
{
|
||||
input_file_open (filename, !flagseen['f']);
|
||||
physical_input_file = filename[0] ? filename : "{standard input}";
|
||||
physical_input_line = 0;
|
||||
|
||||
partial_size = 0;
|
||||
return (buffer_start + BEFORE_SIZE);
|
||||
}
|
||||
|
||||
|
||||
/* Include a file from the current file. Save our state, cause it to
|
||||
be restored on EOF, and begin handling a new file. Same result as
|
||||
input_scrub_new_file. */
|
||||
|
||||
char *
|
||||
input_scrub_include_file (filename, position)
|
||||
char *filename;
|
||||
char *position;
|
||||
{
|
||||
next_saved_file = input_scrub_push (position);
|
||||
return input_scrub_new_file (filename);
|
||||
}
|
||||
|
||||
void
|
||||
input_scrub_close ()
|
||||
{
|
||||
input_file_close ();
|
||||
}
|
||||
char *
|
||||
input_scrub_next_buffer (bufp)
|
||||
char **bufp;
|
||||
{
|
||||
register char * limit; /*->just after last char of buffer. */
|
||||
|
||||
*bufp = buffer_start + BEFORE_SIZE;
|
||||
|
||||
#ifdef DONTDEF
|
||||
if(preprocess) {
|
||||
if(save_buffer) {
|
||||
*bufp = save_buffer;
|
||||
save_buffer = 0;
|
||||
}
|
||||
limit = input_file_give_next_buffer(buffer_start+BEFORE_SIZE);
|
||||
if (!limit) {
|
||||
partial_where = 0;
|
||||
if(partial_size)
|
||||
as_warn("Partial line at end of file ignored");
|
||||
return partial_where;
|
||||
}
|
||||
|
||||
if(partial_size)
|
||||
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");
|
||||
}
|
||||
/* If we should pop to another file at EOF, do it. */
|
||||
if (next_saved_file)
|
||||
{
|
||||
*bufp = input_scrub_pop (next_saved_file); /* Pop state */
|
||||
/* partial_where is now correct to return, since we popped it. */
|
||||
}
|
||||
}
|
||||
return (partial_where);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 we have a file name */
|
||||
|
||||
if (line_number >= 0) {
|
||||
logical_input_line = line_number;
|
||||
} /* if we have a line number */
|
||||
} /* new_logical_line() */
|
||||
|
||||
/*
|
||||
* a s _ w h e r e ()
|
||||
*
|
||||
* Write a line to stderr locating where we are in reading
|
||||
* input source files.
|
||||
* As a sop to the debugger of AS, pretty-print the offending line.
|
||||
*/
|
||||
void
|
||||
as_where()
|
||||
{
|
||||
char *p;
|
||||
line_numberT line;
|
||||
|
||||
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:%d:", p, (int) line);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DONTDEF
|
||||
fprintf (stderr," Before reading source.\n");
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* a s _ h o w m u c h ()
|
||||
*
|
||||
* Output to given stream how much of line we have scanned so far.
|
||||
* Assumes we have scanned up to and including input_line_pointer.
|
||||
* No free '\n' at end of line.
|
||||
*/
|
||||
void
|
||||
as_howmuch (stream)
|
||||
FILE * stream; /* Opened for write please. */
|
||||
{
|
||||
register char * p; /* Scan input line. */
|
||||
/* register char c; JF unused */
|
||||
|
||||
for (p = input_line_pointer - 1; * p != '\n'; --p)
|
||||
{
|
||||
}
|
||||
++ p; /* p->1st char of line. */
|
||||
for (; p <= input_line_pointer; p++)
|
||||
{
|
||||
/* Assume ASCII. EBCDIC & other micro-computer char sets ignored. */
|
||||
/* c = *p & 0xFF; JF unused */
|
||||
as_1_char(*p, stream);
|
||||
}
|
||||
}
|
||||
|
||||
static void as_1_char (c,stream)
|
||||
unsigned int c;
|
||||
FILE *stream;
|
||||
{
|
||||
if (c > 127)
|
||||
{
|
||||
(void)putc('%', stream);
|
||||
c -= 128;
|
||||
}
|
||||
if (c < 32)
|
||||
{
|
||||
(void)putc('^', stream);
|
||||
c += '@';
|
||||
}
|
||||
(void)putc(c, stream);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end: input_scrub.c */
|
391
gas/messages.c
Normal file
391
gas/messages.c
Normal file
|
@ -0,0 +1,391 @@
|
|||
/* messages.c - error reporter -
|
||||
Copyright (C) 1987, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#include <stdio.h> /* define stderr */
|
||||
#include <errno.h>
|
||||
|
||||
#include "as.h"
|
||||
|
||||
#ifndef NO_STDARG
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#ifndef NO_VARARGS
|
||||
#include <varargs.h>
|
||||
#endif /* NO_VARARGS */
|
||||
#endif /* NO_STDARG */
|
||||
|
||||
/*
|
||||
* Despite the rest of the comments in this file, (FIXME-SOON),
|
||||
* here is the current scheme for error messages etc:
|
||||
*
|
||||
* as_fatal() is used when gas is quite confused and
|
||||
* continuing the assembly is pointless. In this case we
|
||||
* exit immediately with error status.
|
||||
*
|
||||
* as_bad() is used to mark errors that result in what we
|
||||
* presume to be a useless object file. Say, we ignored
|
||||
* something that might have been vital. If we see any of
|
||||
* these, assembly will continue to the end of the source,
|
||||
* no object file will be produced, and we will terminate
|
||||
* with error status. The new option, -Z, tells us to
|
||||
* produce an object file anyway but we still exit with
|
||||
* error status. The assumption here is that you don't want
|
||||
* this object file but we could be wrong.
|
||||
*
|
||||
* as_warn() is used when we have an error from which we
|
||||
* have a plausible error recovery. eg, masking the top
|
||||
* bits of a constant that is longer than will fit in the
|
||||
* destination. In this case we will continue to assemble
|
||||
* the source, although we may have made a bad assumption,
|
||||
* and we will produce an object file and return normal exit
|
||||
* status (ie, no error). The new option -X tells us to
|
||||
* treat all as_warn() errors as as_bad() errors. That is,
|
||||
* no object file will be produced and we will exit with
|
||||
* error status. The idea here is that we don't kill an
|
||||
* entire make because of an error that we knew how to
|
||||
* correct. On the other hand, sometimes you might want to
|
||||
* stop the make at these points.
|
||||
*
|
||||
* as_tsktsk() is used when we see a minor error for which
|
||||
* our error recovery action is almost certainly correct.
|
||||
* In this case, we print a message and then assembly
|
||||
* continues as though no error occurred.
|
||||
*/
|
||||
|
||||
/*
|
||||
ERRORS
|
||||
|
||||
JF: this is now bogus. We now print more standard error messages
|
||||
that try to look like everyone else's.
|
||||
|
||||
We print the error message 1st, beginning in column 1.
|
||||
All ancillary info starts in column 2 on lines after the
|
||||
key error text.
|
||||
We try to print a location in logical and physical file
|
||||
just after the main error text.
|
||||
Caller then prints any appendices after that, begining all
|
||||
lines with at least 1 space.
|
||||
|
||||
Optionally, we may die.
|
||||
There is no need for a trailing '\n' in your error text format
|
||||
because we supply one.
|
||||
|
||||
as_warn(fmt,args) Like fprintf(stderr,fmt,args) but also call errwhere().
|
||||
|
||||
as_fatal(fmt,args) Like as_warn() but exit with a fatal status.
|
||||
|
||||
*/
|
||||
|
||||
static int warning_count = 0; /* Count of number of warnings issued */
|
||||
|
||||
int had_warnings() {
|
||||
return(warning_count);
|
||||
} /* had_err() */
|
||||
|
||||
/* Nonzero if we've hit a 'bad error', and should not write an obj file,
|
||||
and exit with a nonzero error code */
|
||||
|
||||
static int error_count = 0;
|
||||
|
||||
int had_errors() {
|
||||
return(error_count);
|
||||
} /* had_errors() */
|
||||
|
||||
|
||||
/*
|
||||
* a s _ p e r r o r
|
||||
*
|
||||
* Like perror(3), but with more info.
|
||||
*/
|
||||
void as_perror(gripe, filename)
|
||||
char *gripe; /* Unpunctuated error theme. */
|
||||
char *filename;
|
||||
{
|
||||
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. */
|
||||
} /* as_perror() */
|
||||
|
||||
/*
|
||||
* a s _ t s k t s k ()
|
||||
*
|
||||
* Send to stderr a string (with bell) (JF: Bell is obnoxious!) as a warning, and locate warning
|
||||
* in input file(s).
|
||||
* Please only use this for when we have some recovery action.
|
||||
* Please explain in string (which may have '\n's) what recovery was done.
|
||||
*/
|
||||
|
||||
#ifndef NO_STDARG
|
||||
void as_tsktsk(Format)
|
||||
const char *Format;
|
||||
{
|
||||
va_list args;
|
||||
|
||||
as_where();
|
||||
va_start(args, Format);
|
||||
vfprintf(stderr, Format, args);
|
||||
va_end(args);
|
||||
(void) putc('\n', stderr);
|
||||
} /* as_tsktsk() */
|
||||
#else
|
||||
#ifndef NO_VARARGS
|
||||
void as_tsktsk(Format,va_alist)
|
||||
char *Format;
|
||||
va_dcl
|
||||
{
|
||||
va_list args;
|
||||
|
||||
as_where();
|
||||
va_start(args);
|
||||
vfprintf(stderr, Format, args);
|
||||
va_end(args);
|
||||
(void) putc('\n', stderr);
|
||||
} /* as_tsktsk() */
|
||||
#else
|
||||
/*VARARGS1 */
|
||||
as_tsktsk(Format,args)
|
||||
char *Format;
|
||||
{
|
||||
as_where();
|
||||
_doprnt (Format, &args, stderr);
|
||||
(void)putc ('\n', stderr);
|
||||
/* as_where(); */
|
||||
} /* as_tsktsk */
|
||||
#endif /* not NO_VARARGS */
|
||||
#endif /* not NO_STDARG */
|
||||
|
||||
#ifdef DONTDEF
|
||||
void as_tsktsk(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an)
|
||||
char *format;
|
||||
{
|
||||
as_where();
|
||||
fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an);
|
||||
(void)putc('\n',stderr);
|
||||
} /* as_tsktsk() */
|
||||
#endif
|
||||
/*
|
||||
* a s _ w a r n ()
|
||||
*
|
||||
* Send to stderr a string (with bell) (JF: Bell is obnoxious!) as a warning, and locate warning
|
||||
* in input file(s).
|
||||
* Please only use this for when we have some recovery action.
|
||||
* Please explain in string (which may have '\n's) what recovery was done.
|
||||
*/
|
||||
|
||||
#ifndef NO_STDARG
|
||||
void as_warn(Format)
|
||||
const char *Format;
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if(!flagseen['W']) {
|
||||
++warning_count;
|
||||
as_where();
|
||||
va_start(args, Format);
|
||||
vfprintf(stderr, Format, args);
|
||||
va_end(args);
|
||||
(void) putc('\n', stderr);
|
||||
}
|
||||
} /* as_warn() */
|
||||
#else
|
||||
#ifndef NO_VARARGS
|
||||
void as_warn(Format,va_alist)
|
||||
char *Format;
|
||||
va_dcl
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if(!flagseen['W']) {
|
||||
++warning_count;
|
||||
as_where();
|
||||
va_start(args);
|
||||
vfprintf(stderr, Format, args);
|
||||
va_end(args);
|
||||
(void) putc('\n', stderr);
|
||||
}
|
||||
} /* as_warn() */
|
||||
#else
|
||||
/*VARARGS1 */
|
||||
as_warn(Format,args)
|
||||
char *Format;
|
||||
{
|
||||
/* -W supresses warning messages. */
|
||||
if (! flagseen ['W']) {
|
||||
++warning_count;
|
||||
as_where();
|
||||
_doprnt (Format, &args, stderr);
|
||||
(void)putc ('\n', stderr);
|
||||
/* as_where(); */
|
||||
}
|
||||
} /* as_warn() */
|
||||
#endif /* not NO_VARARGS */
|
||||
#endif /* not NO_STDARG */
|
||||
|
||||
#ifdef DONTDEF
|
||||
void as_warn(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an)
|
||||
char *format;
|
||||
{
|
||||
if(!flagseen['W']) {
|
||||
++warning_count;
|
||||
as_where();
|
||||
fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an);
|
||||
(void)putc('\n',stderr);
|
||||
}
|
||||
} /* as_warn() */
|
||||
#endif
|
||||
/*
|
||||
* a s _ b a d ()
|
||||
*
|
||||
* Send to stderr a string (with bell) (JF: Bell is obnoxious!) as a warning,
|
||||
* and locate warning in input file(s).
|
||||
* Please us when there is no recovery, but we want to continue processing
|
||||
* but not produce an object file.
|
||||
* Please explain in string (which may have '\n's) what recovery was done.
|
||||
*/
|
||||
|
||||
#ifndef NO_STDARG
|
||||
void as_bad(Format)
|
||||
const char *Format;
|
||||
{
|
||||
va_list args;
|
||||
|
||||
++error_count;
|
||||
as_where();
|
||||
va_start(args, Format);
|
||||
vfprintf(stderr, Format, args);
|
||||
va_end(args);
|
||||
(void) putc('\n', stderr);
|
||||
} /* as_bad() */
|
||||
#else
|
||||
#ifndef NO_VARARGS
|
||||
void as_bad(Format,va_alist)
|
||||
char *Format;
|
||||
va_dcl
|
||||
{
|
||||
va_list args;
|
||||
|
||||
++error_count;
|
||||
as_where();
|
||||
va_start(args);
|
||||
vfprintf(stderr, Format, args);
|
||||
va_end(args);
|
||||
(void) putc('\n', stderr);
|
||||
} /* as_bad() */
|
||||
#else
|
||||
/*VARARGS1 */
|
||||
as_bad(Format,args)
|
||||
char *Format;
|
||||
{
|
||||
++error_count;
|
||||
as_where();
|
||||
_doprnt (Format, &args, stderr);
|
||||
(void)putc ('\n', stderr);
|
||||
/* as_where(); */
|
||||
} /* as_bad() */
|
||||
#endif /* not NO_VARARGS */
|
||||
#endif /* not NO_STDARG */
|
||||
|
||||
#ifdef DONTDEF
|
||||
void as_bad(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an)
|
||||
char *format;
|
||||
{
|
||||
++error_count;
|
||||
as_where();
|
||||
fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an);
|
||||
(void)putc('\n',stderr);
|
||||
} /* as_bad() */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* a s _ f a t a l ()
|
||||
*
|
||||
* Send to stderr a string (with bell) (JF: Bell is obnoxious!) as a fatal
|
||||
* message, and locate stdsource in input file(s).
|
||||
* Please only use this for when we DON'T have some recovery action.
|
||||
* It exit()s with a warning status.
|
||||
*/
|
||||
|
||||
#ifndef NO_STDARG
|
||||
void as_fatal(Format)
|
||||
const char *Format;
|
||||
{
|
||||
va_list args;
|
||||
|
||||
as_where();
|
||||
va_start(args, Format);
|
||||
fprintf (stderr, "FATAL:");
|
||||
vfprintf(stderr, Format, args);
|
||||
(void) putc('\n', stderr);
|
||||
va_end(args);
|
||||
exit(42);
|
||||
} /* as_fatal() */
|
||||
#else
|
||||
#ifndef NO_VARARGS
|
||||
void as_fatal(Format,va_alist)
|
||||
char *Format;
|
||||
va_dcl
|
||||
{
|
||||
va_list args;
|
||||
|
||||
as_where();
|
||||
va_start(args);
|
||||
fprintf (stderr, "FATAL:");
|
||||
vfprintf(stderr, Format, args);
|
||||
(void) putc('\n', stderr);
|
||||
va_end(args);
|
||||
exit(42);
|
||||
} /* as_fatal() */
|
||||
#else
|
||||
/*VARARGS1 */
|
||||
as_fatal(Format, args)
|
||||
char *Format;
|
||||
{
|
||||
as_where();
|
||||
fprintf(stderr,"FATAL:");
|
||||
_doprnt (Format, &args, stderr);
|
||||
(void)putc ('\n', stderr);
|
||||
/* as_where(); */
|
||||
exit(42); /* What is a good exit status? */
|
||||
} /* as_fatal() */
|
||||
#endif /* not NO_VARARGS */
|
||||
#endif /* not NO_STDARG */
|
||||
|
||||
#ifdef DONTDEF
|
||||
void as_fatal(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an)
|
||||
char *Format;
|
||||
{
|
||||
as_where();
|
||||
fprintf (stderr, "FATAL:");
|
||||
fprintf(stderr, Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an);
|
||||
(void) putc('\n', stderr);
|
||||
exit(42);
|
||||
} /* as_fatal() */
|
||||
#endif
|
||||
|
||||
/* end: messages.c */
|
67
gas/obj.h
Normal file
67
gas/obj.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* obj.h - defines the object dependent hooks for all object
|
||||
format backends.
|
||||
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
char *obj_default_output_file_name(void);
|
||||
void obj_crawl_symbol_chain(object_headers *headers);
|
||||
void obj_emit_relocations(char **where, fixS *fixP, relax_addressT segment_address_in_file);
|
||||
void obj_emit_strings(char **where);
|
||||
void obj_emit_symbols(char **where, symbolS *symbol_rootP);
|
||||
void obj_header_append(char **where, object_headers *headers);
|
||||
void obj_read_begin_hook(void);
|
||||
void obj_symbol_new_hook(symbolS *symbolP);
|
||||
void obj_symbol_to_chars(char **where, symbolS *symbolP);
|
||||
|
||||
#ifndef obj_pre_write_hook
|
||||
void obj_pre_write_hook(object_headers *headers);
|
||||
#endif /* obj_pre_write_hook */
|
||||
|
||||
#else
|
||||
|
||||
char *obj_default_output_file_name();
|
||||
void obj_crawl_symbol_chain();
|
||||
void obj_emit_relocations();
|
||||
void obj_emit_strings();
|
||||
void obj_emit_symbols();
|
||||
void obj_header_append();
|
||||
void obj_read_begin_hook();
|
||||
void obj_symbol_new_hook();
|
||||
void obj_symbol_to_chars();
|
||||
|
||||
#ifndef obj_pre_write_hook
|
||||
void obj_pre_write_hook();
|
||||
#endif /* obj_pre_write_hook */
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
extern const pseudo_typeS obj_pseudo_table[];
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of obj.h */
|
83
gas/output-file.c
Normal file
83
gas/output-file.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* output-file.c - Deal with the output file
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
/*
|
||||
* Confines all details of emitting object bytes to this module.
|
||||
* All O/S specific crocks should live here.
|
||||
* What we lose in "efficiency" we gain in modularity.
|
||||
* Note we don't need to #include the "as.h" file. No common coupling!
|
||||
*/
|
||||
|
||||
/* note that we do need config info. xoxorich. */
|
||||
|
||||
/* #include "style.h" */
|
||||
#include <stdio.h>
|
||||
|
||||
#include "as.h"
|
||||
|
||||
#include "output-file.h"
|
||||
|
||||
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);
|
||||
}
|
||||
} /* output_file_create() */
|
||||
|
||||
|
||||
|
||||
void output_file_close(filename)
|
||||
char *filename;
|
||||
{
|
||||
if ( EOF == fclose( stdoutput ) )
|
||||
{
|
||||
as_perror ("FATAL: Can't close %s", filename);
|
||||
exit(42);
|
||||
}
|
||||
stdoutput = NULL; /* Trust nobody! */
|
||||
} /* output_file_close() */
|
||||
|
||||
void output_file_append(where, length, filename)
|
||||
char *where;
|
||||
long length;
|
||||
char *filename;
|
||||
{
|
||||
|
||||
for (; length; length--,where++)
|
||||
{
|
||||
(void)putc(*where,stdoutput);
|
||||
if(ferror(stdoutput))
|
||||
/* if ( EOF == (putc( *where, stdoutput )) ) */
|
||||
{
|
||||
as_perror("Failed to emit an object byte", filename);
|
||||
as_fatal("Can't continue");
|
||||
}
|
||||
}
|
||||
} /* output_file_append() */
|
||||
|
||||
/* end: output-file.c */
|
18
gas/output-file.h
Normal file
18
gas/output-file.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
void output_file_append(char *where, long length, char *filename);
|
||||
void output_file_close(char *filename);
|
||||
void output_file_create(char *name);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
void output_file_append();
|
||||
void output_file_close();
|
||||
void output_file_create();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
|
||||
/* end of output-file.h */
|
2281
gas/read.c
Normal file
2281
gas/read.c
Normal file
File diff suppressed because it is too large
Load diff
137
gas/read.h
Normal file
137
gas/read.h
Normal file
|
@ -0,0 +1,137 @@
|
|||
/* read.h - of read.c
|
||||
Copyright (C) 1986, 1990 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
extern char *input_line_pointer; /* -> char we are parsing now. */
|
||||
|
||||
#define PERMIT_WHITESPACE /* Define to make whitespace be allowed in */
|
||||
/* many syntactically unnecessary places. */
|
||||
/* Normally undefined. For compatibility */
|
||||
/* with ancient GNU cc. */
|
||||
#undef PERMIT_WHITESPACE
|
||||
|
||||
#ifdef PERMIT_WHITESPACE
|
||||
#define SKIP_WHITESPACE() {if (* input_line_pointer == ' ') ++ input_line_pointer;}
|
||||
#else
|
||||
#define SKIP_WHITESPACE() know(*input_line_pointer != ' ' )
|
||||
#endif
|
||||
|
||||
|
||||
#define LEX_NAME (1) /* may continue a name */
|
||||
#define LEX_BEGIN_NAME (2) /* may begin a name */
|
||||
|
||||
#define is_name_beginner(c) ( lex_type[c] & LEX_BEGIN_NAME )
|
||||
#define is_part_of_name(c) ( lex_type[c] & LEX_NAME )
|
||||
|
||||
#ifndef is_a_char
|
||||
#define CHAR_MASK (0xff)
|
||||
#define NOT_A_CHAR (CHAR_MASK+1)
|
||||
#define is_a_char(c) (((unsigned)(c)) <= CHAR_MASK)
|
||||
#endif /* is_a_char() */
|
||||
|
||||
extern const char lex_type[];
|
||||
extern char is_end_of_line[];
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
char *demand_copy_C_string(int *len_pointer);
|
||||
char get_absolute_expression_and_terminator(long *val_pointer);
|
||||
long get_absolute_expression(void);
|
||||
void add_include_dir(char *path);
|
||||
void big_cons(int nbytes);
|
||||
void cons(unsigned int nbytes);
|
||||
void demand_empty_rest_of_line(void);
|
||||
void equals(char *sym_name);
|
||||
void float_cons(int float_type);
|
||||
void ignore_rest_of_line(void);
|
||||
void pseudo_set(symbolS *symbolP);
|
||||
void read_a_source_file(char *name);
|
||||
void read_begin(void);
|
||||
void s_abort(void);
|
||||
void s_align_bytes(int arg);
|
||||
void s_align_ptwo(void);
|
||||
void s_app_file(void);
|
||||
void s_comm(void);
|
||||
void s_data(void);
|
||||
void s_else(int arg);
|
||||
void s_end(int arg);
|
||||
void s_endif(int arg);
|
||||
void s_fill(void);
|
||||
void s_globl(void);
|
||||
void s_if(int arg);
|
||||
void s_ifdef(int arg);
|
||||
void s_ifeqs(int arg);
|
||||
void s_ignore(int arg);
|
||||
void s_include(int arg);
|
||||
void s_lcomm(int needs_align);
|
||||
void s_lsym(void);
|
||||
void s_org(void);
|
||||
void s_set(void);
|
||||
void s_space(void);
|
||||
void s_text(void);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
char *demand_copy_C_string();
|
||||
char get_absolute_expression_and_terminator();
|
||||
long get_absolute_expression();
|
||||
void add_include_dir();
|
||||
void big_cons();
|
||||
void cons();
|
||||
void demand_empty_rest_of_line();
|
||||
void equals();
|
||||
void float_cons();
|
||||
void ignore_rest_of_line();
|
||||
void pseudo_set();
|
||||
void read_a_source_file();
|
||||
void read_begin();
|
||||
void s_abort();
|
||||
void s_align_bytes();
|
||||
void s_align_ptwo();
|
||||
void s_app_file();
|
||||
void s_comm();
|
||||
void s_data();
|
||||
void s_else();
|
||||
void s_end();
|
||||
void s_endif();
|
||||
void s_fill();
|
||||
void s_globl();
|
||||
void s_if();
|
||||
void s_ifdef();
|
||||
void s_ifeqs();
|
||||
void s_ignore();
|
||||
void s_include();
|
||||
void s_lcomm();
|
||||
void s_lsym();
|
||||
void s_org();
|
||||
void s_set();
|
||||
void s_space();
|
||||
void s_text();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end: read.h */
|
113
gas/struc-symbol.h
Normal file
113
gas/struc-symbol.h
Normal file
|
@ -0,0 +1,113 @@
|
|||
/* 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. */
|
||||
|
||||
struct symbol /* our version of an nlist node */
|
||||
{
|
||||
obj_symbol_type sy_symbol; /* what we write in .o file (if permitted) */
|
||||
unsigned long sy_name_offset; /* 4-origin position of sy_name in symbols */
|
||||
/* part of object file. */
|
||||
/* 0 for (nameless) .stabd symbols. */
|
||||
/* Not used until write_object_file() time. */
|
||||
long sy_number; /* 24 bit symbol number. */
|
||||
/* Symbol numbers start at 0 and are */
|
||||
/* unsigned. */
|
||||
struct symbol *sy_next; /* forward chain, or NULL */
|
||||
#ifdef SYMBOLS_NEED_BACKPOINTERS
|
||||
struct symbol *sy_previous; /* backward chain, or NULL */
|
||||
#endif /* SYMBOLS_NEED_BACKPOINTERS */
|
||||
struct frag *sy_frag; /* NULL or -> frag this symbol attaches to. */
|
||||
struct symbol *sy_forward; /* value is really that of this other symbol */
|
||||
/* We will probably want to add a sy_segment here soon. */
|
||||
};
|
||||
|
||||
typedef struct symbol symbolS;
|
||||
|
||||
typedef unsigned valueT; /* The type of n_value. Helps casting. */
|
||||
|
||||
#ifndef WORKING_DOT_WORD
|
||||
struct broken_word {
|
||||
struct broken_word *next_broken_word;/* One of these strucs per .word x-y */
|
||||
fragS *frag; /* Which frag its in */
|
||||
char *word_goes_here;/* Where in the frag it is */
|
||||
fragS *dispfrag; /* where to add the break */
|
||||
symbolS *add; /* symbol_x */
|
||||
symbolS *sub; /* - symbol_y */
|
||||
long addnum; /* + addnum */
|
||||
int added; /* nasty thing happend yet? */
|
||||
/* 1: added and has a long-jump */
|
||||
/* 2: added but uses someone elses long-jump */
|
||||
struct broken_word *use_jump; /* points to broken_word with a similar
|
||||
long-jump */
|
||||
};
|
||||
extern struct broken_word *broken_words;
|
||||
#endif /* ndef WORKING_DOT_WORD */
|
||||
|
||||
/*
|
||||
* Current means for getting from symbols to segments and vice verse.
|
||||
* This will change for infinite-segments support (e.g. COFF).
|
||||
*/
|
||||
/* #define SYMBOL_TYPE_TO_SEGMENT(symP) ( N_TYPE_seg [(int) (symP)->sy_type & N_TYPE] ) */
|
||||
extern segT N_TYPE_seg[]; /* subseg.c */
|
||||
|
||||
#define SEGMENT_TO_SYMBOL_TYPE(seg) ( seg_N_TYPE [(int) (seg)] )
|
||||
extern const short seg_N_TYPE[]; /* subseg.c */
|
||||
|
||||
#define N_REGISTER 30 /* Fake N_TYPE value for SEG_REGISTER */
|
||||
|
||||
#ifdef SYMBOLS_NEED_BACKPOINTERS
|
||||
#ifdef __STDC__
|
||||
|
||||
void symbol_clear_list_pointers(symbolS *symbolP);
|
||||
void symbol_insert(symbolS *addme, symbolS *target, symbolS **rootP, symbolS **lastP);
|
||||
void symbol_remove(symbolS *symbolP, symbolS **rootP, symbolS **lastP);
|
||||
void verify_symbol_chain(symbolS *rootP, symbolS *lastP);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
void symbol_clear_list_pointers();
|
||||
void symbol_insert();
|
||||
void symbol_remove();
|
||||
void verify_symbol_chain();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#define symbol_previous(s) ((s)->sy_previous)
|
||||
|
||||
#else /* SYMBOLS_NEED_BACKPOINTERS */
|
||||
|
||||
#define symbol_clear_list_pointers(clearme) {clearme->sy_next = NULL;}
|
||||
|
||||
#endif /* SYMBOLS_NEED_BACKPOINTERS */
|
||||
|
||||
#ifdef __STDC__
|
||||
void symbol_append(symbolS *addme, symbolS *target, symbolS **rootP, symbolS **lastP);
|
||||
#else /* __STDC__ */
|
||||
void symbol_append();
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#define symbol_next(s) ((s)->sy_next)
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of struc-symbol.h */
|
279
gas/subsegs.c
Normal file
279
gas/subsegs.c
Normal file
|
@ -0,0 +1,279 @@
|
|||
/* subsegs.c - subsegments -
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
/*
|
||||
* Segments & sub-segments.
|
||||
*/
|
||||
|
||||
#include "as.h"
|
||||
|
||||
#include "subsegs.h"
|
||||
#include "obstack.h"
|
||||
|
||||
frchainS* frchain_root,
|
||||
* frchain_now, /* Commented in "subsegs.h". */
|
||||
* data0_frchainP;
|
||||
|
||||
|
||||
char * const /* in: segT out: char* */
|
||||
seg_name[] = {
|
||||
"absolute",
|
||||
"text",
|
||||
"data",
|
||||
"bss",
|
||||
"unknown",
|
||||
"absent",
|
||||
"pass1",
|
||||
"ASSEMBLER-INTERNAL-LOGIC-ERROR!",
|
||||
"bignum/flonum",
|
||||
"difference",
|
||||
"debug",
|
||||
"transfert vector preload",
|
||||
"transfert vector postload",
|
||||
"register",
|
||||
"",
|
||||
}; /* Used by error reporters, dumpers etc. */
|
||||
|
||||
|
||||
void
|
||||
subsegs_begin()
|
||||
{
|
||||
/* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */
|
||||
know( SEG_ABSOLUTE == 0 );
|
||||
know( SEG_TEXT == 1 );
|
||||
know( SEG_DATA == 2 );
|
||||
know( SEG_BSS == 3 );
|
||||
know( SEG_UNKNOWN == 4 );
|
||||
know( SEG_ABSENT == 5 );
|
||||
know( SEG_PASS1 == 6 );
|
||||
know( SEG_GOOF == 7 );
|
||||
know( SEG_BIG == 8 );
|
||||
know( SEG_DIFFERENCE == 9 );
|
||||
know( SEG_DEBUG == 10 );
|
||||
know( SEG_NTV == 11 );
|
||||
know( SEG_PTV == 12 );
|
||||
know( SEG_REGISTER == 13 );
|
||||
know( SEG_MAXIMUM_ORDINAL == SEG_REGISTER );
|
||||
know( segment_name (SEG_MAXIMUM_ORDINAL + 1) [0] == 0 );
|
||||
|
||||
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;
|
||||
seg_fix_tailP = & data_fix_tail;
|
||||
}
|
||||
else
|
||||
{
|
||||
know (seg == SEG_TEXT);
|
||||
seg_fix_rootP = & text_fix_root;
|
||||
seg_fix_tailP = & text_fix_tail;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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() */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end: subsegs.c */
|
65
gas/subsegs.h
Normal file
65
gas/subsegs.h
Normal file
|
@ -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 */
|
614
gas/symbols.c
Normal file
614
gas/symbols.c
Normal file
|
@ -0,0 +1,614 @@
|
|||
/* symbols.c -symbol table-
|
||||
Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
#include "as.h"
|
||||
|
||||
#include "obstack.h" /* For "symbols.h" */
|
||||
#include "subsegs.h"
|
||||
|
||||
#ifndef WORKING_DOT_WORD
|
||||
extern int new_broken_words;
|
||||
#endif
|
||||
#ifdef VMS
|
||||
extern char const_flag;
|
||||
#endif
|
||||
|
||||
static
|
||||
struct hash_control *
|
||||
sy_hash; /* symbol-name => struct symbol pointer */
|
||||
|
||||
/* Below are commented in "symbols.h". */
|
||||
unsigned int local_bss_counter;
|
||||
symbolS * symbol_rootP;
|
||||
symbolS * symbol_lastP;
|
||||
symbolS abs_symbol;
|
||||
|
||||
symbolS* dot_text_symbol;
|
||||
symbolS* dot_data_symbol;
|
||||
symbolS* dot_bss_symbol;
|
||||
|
||||
struct obstack notes;
|
||||
|
||||
/*
|
||||
* Un*x idea of local labels. They are made by "n:" where n
|
||||
* is any decimal digit. Refer to them with
|
||||
* "nb" for previous (backward) n:
|
||||
* or "nf" for next (forward) n:.
|
||||
*
|
||||
* Like Un*x AS, we have one set of local label counters for entire assembly,
|
||||
* not one set per (sub)segment like in most assemblers. This implies that
|
||||
* one can refer to a label in another segment, and indeed some crufty
|
||||
* compilers have done just that.
|
||||
*
|
||||
* I document the symbol names here to save duplicating words elsewhere.
|
||||
* The mth occurence of label n: is turned into the symbol "Ln^Am" where
|
||||
* n is a digit and m is a decimal number. "L" makes it a label discarded
|
||||
* unless debugging and "^A"('\1') ensures no ordinary symbol SHOULD get the
|
||||
* same name as a local label symbol. The first "4:" is "L4^A1" - the m
|
||||
* numbers begin at 1.
|
||||
*/
|
||||
|
||||
typedef short unsigned int
|
||||
local_label_countT;
|
||||
|
||||
static local_label_countT
|
||||
local_label_counter[10];
|
||||
|
||||
static /* Returned to caller, then copied. */
|
||||
char symbol_name_build[12]; /* used for created names ("4f") */
|
||||
|
||||
#ifdef LOCAL_LABELS_DOLLAR
|
||||
int local_label_defined[10];
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
symbol_begin()
|
||||
{
|
||||
symbol_lastP = NULL;
|
||||
symbol_rootP = NULL; /* In case we have 0 symbols (!!) */
|
||||
sy_hash = hash_new();
|
||||
bzero ((char *)(& abs_symbol), sizeof(abs_symbol));
|
||||
S_SET_SEGMENT(&abs_symbol, SEG_ABSOLUTE); /* 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 ) != '\0') ;;
|
||||
|
||||
/* The label, as a '\0' ended string, starts at symbol_name_build. */
|
||||
return(symbol_name_build);
|
||||
} /* local_label_name() */
|
||||
|
||||
|
||||
void local_colon (n)
|
||||
int n; /* just saw "n:" */
|
||||
{
|
||||
local_label_counter [n] ++;
|
||||
#ifdef LOCAL_LABELS_DOLLAR
|
||||
local_label_defined[n]=1;
|
||||
#endif
|
||||
colon (local_label_name (n, 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* symbol_new()
|
||||
*
|
||||
* Return a pointer to a new symbol.
|
||||
* Die if we can't make a new symbol.
|
||||
* Fill in the symbol's values.
|
||||
* Add symbol to end of symbol chain.
|
||||
*
|
||||
*
|
||||
* Please always call this to create a new symbol.
|
||||
*
|
||||
* Changes since 1985: Symbol names may not contain '\0'. Sigh.
|
||||
* 2nd argument is now a SEG rather than a TYPE. The mapping between
|
||||
* segments and types is mostly encapsulated herein (actually, we inherit it
|
||||
* from macros in struc-symbol.h).
|
||||
*/
|
||||
|
||||
symbolS *symbol_new(name, segment, value, frag)
|
||||
char *name; /* It is copied, the caller can destroy/modify */
|
||||
segT segment; /* Segment identifier (SEG_<something>) */
|
||||
long value; /* Symbol value */
|
||||
fragS *frag; /* Associated fragment */
|
||||
{
|
||||
unsigned int name_length;
|
||||
char *preserved_copy_of_name;
|
||||
symbolS *symbolP;
|
||||
|
||||
name_length = strlen(name) + 1; /* +1 for \0 */
|
||||
obstack_grow(¬es, name, name_length);
|
||||
preserved_copy_of_name = obstack_finish(¬es);
|
||||
symbolP = (symbolS *)obstack_alloc(¬es, sizeof(symbolS));
|
||||
|
||||
#if STRIP_UNDERSCORE
|
||||
S_SET_NAME(symbolP, (*preserved_copy_of_name == '_'
|
||||
? preserved_copy_of_name + 1
|
||||
: preserved_copy_of_name));
|
||||
#else /* STRIP_UNDERSCORE */
|
||||
S_SET_NAME(symbolP, preserved_copy_of_name);
|
||||
#endif /* STRIP_UNDERSCORE */
|
||||
|
||||
S_SET_SEGMENT(symbolP, segment);
|
||||
S_SET_VALUE(symbolP, value);
|
||||
symbol_clear_list_pointers(symbolP);
|
||||
|
||||
symbolP->sy_frag = frag;
|
||||
symbolP->sy_forward = NULL; /* JF */
|
||||
symbolP->sy_number = ~0;
|
||||
symbolP->sy_name_offset = ~0;
|
||||
|
||||
/*
|
||||
* Link to end of symbol chain.
|
||||
*/
|
||||
symbol_append(symbolP, symbol_lastP, &symbol_rootP, &symbol_lastP);
|
||||
|
||||
obj_symbol_new_hook(symbolP);
|
||||
|
||||
#ifdef DEBUG
|
||||
verify_symbol_chain(symbol_rootP, symbol_lastP);
|
||||
#endif /* DEBUG */
|
||||
|
||||
return(symbolP);
|
||||
} /* symbol_new() */
|
||||
|
||||
|
||||
/*
|
||||
* colon()
|
||||
*
|
||||
* We have just seen "<name>:".
|
||||
* Creates a struct symbol unless it already exists.
|
||||
*
|
||||
* Gripes if we are redefining a symbol incompatibly (and ignores it).
|
||||
*
|
||||
*/
|
||||
void colon(sym_name) /* just seen "x:" - rattle symbols & frags */
|
||||
register char * sym_name; /* symbol name, as a cannonical string */
|
||||
/* We copy this string: OK to alter later. */
|
||||
{
|
||||
register symbolS * symbolP; /* symbol we are working with */
|
||||
|
||||
#ifdef LOCAL_LABELS_DOLLAR
|
||||
/* Sun local labels go out of scope whenever a non-local symbol is defined. */
|
||||
|
||||
if(*sym_name !='L')
|
||||
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,
|
||||
0L,
|
||||
NULL);
|
||||
|
||||
/* We want to store the pointer to where to insert the jump table in the
|
||||
fr_opcode of the rs_broken_word frag. This requires a little hackery */
|
||||
while(frag_tmp && (frag_tmp->fr_type!=rs_broken_word || frag_tmp->fr_opcode))
|
||||
frag_tmp=frag_tmp->fr_next;
|
||||
know(frag_tmp);
|
||||
frag_tmp->fr_opcode=frag_opcode;
|
||||
new_broken_words = 0;
|
||||
|
||||
for(a=broken_words;a && a->dispfrag==0;a=a->next_broken_word)
|
||||
a->dispfrag=frag_tmp;
|
||||
}
|
||||
#endif
|
||||
if ((symbolP = symbol_find(sym_name)) != 0) {
|
||||
#ifdef VMS
|
||||
/*
|
||||
* If the new symbol is .comm AND it has a size of zero,
|
||||
* we ignore it (i.e. the old symbol overrides it)
|
||||
*/
|
||||
if ((SEGMENT_TO_SYMBOL_TYPE((int) now_seg) == (N_UNDF | N_EXT)) &&
|
||||
((obstack_next_free(& frags) - frag_now->fr_literal) == 0))
|
||||
return;
|
||||
/*
|
||||
* If the old symbol is .comm and it has a size of zero,
|
||||
* we override it with the new symbol value.
|
||||
*/
|
||||
if ((symbolP->sy_type == (N_UNDF | N_EXT))
|
||||
&& (S_GET_VALUE(symbolP) == 0)) {
|
||||
symbolP->sy_frag = frag_now;
|
||||
symbolP->sy_other = const_flag;
|
||||
S_SET_VALUE(symbolP, obstack_next_free(& frags) - frag_now->fr_literal);
|
||||
symbolP->sy_type |= SEGMENT_TO_SYMBOL_TYPE((int) now_seg); /* keep N_EXT bit */
|
||||
return;
|
||||
}
|
||||
#endif /* VMS */
|
||||
/*
|
||||
* Now check for undefined symbols
|
||||
*/
|
||||
if (!S_IS_DEFINED(symbolP)) {
|
||||
if (S_GET_VALUE(symbolP) == 0) {
|
||||
symbolP->sy_frag = frag_now;
|
||||
#ifdef VMS
|
||||
symbolP->sy_other = const_flag;
|
||||
#endif
|
||||
S_SET_VALUE(symbolP, obstack_next_free(&frags) - frag_now->fr_literal);
|
||||
S_SET_SEGMENT(symbolP, now_seg);
|
||||
#ifdef N_UNDF
|
||||
know(N_UNDF == 0);
|
||||
#endif /* if we have one, it better be zero. */
|
||||
|
||||
} else {
|
||||
/*
|
||||
* There are still several cases to check:
|
||||
* A .comm/.lcomm symbol being redefined as
|
||||
* initialized data is OK
|
||||
* A .comm/.lcomm symbol being redefined with
|
||||
* a larger size is also OK
|
||||
*
|
||||
* This only used to be allowed on VMS gas, but Sun cc
|
||||
* on the sparc also depends on it.
|
||||
*/
|
||||
char New_Type = SEGMENT_TO_SYMBOL_TYPE((int) now_seg);
|
||||
|
||||
if (((!S_IS_DEBUG(symbolP) && !S_IS_DEFINED(symbolP) && S_IS_EXTERNAL(symbolP))
|
||||
|| (S_GET_SEGMENT(symbolP) == SEG_BSS))
|
||||
&& ((now_seg == SEG_DATA)
|
||||
|| (now_seg == S_GET_SEGMENT(symbolP)))) {
|
||||
/*
|
||||
* Select which of the 2 cases this is
|
||||
*/
|
||||
if (now_seg != SEG_DATA) {
|
||||
/*
|
||||
* New .comm for prev .comm symbol.
|
||||
* If the new size is larger we just
|
||||
* change its value. If the new size
|
||||
* is smaller, we ignore this symbol
|
||||
*/
|
||||
if (S_GET_VALUE(symbolP)
|
||||
< ((unsigned) (obstack_next_free(& frags) - frag_now->fr_literal))) {
|
||||
S_SET_VALUE(symbolP,
|
||||
obstack_next_free(& frags) -
|
||||
frag_now->fr_literal);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* It is a .comm/.lcomm being converted
|
||||
* to initialized data.
|
||||
*/
|
||||
symbolP->sy_frag = frag_now;
|
||||
#ifdef VMS
|
||||
symbolP->sy_other = const_flag;
|
||||
#endif /* VMS */
|
||||
S_SET_VALUE(symbolP, obstack_next_free(& frags) - frag_now->fr_literal);
|
||||
S_SET_SEGMENT(symbolP, now_seg); /* keep N_EXT bit */
|
||||
}
|
||||
} else {
|
||||
#ifdef OBJ_COFF
|
||||
as_fatal("Symbol \"%s\" is already defined as \"%s\"/%d.",
|
||||
sym_name,
|
||||
segment_name(S_GET_SEGMENT(symbolP)),
|
||||
S_GET_VALUE(symbolP));
|
||||
#else /* OBJ_COFF */
|
||||
as_fatal("Symbol \"%s\" is already defined as \"%s\"/%d.%d.%d.",
|
||||
sym_name,
|
||||
segment_name(S_GET_SEGMENT(symbolP)),
|
||||
S_GET_OTHER(symbolP), S_GET_DESC(symbolP),
|
||||
S_GET_VALUE(symbolP));
|
||||
#endif /* OBJ_COFF */
|
||||
}
|
||||
} /* if the undefined symbol has no value */
|
||||
} else {
|
||||
as_fatal("Symbol %s already defined.", sym_name);
|
||||
} /* if this symbol is not yet defined */
|
||||
|
||||
} else {
|
||||
symbolP = symbol_new(sym_name,
|
||||
now_seg,
|
||||
(valueT)(obstack_next_free(&frags)-frag_now->fr_literal),
|
||||
frag_now);
|
||||
#ifdef VMS
|
||||
S_SET_OTHER(symbolP, const_flag);
|
||||
#endif /* VMS */
|
||||
|
||||
symbol_table_insert(symbolP);
|
||||
} /* if we have seen this symbol before */
|
||||
|
||||
return;
|
||||
} /* colon() */
|
||||
|
||||
|
||||
/*
|
||||
* symbol_table_insert()
|
||||
*
|
||||
* Die if we can't insert the symbol.
|
||||
*
|
||||
*/
|
||||
|
||||
void symbol_table_insert(symbolP)
|
||||
symbolS *symbolP;
|
||||
{
|
||||
register char *error_string;
|
||||
|
||||
know(symbolP);
|
||||
know(S_GET_NAME(symbolP));
|
||||
|
||||
if (*(error_string = hash_jam(sy_hash, S_GET_NAME(symbolP), (char *)symbolP))) {
|
||||
as_fatal("Inserting \"%s\" into symbol table failed: %s",
|
||||
S_GET_NAME(symbolP), error_string);
|
||||
} /* on error */
|
||||
} /* symbol_table_insert() */
|
||||
|
||||
/*
|
||||
* symbol_find_or_make()
|
||||
*
|
||||
* If a symbol name does not exist, create it as undefined, and insert
|
||||
* it into the symbol table. Return a pointer to it.
|
||||
*/
|
||||
symbolS *symbol_find_or_make(name)
|
||||
char *name;
|
||||
{
|
||||
register symbolS *symbolP;
|
||||
|
||||
symbolP = symbol_find(name);
|
||||
|
||||
if (symbolP == NULL) {
|
||||
symbolP = symbol_make(name);
|
||||
|
||||
symbol_table_insert(symbolP);
|
||||
} /* if symbol wasn't found */
|
||||
|
||||
return(symbolP);
|
||||
} /* symbol_find_or_make() */
|
||||
|
||||
symbolS *symbol_make(name)
|
||||
char *name;
|
||||
{
|
||||
symbolS *symbolP;
|
||||
|
||||
/* Let the machine description default it, e.g. for register names. */
|
||||
symbolP = md_undefined_symbol(name);
|
||||
|
||||
if (!symbolP) {
|
||||
symbolP = symbol_new(name,
|
||||
SEG_UNKNOWN,
|
||||
0,
|
||||
&zero_address_frag);
|
||||
} /* if md didn't build us a symbol */
|
||||
|
||||
return(symbolP);
|
||||
} /* symbol_make() */
|
||||
|
||||
/*
|
||||
* symbol_find()
|
||||
*
|
||||
* Implement symbol table lookup.
|
||||
* In: A symbol's name as a string: '\0' can't be part of a symbol name.
|
||||
* Out: NULL if the name was not in the symbol table, else the address
|
||||
* of a struct symbol associated with that name.
|
||||
*/
|
||||
|
||||
symbolS *symbol_find(name)
|
||||
char *name;
|
||||
{
|
||||
#ifndef STRIP_UNDERSCORE
|
||||
#define STRIP_UNDERSCORE 0
|
||||
#endif /* STRIP_UNDERSCORE */
|
||||
return symbol_find_base(name, STRIP_UNDERSCORE);
|
||||
}
|
||||
|
||||
symbolS *symbol_find_base(name, strip_underscore)
|
||||
char *name;
|
||||
int strip_underscore;
|
||||
{
|
||||
if(strip_underscore && *name == '_') name++;
|
||||
return ( (symbolS *) hash_find( sy_hash, name ));
|
||||
}
|
||||
|
||||
/*
|
||||
* Once upon a time, symbols were kept in a singly linked list. At
|
||||
* least coff needs to be able to rearrange them from time to time, for
|
||||
* which a doubly linked list is much more convenient. Loic did these
|
||||
* as macros which seemed dangerous to me so they're now functions.
|
||||
* xoxorich.
|
||||
*/
|
||||
|
||||
/* Link symbol ADDME after symbol TARGET in the chain. */
|
||||
void symbol_append(addme, target, rootPP, lastPP)
|
||||
symbolS *addme;
|
||||
symbolS *target;
|
||||
symbolS **rootPP;
|
||||
symbolS **lastPP;
|
||||
{
|
||||
if (target == NULL) {
|
||||
know(*rootPP == NULL);
|
||||
know(*lastPP == NULL);
|
||||
*rootPP = addme;
|
||||
*lastPP = addme;
|
||||
return;
|
||||
} /* if the list is empty */
|
||||
|
||||
if (target->sy_next != NULL) {
|
||||
#ifdef SYMBOLS_NEED_BACKPOINTERS
|
||||
target->sy_next->sy_previous = addme;
|
||||
#endif /* SYMBOLS_NEED_BACKPOINTERS */
|
||||
} else {
|
||||
know(*lastPP == target);
|
||||
*lastPP = addme;
|
||||
} /* if we have a next */
|
||||
|
||||
addme->sy_next = target->sy_next;
|
||||
target->sy_next = addme;
|
||||
|
||||
#ifdef SYMBOLS_NEED_BACKPOINTERS
|
||||
addme->sy_previous = target;
|
||||
#endif /* SYMBOLS_NEED_BACKPOINTERS */
|
||||
|
||||
#ifdef DEBUG
|
||||
verify_symbol_chain(*rootPP, *lastPP);
|
||||
#endif /* DEBUG */
|
||||
|
||||
return;
|
||||
} /* symbol_append() */
|
||||
|
||||
#ifdef SYMBOLS_NEED_BACKPOINTERS
|
||||
/* Remove SYMBOLP from the list. */
|
||||
void symbol_remove(symbolP, rootPP, lastPP)
|
||||
symbolS *symbolP;
|
||||
symbolS **rootPP;
|
||||
symbolS **lastPP;
|
||||
{
|
||||
if (symbolP == *rootPP) {
|
||||
*rootPP = symbolP->sy_next;
|
||||
} /* if it was the root */
|
||||
|
||||
if (symbolP == *lastPP) {
|
||||
*lastPP = symbolP->sy_previous;
|
||||
} /* if it was the tail */
|
||||
|
||||
if (symbolP->sy_next != NULL) {
|
||||
symbolP->sy_next->sy_previous = symbolP->sy_previous;
|
||||
} /* if not last */
|
||||
|
||||
if (symbolP->sy_previous != NULL) {
|
||||
symbolP->sy_previous->sy_next = symbolP->sy_next;
|
||||
} /* if not first */
|
||||
|
||||
#ifdef DEBUG
|
||||
verify_symbol_chain(*rootPP, *lastPP);
|
||||
#endif /* DEBUG */
|
||||
|
||||
return;
|
||||
} /* symbol_remove() */
|
||||
|
||||
/* Set the chain pointers of SYMBOL to null. */
|
||||
void symbol_clear_list_pointers(symbolP)
|
||||
symbolS *symbolP;
|
||||
{
|
||||
symbolP->sy_next = NULL;
|
||||
symbolP->sy_previous = NULL;
|
||||
} /* symbol_clear_list_pointers() */
|
||||
|
||||
/* Link symbol ADDME before symbol TARGET in the chain. */
|
||||
void symbol_insert(addme, target, rootPP, lastPP)
|
||||
symbolS *addme;
|
||||
symbolS *target;
|
||||
symbolS **rootPP;
|
||||
symbolS **lastPP;
|
||||
{
|
||||
if (target->sy_previous != NULL) {
|
||||
target->sy_previous->sy_next = addme;
|
||||
} else {
|
||||
know(*rootPP == target);
|
||||
*rootPP = addme;
|
||||
} /* if not first */
|
||||
|
||||
addme->sy_previous = target->sy_previous;
|
||||
target->sy_previous = addme;
|
||||
addme->sy_next = target;
|
||||
|
||||
#ifdef DEBUG
|
||||
verify_symbol_chain(*rootPP, *lastPP);
|
||||
#endif /* DEBUG */
|
||||
|
||||
return;
|
||||
} /* symbol_insert() */
|
||||
#endif /* SYMBOLS_NEED_BACKPOINTERS */
|
||||
|
||||
void verify_symbol_chain(rootP, lastP)
|
||||
symbolS *rootP;
|
||||
symbolS *lastP;
|
||||
{
|
||||
symbolS *symbolP = rootP;
|
||||
|
||||
if (symbolP == NULL) {
|
||||
return;
|
||||
} /* empty chain */
|
||||
|
||||
for ( ; symbol_next(symbolP) != NULL; symbolP = symbol_next(symbolP)) {
|
||||
#ifdef SYMBOLS_NEED_BACKPOINTERS
|
||||
/*$if (symbolP->sy_previous) {
|
||||
know(symbolP->sy_previous->sy_next == symbolP);
|
||||
} else {
|
||||
know(symbolP == rootP);
|
||||
}$*/ /* both directions */
|
||||
know(symbolP->sy_next->sy_previous == symbolP);
|
||||
#else /* SYMBOLS_NEED_BACKPOINTERS */
|
||||
;
|
||||
#endif /* SYMBOLS_NEED_BACKPOINTERS */
|
||||
} /* verify pointers */
|
||||
|
||||
know(lastP == symbolP);
|
||||
|
||||
return;
|
||||
} /* verify_symbol_chain() */
|
||||
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end: symbols.c */
|
77
gas/symbols.h
Normal file
77
gas/symbols.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* symbols.h -
|
||||
Copyright (C) 1987, 1990 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
extern struct obstack notes; /* eg FixS live here. */
|
||||
|
||||
extern struct obstack cond_obstack; /* this is where we track .ifdef/.endif
|
||||
(if we do that at all). */
|
||||
|
||||
extern unsigned int local_bss_counter; /* Zeroed before a pass. */
|
||||
/* Only used by .lcomm directive. */
|
||||
|
||||
extern symbolS * symbol_rootP; /* all the symbol nodes */
|
||||
extern symbolS * symbol_lastP; /* last struct symbol we made, or NULL */
|
||||
|
||||
extern symbolS abs_symbol;
|
||||
|
||||
extern symbolS* dot_text_symbol;
|
||||
extern symbolS* dot_data_symbol;
|
||||
extern symbolS* dot_bss_symbol;
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
char *local_label_name(int n, int augend);
|
||||
symbolS *symbol_find(char *name);
|
||||
symbolS *symbol_find_base(char *name, int strip_underscore);
|
||||
symbolS *symbol_find_or_make(char *name);
|
||||
symbolS *symbol_make(char *name);
|
||||
symbolS *symbol_new(char *name, segT segment, long value, fragS *frag);
|
||||
void colon(char *sym_name);
|
||||
void local_colon(int n);
|
||||
void symbol_begin(void);
|
||||
void symbol_table_insert(symbolS *symbolP);
|
||||
void verify_symbol_chain(symbolS *rootP, symbolS *lastP);
|
||||
|
||||
#else
|
||||
|
||||
char *local_label_name();
|
||||
symbolS *symbol_find();
|
||||
symbolS *symbol_find_base();
|
||||
symbolS *symbol_find_or_make();
|
||||
symbolS *symbol_make();
|
||||
symbolS *symbol_new();
|
||||
void colon();
|
||||
void local_colon();
|
||||
void symbol_begin();
|
||||
void symbol_table_insert();
|
||||
void verify_symbol_chain();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end: symbols.h */
|
112
gas/tc.h
Normal file
112
gas/tc.h
Normal file
|
@ -0,0 +1,112 @@
|
|||
/* tc.h -target cpu dependent- */
|
||||
|
||||
/* Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* static const char rcsid[] = "$Id$"; */
|
||||
|
||||
/* In theory (mine, at least!) the machine dependent part of the assembler
|
||||
should only have to include one file. This one. -- JF */
|
||||
|
||||
extern const pseudo_typeS md_pseudo_table[];
|
||||
|
||||
/* JF moved this here from as.h under the theory that nobody except MACHINE.c
|
||||
and write.c care about it anyway. */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
long rlx_forward; /* Forward reach. Signed number. > 0. */
|
||||
long rlx_backward; /* Backward reach. Signed number. < 0. */
|
||||
unsigned char rlx_length; /* Bytes length of this address. */
|
||||
relax_substateT rlx_more; /* Next longer relax-state. */
|
||||
/* 0 means there is no 'next' relax-state. */
|
||||
}
|
||||
relax_typeS;
|
||||
|
||||
extern const relax_typeS md_relax_table[]; /* Define it in MACHINE.c */
|
||||
|
||||
extern int md_reloc_size; /* Size of a relocation record */
|
||||
|
||||
extern void (*md_emit_relocations)();
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
char *md_atof(int what_statement_type, char *literalP, int *sizeP);
|
||||
int md_estimate_size_before_relax(fragS *fragP, segT segtype);
|
||||
int md_parse_option(char **argP, int *cntP, char ***vecP);
|
||||
long md_pcrel_from(fixS *fixP);
|
||||
long md_section_align(segT seg, long align);
|
||||
short tc_coff_fix2rtype(fixS *fixP);
|
||||
symbolS *md_undefined_symbol(char *name);
|
||||
void md_apply_fix(fixS *fixP, long val);
|
||||
void md_assemble(char *str);
|
||||
void md_begin(void);
|
||||
void md_convert_frag(fragS *fragP);
|
||||
void md_create_long_jump(char *ptr, long from_addr, long to_addr, fragS *frag, symbolS *to_symbol);
|
||||
void md_create_short_jump(char *ptr, long from_addr, long to_addr, fragS *frag, symbolS *to_symbol);
|
||||
void md_end(void);
|
||||
void md_number_to_chars(char *buf, long val, int n);
|
||||
void md_operand(expressionS *expressionP);
|
||||
void md_ri_to_chars(char *the_bytes, struct reloc_info_generic *ri);
|
||||
|
||||
#ifndef tc_crawl_symbol_chain
|
||||
void tc_crawl_symbol_chain(object_headers *headers);
|
||||
#endif /* tc_crawl_symbol_chain */
|
||||
|
||||
#ifndef tc_headers_hook
|
||||
void tc_headers_hook(object_headers *headers);
|
||||
#endif /* tc_headers_hook */
|
||||
|
||||
#else
|
||||
|
||||
char *md_atof();
|
||||
int md_estimate_size_before_relax();
|
||||
int md_parse_option();
|
||||
long md_pcrel_from();
|
||||
long md_section_align();
|
||||
short tc_coff_fix2rtype();
|
||||
symbolS *md_undefined_symbol();
|
||||
void md_apply_fix();
|
||||
void md_assemble();
|
||||
void md_begin();
|
||||
void md_convert_frag();
|
||||
void md_create_long_jump();
|
||||
void md_create_short_jump();
|
||||
void md_end();
|
||||
void md_number_to_chars();
|
||||
void md_operand();
|
||||
void md_ri_to_chars();
|
||||
|
||||
#ifndef tc_headers_hook
|
||||
void tc_headers_hook();
|
||||
#endif /* tc_headers_hook */
|
||||
|
||||
#ifndef tc_crawl_symbol_chain
|
||||
void tc_crawl_symbol_chain();
|
||||
#endif /* tc_crawl_symbol_chain */
|
||||
|
||||
#endif /* __STDC_ */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of tp.h */
|
1162
gas/write.c
Normal file
1162
gas/write.c
Normal file
File diff suppressed because it is too large
Load diff
130
gas/write.h
Normal file
130
gas/write.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
/* write.h -> write.c */
|
||||
|
||||
/* MODIFIED BY CHRIS BENENATI, FOR INTEL CORPORATION, 4/89 */
|
||||
/* 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. */
|
||||
|
||||
#ifndef TC_I960
|
||||
#ifdef hpux
|
||||
#define EXEC_MACHINE_TYPE HP9000S200_ID
|
||||
#endif
|
||||
#endif /* TC_I960 */
|
||||
|
||||
#ifndef LOCAL_LABEL
|
||||
#ifdef DOT_LABEL_PREFIX
|
||||
#define LOCAL_LABEL(name) (name[0] =='.' \
|
||||
&& ( name [1] == 'L' || name [1] == '.' ))
|
||||
#else /* not defined DOT_LABEL_PREFIX */
|
||||
#define LOCAL_LABEL(name) (name [0] == 'L' )
|
||||
#endif /* not defined DOT_LABEL_PREFIX */
|
||||
#endif /* LOCAL_LABEL */
|
||||
|
||||
#define S_LOCAL_NAME(s) (LOCAL_LABEL(S_GET_NAME(s)))
|
||||
|
||||
/* 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 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 fx_offset; /* Absolute number we add in. */
|
||||
struct fix * fx_next; /* NULL or -> next fixS. */
|
||||
short int fx_size; /* How many bytes are involved? */
|
||||
char fx_pcrel; /* TRUE: pc-relative. */
|
||||
char fx_pcrel_adjust;/* pc-relative offset adjust */
|
||||
char fx_im_disp; /* TRUE: value is a displacement */
|
||||
bit_fixS * fx_bit_fixP; /* IF NULL no bitfix's to do */
|
||||
char fx_bsr; /* sequent-hack */
|
||||
enum reloc_type fx_r_type; /* Sparc hacks */
|
||||
char fx_callj; /* TRUE if target is a 'callj'
|
||||
(used by i960) */
|
||||
long fx_addnumber;
|
||||
};
|
||||
|
||||
typedef struct fix fixS;
|
||||
|
||||
COMMON char *next_object_file_charP;
|
||||
|
||||
COMMON fixS *text_fix_root, *text_fix_tail; /* Chains fixSs. */
|
||||
COMMON fixS *data_fix_root, *data_fix_tail; /* Chains fixSs. */
|
||||
COMMON fixS **seg_fix_rootP, **seg_fix_tailP; /* -> one of above. */
|
||||
extern long string_byte_count;
|
||||
extern int section_alignment[];
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
bit_fixS *bit_fix_new(char size, char offset, long base_type, long base_adj, long min, long max, long add);
|
||||
void append(char **charPP, char *fromP, unsigned long length);
|
||||
void record_alignment(segT seg, int align);
|
||||
void write_object_file(void);
|
||||
|
||||
fixS *fix_new(fragS *frag,
|
||||
int where,
|
||||
int size,
|
||||
symbolS *add_symbol,
|
||||
symbolS *sub_symbol,
|
||||
long offset,
|
||||
int pcrel,
|
||||
enum reloc_type r_type);
|
||||
|
||||
#else
|
||||
|
||||
bit_fixS *bit_fix_new();
|
||||
fixS *fix_new();
|
||||
void append();
|
||||
void record_alignment();
|
||||
void write_object_file();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* comment-column: 0
|
||||
* fill-column: 131
|
||||
* End:
|
||||
*/
|
||||
|
||||
/* end of write.h */
|
132
ld/ld.h
Normal file
132
ld/ld.h
Normal file
|
@ -0,0 +1,132 @@
|
|||
/* ld.h -
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
|
||||
#define flag_is_not_at_end(x) ((x) & BSF_NOT_AT_END)
|
||||
#define flag_is_ordinary_local(x) (((x) & (BSF_LOCAL))&!((x) & (BSF_DEBUGGING)))
|
||||
#define flag_is_debugger(x) ((x) & BSF_DEBUGGING)
|
||||
#define flag_is_undefined_or_global(x) ((x) & (BSF_UNDEFINED | BSF_GLOBAL))
|
||||
#define flag_is_defined(x) (!((x) & (BSF_UNDEFINED)))
|
||||
#define flag_is_global_or_common(x) ((x) & (BSF_GLOBAL | BSF_FORT_COMM))
|
||||
#define flag_is_undefined_or_global_or_common(x) ((x) & (BSF_UNDEFINED | BSF_GLOBAL | BSF_FORT_COMM))
|
||||
#define flag_is_common(x) ((x) & BSF_FORT_COMM)
|
||||
#define flag_is_global(x) ((x) & (BSF_GLOBAL))
|
||||
#define flag_is_undefined(x) ((x) & BSF_UNDEFINED)
|
||||
#define flag_set(x,y) (x = y)
|
||||
#define flag_is_fort_comm(x) ((x) & BSF_FORT_COMM)
|
||||
#define flag_is_absolute(x) ((x) & BSF_ABSOLUTE)
|
||||
/* Extra information we hold on sections */
|
||||
typedef struct user_section_struct {
|
||||
/* Pointer to the section where this data will go */
|
||||
struct lang_input_statement_struct *file;
|
||||
} section_userdata_type;
|
||||
|
||||
|
||||
#define get_userdata(x) ((x)->userdata)
|
||||
#define as_output_section_statement(x) ((x)->otheruserdata)
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Structure for communication between do_file_warnings and it's
|
||||
* helper routines. Will in practice be an array of three of these:
|
||||
* 0) Current line, 1) Next line, 2) Source file info.
|
||||
*/
|
||||
struct line_debug_entry
|
||||
{
|
||||
int line;
|
||||
char *filename;
|
||||
struct nlist *sym;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Which symbols should be stripped (omitted from the output):
|
||||
none, all, or debugger symbols. */
|
||||
enum { STRIP_NONE, STRIP_ALL, STRIP_DEBUGGER } strip_symbols;
|
||||
|
||||
|
||||
|
||||
|
||||
/* Which local symbols should be omitted:
|
||||
none, all, or those starting with L.
|
||||
This is irrelevant if STRIP_NONE. */
|
||||
enum { DISCARD_NONE, DISCARD_ALL, DISCARD_L } discard_locals;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define ALIGN(this, boundary) ((( (this) + ((boundary) -1)) & (~((boundary)-1))))
|
||||
#if 0
|
||||
#define FOREACHGLOBALSYMBOL(x) ldsym_type *x; for (x = symbol_head; x; x=x->next)
|
||||
|
||||
|
||||
|
||||
|
||||
#define SECTIONLOOP(abfd, ptr) \
|
||||
asection *ptr; for(ptr = abfd->sections; ptr;ptr=ptr->next)
|
||||
|
||||
|
||||
#endif
|
||||
typedef struct {
|
||||
|
||||
/* 1 => assign space to common symbols even if `relocatable_output'. */
|
||||
boolean force_common_definition;
|
||||
|
||||
} args_type;
|
||||
|
||||
typedef int token_code_type;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int specified_data_size;
|
||||
boolean magic_demand_paged;
|
||||
boolean make_executable;
|
||||
/* 1 => write relocation into output file so can re-input it later. */
|
||||
boolean relocateable_output;
|
||||
|
||||
/* Will we build contstructors, or leave alone ? */
|
||||
boolean build_constructors;
|
||||
/* 1 => write relocation such that a UNIX linker can understand it.
|
||||
This is used mainly to finish of sets that were built. */
|
||||
boolean unix_relocate;
|
||||
|
||||
|
||||
} ld_config_type;
|
||||
#define set_asymbol_chain(x,y) ((x)->udata = (void *)y)
|
||||
#define get_asymbol_chain(x) ((asymbol **)((x)->udata))
|
||||
#define get_loader_symbol(x) ((loader_global_asymbol *)((x)->udata))
|
||||
#define set_loader_symbol(x,y) ((x)->udata = (void *)y)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
lang_first_phase_enum,
|
||||
lang_allocating_phase_enum,
|
||||
lang_final_phase_enum } lang_phase_type;
|
||||
|
||||
|
||||
|
||||
|
770
ld/ldexp.c
Normal file
770
ld/ldexp.c
Normal file
|
@ -0,0 +1,770 @@
|
|||
/* Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*
|
||||
$Id$
|
||||
|
||||
$Log$
|
||||
Revision 1.1 1991/03/21 21:28:34 gumby
|
||||
Initial revision
|
||||
|
||||
* Revision 1.1 1991/03/13 00:48:16 chrisb
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.6 1991/03/10 09:31:22 rich
|
||||
* Modified Files:
|
||||
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
|
||||
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
|
||||
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
|
||||
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
|
||||
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
|
||||
*
|
||||
* As of this round of changes, ld now builds on all hosts of (Intel960)
|
||||
* interest and copy passes my copy test on big endian hosts again.
|
||||
*
|
||||
* Revision 1.5 1991/03/09 03:25:04 sac
|
||||
* Added support for LONG, SHORT and BYTE keywords in scripts
|
||||
*
|
||||
* Revision 1.4 1991/03/06 02:27:15 sac
|
||||
* Added LONG, SHORT and BYTE keywords
|
||||
*
|
||||
* Revision 1.3 1991/02/22 17:14:59 sac
|
||||
* Added RCS keywords and copyrights
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Written by Steve Chamberlain
|
||||
* steve@cygnus.com
|
||||
*
|
||||
* This module handles expression trees.
|
||||
*/
|
||||
|
||||
|
||||
#include "sysdep.h"
|
||||
#include "bfd.h"
|
||||
|
||||
#include "ld.h"
|
||||
#include "ldmain.h"
|
||||
#include "ldmisc.h"
|
||||
#include "ldexp.h"
|
||||
#include "ldgram.tab.h"
|
||||
#include "ldsym.h"
|
||||
#include "ldlang.h"
|
||||
|
||||
extern char *output_filename;
|
||||
extern unsigned int undefined_global_sym_count;
|
||||
extern unsigned int defined_global_sym_count;
|
||||
extern bfd *output_bfd;
|
||||
extern size_t largest_section;
|
||||
extern lang_statement_list_type file_chain;
|
||||
extern args_type command_line;
|
||||
extern ld_config_type config;
|
||||
|
||||
extern lang_input_statement_type *script_file;
|
||||
extern unsigned int defined_global_sym_count;
|
||||
|
||||
extern bfd_vma print_dot;
|
||||
|
||||
|
||||
static void
|
||||
exp_print_token(outfile, code)
|
||||
FILE *outfile;
|
||||
token_code_type code;
|
||||
{
|
||||
static struct {
|
||||
token_code_type code;
|
||||
char *name;
|
||||
} table[] =
|
||||
{
|
||||
INT, "int",
|
||||
CHAR,"char",
|
||||
NAME,"NAME",
|
||||
PLUSEQ,"+=",
|
||||
MINUSEQ,"-=",
|
||||
MULTEQ,"*=",
|
||||
DIVEQ,"/=",
|
||||
LSHIFTEQ,"<<=",
|
||||
RSHIFTEQ,">>=",
|
||||
ANDEQ,"&=",
|
||||
OREQ,"|=",
|
||||
OROR,"||",
|
||||
ANDAND,"&&",
|
||||
EQ,"==",
|
||||
NE,"!=",
|
||||
LE,"<=",
|
||||
GE,">=",
|
||||
LSHIFT,"<<",
|
||||
RSHIFT,">>=",
|
||||
ALIGN_K,"ALIGN",
|
||||
BLOCK,"BLOCK",
|
||||
SECTIONS,"SECTIONS",
|
||||
ALIGNMENT,"ALIGNMENT",
|
||||
SIZEOF_HEADERS,"SIZEOF_HEADERS",
|
||||
NEXT,"NEXT",
|
||||
SIZEOF,"SIZEOF",
|
||||
ADDR,"ADDR",
|
||||
MEMORY,"MEMORY",
|
||||
DSECT,"DSECT",
|
||||
NOLOAD,"NOLOAD",
|
||||
COPY,"COPY",
|
||||
INFO,"INFO",
|
||||
OVERLAY,"OVERLAY",
|
||||
DEFINED,"DEFINED",
|
||||
TARGET_K,"TARGET",
|
||||
SEARCH_DIR,"SEARCH_DIR",
|
||||
MAP,"MAP",
|
||||
LONG,"LONG",
|
||||
SHORT,"SHORT",
|
||||
BYTE,"BYTE",
|
||||
ENTRY,"ENTRY",
|
||||
0,(char *)NULL} ;
|
||||
|
||||
|
||||
|
||||
unsigned int idx;
|
||||
for (idx = 0; table[idx].name != (char*)NULL; idx++) {
|
||||
if (table[idx].code == code) {
|
||||
fprintf(outfile, "%s", table[idx].name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Not in table, just print it alone */
|
||||
fprintf(outfile, "%c",code);
|
||||
}
|
||||
|
||||
static void
|
||||
make_abs(ptr)
|
||||
etree_value_type *ptr;
|
||||
{
|
||||
if (ptr->section != (lang_output_section_statement_type *)NULL) {
|
||||
asection *s = ptr->section->bfd_section;
|
||||
ptr->value += s->vma;
|
||||
ptr->section = (lang_output_section_statement_type *)NULL;
|
||||
}
|
||||
|
||||
}
|
||||
static
|
||||
etree_value_type new_abs(value)
|
||||
bfd_vma value;
|
||||
{
|
||||
etree_value_type new;
|
||||
new.valid = true;
|
||||
new.section = (lang_output_section_statement_type *)NULL;
|
||||
new.value = value;
|
||||
return new;
|
||||
}
|
||||
|
||||
static void check(os)
|
||||
lang_output_section_statement_type *os;
|
||||
{
|
||||
if (os == (lang_output_section_statement_type *)NULL) {
|
||||
info("%F%P undefined section");
|
||||
}
|
||||
if (os->processed == false) {
|
||||
info("%F%P forward reference of section");
|
||||
}
|
||||
}
|
||||
|
||||
etree_type *exp_intop(value)
|
||||
bfd_vma value;
|
||||
{
|
||||
etree_type *new = (etree_type *)ldmalloc(sizeof(new->value));
|
||||
new->type.node_code = INT;
|
||||
new->value.value = value;
|
||||
new->type.node_class = etree_value;
|
||||
return new;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
etree_value_type new_rel(value, section)
|
||||
bfd_vma value;
|
||||
lang_output_section_statement_type *section;
|
||||
{
|
||||
etree_value_type new;
|
||||
new.valid = true;
|
||||
new.value = value;
|
||||
new.section = section;
|
||||
return new;
|
||||
}
|
||||
|
||||
static
|
||||
etree_value_type new_rel_from_section(value, section)
|
||||
bfd_vma value;
|
||||
lang_output_section_statement_type *section;
|
||||
{
|
||||
etree_value_type new;
|
||||
new.valid = true;
|
||||
new.value = value;
|
||||
new.section = section;
|
||||
if (new.section != (lang_output_section_statement_type *)NULL) {
|
||||
new.value -= section->bfd_section->vma;
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
static etree_value_type
|
||||
fold_binary(tree, current_section, allocation_done, dot, dotp)
|
||||
etree_type *tree;
|
||||
lang_output_section_statement_type *current_section;
|
||||
lang_phase_type allocation_done;
|
||||
bfd_vma dot;
|
||||
bfd_vma *dotp;
|
||||
{
|
||||
etree_value_type result;
|
||||
|
||||
result = exp_fold_tree(tree->binary.lhs, current_section,
|
||||
allocation_done, dot, dotp);
|
||||
if (result.valid) {
|
||||
etree_value_type other;
|
||||
other = exp_fold_tree(tree->binary.rhs,
|
||||
current_section,
|
||||
allocation_done, dot,dotp) ;
|
||||
if (other.valid) {
|
||||
/* If values are from different sections, or this is an */
|
||||
/* absolute expression, make both source args absolute */
|
||||
if (result.section != other.section ||
|
||||
current_section == (lang_output_section_statement_type *)NULL) {
|
||||
|
||||
make_abs(&result);
|
||||
make_abs(&other);
|
||||
}
|
||||
|
||||
switch (tree->type.node_code)
|
||||
{
|
||||
case '%':
|
||||
/* Mod, both absolule*/
|
||||
|
||||
if (other.value == 0) {
|
||||
info("%F%S % by zero\n");
|
||||
}
|
||||
result.value %= other.value;
|
||||
break;
|
||||
case '/':
|
||||
if (other.value == 0) {
|
||||
info("%F%S / by zero\n");
|
||||
}
|
||||
result.value /= other.value;
|
||||
break;
|
||||
#define BOP(x,y) case x : result.value = result.value y other.value;break;
|
||||
BOP('+',+);
|
||||
BOP('*',*);
|
||||
BOP('-',-);
|
||||
BOP(LSHIFT,<<);
|
||||
BOP(RSHIFT,>>);
|
||||
BOP(EQ,==);
|
||||
BOP(NE,!=);
|
||||
BOP('<',<);
|
||||
BOP('>',>);
|
||||
BOP(LE,<=);
|
||||
BOP(GE,>=);
|
||||
BOP('&',&);
|
||||
BOP('^',^);
|
||||
BOP('|',|);
|
||||
BOP(ANDAND,&&);
|
||||
BOP(OROR,||);
|
||||
default:
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
etree_value_type invalid()
|
||||
{
|
||||
etree_value_type new;
|
||||
new.valid = false;
|
||||
return new;
|
||||
}
|
||||
|
||||
etree_value_type fold_name(tree, current_section, allocation_done, dot)
|
||||
etree_type *tree;
|
||||
lang_output_section_statement_type *current_section;
|
||||
lang_phase_type allocation_done;
|
||||
bfd_vma dot;
|
||||
|
||||
{
|
||||
etree_value_type result;
|
||||
switch (tree->type.node_code)
|
||||
{
|
||||
case DEFINED:
|
||||
result.value =
|
||||
ldsym_get_soft(tree->name.name) != (ldsym_type *)NULL;
|
||||
result.section = 0;
|
||||
result.valid = true;
|
||||
break;
|
||||
case NAME:
|
||||
result.valid = false;
|
||||
if (tree->name.name[0] == '.' && tree->name.name[1] == 0) {
|
||||
|
||||
if (allocation_done != lang_first_phase_enum) {
|
||||
result = new_rel_from_section(dot, current_section);
|
||||
}
|
||||
else {
|
||||
result = invalid();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (allocation_done == lang_final_phase_enum) {
|
||||
ldsym_type *sy = ldsym_get_soft(tree->name.name);
|
||||
|
||||
if (sy) {
|
||||
asymbol **sdefp = sy->sdefs_chain;
|
||||
|
||||
if (sdefp) {
|
||||
asymbol *sdef = *sdefp;
|
||||
if (sdef->section == (asection *)NULL) {
|
||||
/* This is an absolute symbol */
|
||||
result = new_abs(sdef->value);
|
||||
}
|
||||
else {
|
||||
lang_output_section_statement_type *os =
|
||||
lang_output_section_statement_lookup( sdef->section->output_section->name);
|
||||
result = new_rel(sdef->value, os);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.valid == false) {
|
||||
info("%F%S: undefined symbol `%s' referenced in expression.\n",
|
||||
tree->name.name);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ADDR:
|
||||
|
||||
if (allocation_done != lang_first_phase_enum) {
|
||||
lang_output_section_statement_type *os =
|
||||
lang_output_section_find(tree->name.name);
|
||||
check(os);
|
||||
result = new_rel((bfd_vma)0, os);
|
||||
}
|
||||
else {
|
||||
result = invalid();
|
||||
}
|
||||
break;
|
||||
case SIZEOF:
|
||||
if(allocation_done != lang_first_phase_enum) {
|
||||
lang_output_section_statement_type *os =
|
||||
lang_output_section_find(tree->name.name);
|
||||
check(os);
|
||||
result = new_abs((bfd_vma)(os->bfd_section->size));
|
||||
}
|
||||
else {
|
||||
result = invalid();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
FAIL();
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
etree_value_type exp_fold_tree(tree, current_section, allocation_done,
|
||||
dot, dotp)
|
||||
etree_type *tree;
|
||||
lang_output_section_statement_type *current_section;
|
||||
lang_phase_type allocation_done;
|
||||
bfd_vma dot;
|
||||
bfd_vma *dotp;
|
||||
{
|
||||
etree_value_type result;
|
||||
|
||||
if (tree == (etree_type *)NULL) {
|
||||
result.valid = false;
|
||||
}
|
||||
else {
|
||||
switch (tree->type.node_class)
|
||||
{
|
||||
case etree_value:
|
||||
result = new_rel(tree->value.value, current_section);
|
||||
break;
|
||||
case etree_unary:
|
||||
result = exp_fold_tree(tree->unary.child,
|
||||
current_section,
|
||||
allocation_done, dot, dotp);
|
||||
if (result.valid == true)
|
||||
{
|
||||
switch(tree->type.node_code)
|
||||
{
|
||||
case ALIGN_K:
|
||||
if (allocation_done != lang_first_phase_enum) {
|
||||
result = new_rel_from_section(ALIGN(dot,
|
||||
result.value) ,
|
||||
current_section);
|
||||
|
||||
}
|
||||
else {
|
||||
result.valid = false;
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
result.value = -result.value;
|
||||
break;
|
||||
case NEXT:
|
||||
result.valid = false;
|
||||
break;
|
||||
default:
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case etree_trinary:
|
||||
|
||||
result = exp_fold_tree(tree->trinary.cond,
|
||||
current_section,
|
||||
allocation_done, dot, dotp);
|
||||
if (result.valid) {
|
||||
result = exp_fold_tree(result.value ?
|
||||
tree->trinary.lhs:tree->trinary.rhs,
|
||||
current_section,
|
||||
allocation_done, dot, dotp);
|
||||
}
|
||||
|
||||
break;
|
||||
case etree_binary:
|
||||
result = fold_binary(tree, current_section, allocation_done,
|
||||
dot, dotp);
|
||||
break;
|
||||
case etree_assign:
|
||||
if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0) {
|
||||
/* Assignment to dot can only be done during allocation */
|
||||
if (allocation_done == lang_allocating_phase_enum) {
|
||||
result = exp_fold_tree(tree->assign.src,
|
||||
current_section,
|
||||
lang_allocating_phase_enum, dot, dotp);
|
||||
if (result.valid == false) {
|
||||
info("%F%S invalid assignment to location counter\n");
|
||||
}
|
||||
else {
|
||||
if (current_section ==
|
||||
(lang_output_section_statement_type *)NULL) {
|
||||
info("%F%S assignment to location counter invalid outside of SECTION\n");
|
||||
}
|
||||
else {
|
||||
unsigned long nextdot =result.value +
|
||||
current_section->bfd_section->vma;
|
||||
if (nextdot < dot) {
|
||||
info("%F%S cannot move location counter backwards");
|
||||
}
|
||||
else {
|
||||
*dotp = nextdot;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ldsym_type *sy = ldsym_get(tree->assign.dst);
|
||||
|
||||
/* If this symbol has just been created then we'll place it into
|
||||
* a section of our choice
|
||||
*/
|
||||
result = exp_fold_tree(tree->assign.src,
|
||||
current_section, allocation_done,
|
||||
dot, dotp);
|
||||
if (result.valid)
|
||||
{
|
||||
asymbol *def;
|
||||
asymbol **def_ptr = (asymbol **)ldmalloc(sizeof(asymbol **));
|
||||
/* Add this definition to script file */
|
||||
def = (asymbol *)bfd_make_empty_symbol(script_file->the_bfd);
|
||||
*def_ptr = def;
|
||||
|
||||
|
||||
def->value = result.value;
|
||||
if (result.section !=
|
||||
(lang_output_section_statement_type *)NULL) {
|
||||
if (current_section !=
|
||||
(lang_output_section_statement_type *)NULL) {
|
||||
|
||||
def->section = result.section->bfd_section;
|
||||
def->flags = BSF_GLOBAL | BSF_EXPORT;
|
||||
}
|
||||
else {
|
||||
/* Force to absolute */
|
||||
def->value += result.section->bfd_section->vma;
|
||||
def->section = (asection *)NULL;
|
||||
def->flags = BSF_GLOBAL | BSF_EXPORT | BSF_ABSOLUTE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
def->section = (asection *)NULL;
|
||||
def->flags = BSF_GLOBAL | BSF_EXPORT | BSF_ABSOLUTE;
|
||||
}
|
||||
|
||||
|
||||
def->udata = (void *)NULL;
|
||||
def->name = sy->name;
|
||||
Q_enter_global_ref(def_ptr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
case etree_name:
|
||||
result = fold_name(tree, current_section, allocation_done, dot);
|
||||
break;
|
||||
default:
|
||||
info("%F%S Need more of these %d",tree->type.node_class );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
etree_value_type exp_fold_tree_no_dot(tree, current_section, allocation_done)
|
||||
etree_type *tree;
|
||||
lang_output_section_statement_type *current_section;
|
||||
lang_phase_type allocation_done;
|
||||
{
|
||||
return exp_fold_tree(tree, current_section, allocation_done, (bfd_vma)
|
||||
0, (bfd_vma *)NULL);
|
||||
}
|
||||
|
||||
etree_type *
|
||||
exp_binop(code, lhs, rhs)
|
||||
int code;
|
||||
etree_type *lhs;
|
||||
etree_type *rhs;
|
||||
{
|
||||
etree_type value, *new;
|
||||
etree_value_type r;
|
||||
|
||||
value.type.node_code = code;
|
||||
value.binary.lhs = lhs;
|
||||
value.binary.rhs = rhs;
|
||||
value.type.node_class = etree_binary;
|
||||
r = exp_fold_tree_no_dot(&value, (lang_output_section_statement_type *)NULL,
|
||||
lang_first_phase_enum );
|
||||
if (r.valid)
|
||||
{
|
||||
return exp_intop(r.value);
|
||||
}
|
||||
new = (etree_type *)ldmalloc(sizeof(new->binary));
|
||||
memcpy((char *)new, (char *)&value, sizeof(new->binary));
|
||||
return new;
|
||||
}
|
||||
|
||||
etree_type *
|
||||
exp_trinop(code, cond, lhs, rhs)
|
||||
int code;
|
||||
etree_type *cond;
|
||||
etree_type *lhs;
|
||||
etree_type *rhs;
|
||||
{
|
||||
etree_type value, *new;
|
||||
etree_value_type r;
|
||||
value.type.node_code = code;
|
||||
value.trinary.lhs = lhs;
|
||||
value.trinary.cond = cond;
|
||||
value.trinary.rhs = rhs;
|
||||
value.type.node_class = etree_trinary;
|
||||
r= exp_fold_tree_no_dot(&value, (lang_output_section_statement_type
|
||||
*)NULL,lang_first_phase_enum);
|
||||
if (r.valid) {
|
||||
return exp_intop(r.value);
|
||||
}
|
||||
new = (etree_type *)ldmalloc(sizeof(new->trinary));
|
||||
memcpy((char *)new,(char *) &value, sizeof(new->trinary));
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
etree_type *
|
||||
exp_unop(code, child)
|
||||
int code;
|
||||
etree_type *child;
|
||||
{
|
||||
etree_type value, *new;
|
||||
|
||||
etree_value_type r;
|
||||
value.unary.type.node_code = code;
|
||||
value.unary.child = child;
|
||||
value.unary.type.node_class = etree_unary;
|
||||
r = exp_fold_tree_no_dot(&value,(lang_output_section_statement_type *)NULL,
|
||||
lang_first_phase_enum);
|
||||
if (r.valid) {
|
||||
return exp_intop(r.value);
|
||||
}
|
||||
new = (etree_type *)ldmalloc(sizeof(new->unary));
|
||||
memcpy((char *)new, (char *)&value, sizeof(new->unary));
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
etree_type *
|
||||
exp_nameop(code, name)
|
||||
int code;
|
||||
char *name;
|
||||
{
|
||||
|
||||
etree_type value, *new;
|
||||
|
||||
etree_value_type r;
|
||||
value.name.type.node_code = code;
|
||||
value.name.name = name;
|
||||
value.name.type.node_class = etree_name;
|
||||
|
||||
|
||||
r = exp_fold_tree_no_dot(&value,(lang_output_section_statement_type *)NULL,
|
||||
lang_first_phase_enum);
|
||||
if (r.valid) {
|
||||
return exp_intop(r.value);
|
||||
}
|
||||
new = (etree_type *)ldmalloc(sizeof(new->name));
|
||||
memcpy((char *)new, (char *)&value, sizeof(new->name));
|
||||
return new;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
etree_type *
|
||||
exp_assop(code, dst, src)
|
||||
int code;
|
||||
char *dst;
|
||||
etree_type *src;
|
||||
{
|
||||
etree_type value, *new;
|
||||
|
||||
value.assign.type.node_code = code;
|
||||
|
||||
|
||||
value.assign.src = src;
|
||||
value.assign.dst = dst;
|
||||
value.assign.type.node_class = etree_assign;
|
||||
|
||||
#if 0
|
||||
if (exp_fold_tree_no_dot(&value, &result)) {
|
||||
return exp_intop(result);
|
||||
}
|
||||
#endif
|
||||
new = (etree_type*)ldmalloc(sizeof(new->assign));
|
||||
memcpy((char *)new, (char *)&value, sizeof(new->assign));
|
||||
return new;
|
||||
}
|
||||
|
||||
void
|
||||
exp_print_tree(outfile, tree)
|
||||
FILE *outfile;
|
||||
etree_type *tree;
|
||||
{
|
||||
switch (tree->type.node_class) {
|
||||
case etree_value:
|
||||
fprintf(outfile,"0x%08lx",(bfd_vma)(tree->value.value));
|
||||
return;
|
||||
case etree_assign:
|
||||
#if 0
|
||||
if (tree->assign.dst->sdefs != (asymbol *)NULL){
|
||||
fprintf(outfile,"%s (%x) ",tree->assign.dst->name,
|
||||
tree->assign.dst->sdefs->value);
|
||||
}
|
||||
else {
|
||||
fprintf(outfile,"%s (UNDEFINED)",tree->assign.dst->name);
|
||||
}
|
||||
#endif
|
||||
fprintf(outfile,"%s ",tree->assign.dst);
|
||||
exp_print_token(outfile,tree->type.node_code);
|
||||
exp_print_tree(outfile,tree->assign.src);
|
||||
break;
|
||||
case etree_binary:
|
||||
exp_print_tree(outfile,tree->binary.lhs);
|
||||
exp_print_token(outfile,tree->type.node_code);
|
||||
exp_print_tree(outfile,tree->binary.rhs);
|
||||
break;
|
||||
case etree_trinary:
|
||||
exp_print_tree(outfile,tree->trinary.cond);
|
||||
fprintf(outfile,"?");
|
||||
exp_print_tree(outfile,tree->trinary.lhs);
|
||||
fprintf(outfile,":");
|
||||
exp_print_tree(outfile,tree->trinary.rhs);
|
||||
break;
|
||||
case etree_unary:
|
||||
exp_print_token(outfile,tree->unary.type.node_code);
|
||||
fprintf(outfile,"(");
|
||||
exp_print_tree(outfile,tree->unary.child);
|
||||
fprintf(outfile,")");
|
||||
break;
|
||||
case etree_undef:
|
||||
fprintf(outfile,"????????");
|
||||
break;
|
||||
case etree_name:
|
||||
if (tree->type.node_code == NAME) {
|
||||
fprintf(outfile,"%s", tree->name.name);
|
||||
}
|
||||
else {
|
||||
exp_print_token(outfile,tree->type.node_code);
|
||||
fprintf(outfile,"(%s)", tree->name.name);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FAIL();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bfd_vma
|
||||
exp_get_vma(tree, def, name, allocation_done)
|
||||
etree_type *tree;
|
||||
bfd_vma def;
|
||||
char *name;
|
||||
lang_phase_type allocation_done;
|
||||
{
|
||||
etree_value_type r;
|
||||
|
||||
if (tree != (etree_type *)NULL) {
|
||||
r = exp_fold_tree_no_dot(tree,
|
||||
(lang_output_section_statement_type *)NULL,
|
||||
allocation_done);
|
||||
if (r.valid == false && name) {
|
||||
info("%F%S Nonconstant expression for %s\n",name);
|
||||
}
|
||||
return r.value;
|
||||
}
|
||||
else {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
exp_get_value_int(tree,def,name, allocation_done)
|
||||
etree_type *tree;
|
||||
int def;
|
||||
char *name;
|
||||
lang_phase_type allocation_done;
|
||||
{
|
||||
return (int)exp_get_vma(tree,(bfd_vma)def,name, allocation_done);
|
||||
}
|
99
ld/ldexp.h
Normal file
99
ld/ldexp.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
/* ldexp.h -
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
|
||||
|
||||
|
||||
/* The result of an expression tree */
|
||||
typedef struct
|
||||
{
|
||||
bfd_vma value;
|
||||
struct lang_output_section_statement_struct *section;
|
||||
boolean valid;
|
||||
} etree_value_type;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int node_code;
|
||||
enum { etree_binary,
|
||||
etree_trinary,
|
||||
etree_unary,
|
||||
etree_name,
|
||||
etree_assign,
|
||||
etree_undef,
|
||||
etree_unspec,
|
||||
etree_value } node_class;
|
||||
} node_type;
|
||||
|
||||
|
||||
|
||||
typedef union etree_union
|
||||
{
|
||||
node_type type;
|
||||
struct {
|
||||
node_type type;
|
||||
union etree_union *lhs;
|
||||
union etree_union *rhs;
|
||||
} binary;
|
||||
struct {
|
||||
node_type type;
|
||||
union etree_union *cond;
|
||||
union etree_union *lhs;
|
||||
union etree_union *rhs;
|
||||
} trinary;
|
||||
struct {
|
||||
node_type type;
|
||||
char *dst;
|
||||
union etree_union *src;
|
||||
} assign;
|
||||
|
||||
struct {
|
||||
node_type type;
|
||||
union etree_union *child;
|
||||
} unary;
|
||||
struct {
|
||||
node_type type;
|
||||
char *name;
|
||||
} name;
|
||||
struct {
|
||||
node_type type;
|
||||
bfd_vma value;
|
||||
} value;
|
||||
|
||||
} etree_type;
|
||||
|
||||
|
||||
PROTO(etree_type *,exp_intop,(bfd_vma));
|
||||
|
||||
PROTO(etree_value_type, invalid,(void));
|
||||
PROTO(etree_value_type, exp_fold_tree,(etree_type *, struct
|
||||
lang_output_section_statement_struct *, lang_phase_type,
|
||||
bfd_vma, bfd_vma *));
|
||||
|
||||
PROTO(etree_type *, exp_binop,(int, etree_type *, etree_type *));
|
||||
PROTO(etree_type *,exp_trinop,(int,etree_type *, etree_type *, etree_type *));
|
||||
PROTO(etree_type *,exp_unop,(int, etree_type *));
|
||||
PROTO(etree_type *,exp_nameop,(int, char *));
|
||||
PROTO(etree_type *,exp_assop,(int, char *, etree_type *));
|
||||
PROTO(void, exp_print_tree,(struct _iobuf *, etree_type *));
|
||||
PROTO(bfd_vma, exp_get_vma,(etree_type *, bfd_vma, char *, enum boolean));
|
||||
PROTO(int, exp_get_value_int,(etree_type *, int, char *, enum boolean));
|
284
ld/ldfile.c
Normal file
284
ld/ldfile.c
Normal file
|
@ -0,0 +1,284 @@
|
|||
|
||||
/* Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*
|
||||
$Id$
|
||||
|
||||
$Log$
|
||||
Revision 1.1 1991/03/21 21:28:37 gumby
|
||||
Initial revision
|
||||
|
||||
* Revision 1.2 1991/03/15 18:45:55 rich
|
||||
* foo
|
||||
*
|
||||
* Revision 1.1 1991/03/13 00:48:18 chrisb
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.4 1991/03/10 09:31:24 rich
|
||||
* Modified Files:
|
||||
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
|
||||
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
|
||||
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
|
||||
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
|
||||
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
|
||||
*
|
||||
* As of this round of changes, ld now builds on all hosts of (Intel960)
|
||||
* interest and copy passes my copy test on big endian hosts again.
|
||||
*
|
||||
* Revision 1.3 1991/02/22 17:15:00 sac
|
||||
* Added RCS keywords and copyrights
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
ldfile.c
|
||||
|
||||
look after all the file stuff
|
||||
|
||||
*/
|
||||
|
||||
#include "sysdep.h"
|
||||
#include "bfd.h"
|
||||
|
||||
#include "ldmisc.h"
|
||||
#include "ldlang.h"
|
||||
#include "ldfile.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
/* EXPORT */
|
||||
char *ldfile_input_filename;
|
||||
char *ldfile_output_machine_name;
|
||||
unsigned long ldfile_output_machine;
|
||||
enum bfd_architecture ldfile_output_architecture;
|
||||
boolean had_script;
|
||||
|
||||
/* IMPORT */
|
||||
|
||||
extern boolean option_v;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* LOACL */
|
||||
typedef struct search_dirs_struct
|
||||
{
|
||||
char *name;
|
||||
struct search_dirs_struct *next;
|
||||
} search_dirs_type;
|
||||
|
||||
static search_dirs_type *search_head;
|
||||
static search_dirs_type **search_tail_ptr = &search_head;
|
||||
|
||||
typedef struct search_arch_struct
|
||||
{
|
||||
char *name;
|
||||
struct search_arch_struct *next;
|
||||
} search_arch_type;
|
||||
|
||||
static search_arch_type *search_arch_head;
|
||||
static search_arch_type **search_arch_tail_ptr = &search_arch_head;
|
||||
|
||||
void
|
||||
ldfile_add_library_path(name)
|
||||
char *name;
|
||||
{
|
||||
search_dirs_type *new =
|
||||
(search_dirs_type *)ldmalloc(sizeof(search_dirs_type));
|
||||
new->name = name;
|
||||
new->next = (search_dirs_type*)NULL;
|
||||
*search_tail_ptr = new;
|
||||
search_tail_ptr = &new->next;
|
||||
}
|
||||
|
||||
|
||||
static bfd*
|
||||
cached_bfd_openr(attempt,entry)
|
||||
char *attempt;
|
||||
lang_input_statement_type *entry;
|
||||
{
|
||||
entry->the_bfd = bfd_openr(attempt, entry->target);
|
||||
|
||||
|
||||
return entry->the_bfd;
|
||||
}
|
||||
|
||||
static bfd *
|
||||
open_a(arch, entry, lib, suffix)
|
||||
char *arch;
|
||||
lang_input_statement_type *entry;
|
||||
char *lib;
|
||||
char *suffix;
|
||||
{
|
||||
bfd*desc;
|
||||
search_dirs_type *search ;
|
||||
for (search = search_head;
|
||||
search != (search_dirs_type *)NULL;
|
||||
search = search->next)
|
||||
{
|
||||
char buffer[1000];
|
||||
char *string;
|
||||
if (entry->is_archive == true) {
|
||||
sprintf(buffer,
|
||||
"%s/%s%s%s%s",
|
||||
search->name,
|
||||
lib,
|
||||
entry->filename, arch, suffix);
|
||||
}
|
||||
else {
|
||||
if (entry->filename[0] == '/') {
|
||||
strcpy(buffer, entry->filename);
|
||||
} else {
|
||||
sprintf(buffer,"%s/%s",search->name, entry->filename);
|
||||
} /* */
|
||||
}
|
||||
string = buystring(buffer);
|
||||
desc = cached_bfd_openr (string, entry);
|
||||
if (desc)
|
||||
{
|
||||
entry->filename = string;
|
||||
entry->search_dirs_flag = false;
|
||||
entry->the_bfd = desc;
|
||||
return desc;
|
||||
}
|
||||
free(string);
|
||||
}
|
||||
return (bfd *)NULL;
|
||||
}
|
||||
|
||||
/* Open the input file specified by 'entry', and return a descriptor.
|
||||
The open file is remembered; if the same file is opened twice in a row,
|
||||
a new open is not actually done. */
|
||||
|
||||
void
|
||||
ldfile_open_file (entry)
|
||||
lang_input_statement_type *entry;
|
||||
{
|
||||
|
||||
if (entry->superfile)
|
||||
ldfile_open_file (entry->superfile);
|
||||
|
||||
if (entry->search_dirs_flag)
|
||||
{
|
||||
search_arch_type *arch;
|
||||
for (arch = search_arch_head;
|
||||
arch != (search_arch_type *)NULL;
|
||||
arch = arch->next) {
|
||||
if (open_a(arch->name,entry,"","") != (bfd *)NULL) {
|
||||
return;
|
||||
}
|
||||
if (open_a(arch->name,entry,"lib",".a") != (bfd *)NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
entry->the_bfd = cached_bfd_openr (entry->filename, entry);
|
||||
|
||||
}
|
||||
if (!entry->the_bfd) info("%F%P: %E %I\n", entry);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static FILE *
|
||||
try_open(name, exten)
|
||||
char *name;
|
||||
char *exten;
|
||||
{
|
||||
FILE *result;
|
||||
char buff[1000];
|
||||
result = fopen(name, "r");
|
||||
if (result && option_v == true) {
|
||||
info("%s\n",name);
|
||||
return result;
|
||||
}
|
||||
sprintf(buff, "%s%s", name, exten);
|
||||
result = fopen(buff, "r");
|
||||
|
||||
if (result && option_v == true) {
|
||||
info("%s\n", buff);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static FILE *
|
||||
find_a_name(name, extend)
|
||||
char *name;
|
||||
char *extend;
|
||||
{
|
||||
search_dirs_type *search;
|
||||
FILE *result;
|
||||
char buffer[1000];
|
||||
/* First try raw name */
|
||||
result = try_open(name,"");
|
||||
if (result == (FILE *)NULL) {
|
||||
/* Try now prefixes */
|
||||
for (search = search_head;
|
||||
search != (search_dirs_type *)NULL;
|
||||
search = search->next) {
|
||||
sprintf(buffer,"%s/%s", search->name, name);
|
||||
result = try_open(buffer, extend);
|
||||
if (result)break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ldfile_open_command_file(name)
|
||||
char *name;
|
||||
{
|
||||
extern FILE *ldlex_input_stack;
|
||||
ldlex_input_stack = find_a_name(name, ".ld");
|
||||
|
||||
if (ldlex_input_stack == (FILE *)NULL) {
|
||||
info("%P%F cannot open load script file %s\n",name);
|
||||
}
|
||||
ldfile_input_filename = name;
|
||||
had_script = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
ldfile_add_arch(name)
|
||||
char *name;
|
||||
{
|
||||
search_arch_type *new =
|
||||
(search_arch_type *)ldmalloc(sizeof(search_arch_type));
|
||||
ldfile_output_machine_name = name;
|
||||
|
||||
new->name = name;
|
||||
new->next = (search_arch_type*)NULL;
|
||||
while (*name) {
|
||||
if (isupper(*name)) *name = tolower(*name);
|
||||
name++;
|
||||
}
|
||||
*search_arch_tail_ptr = new;
|
||||
search_arch_tail_ptr = &new->next;
|
||||
|
||||
}
|
27
ld/ldfile.h
Normal file
27
ld/ldfile.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* ldfile.h -
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
|
||||
|
||||
PROTO(void,ldfile_add_arch,(char *));
|
||||
PROTO(void,ldfile_add_library_path,(char *));
|
||||
PROTO(void,ldfile_open_command_file,(char *name));
|
||||
PROTO(void,ldfile_open_file,(struct lang_input_statement_struct *));
|
||||
|
693
ld/ldgram.y
Normal file
693
ld/ldgram.y
Normal file
|
@ -0,0 +1,693 @@
|
|||
%{
|
||||
/* Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.1 1991/03/21 21:28:41 gumby
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.2 1991/03/16 22:27:24 rich
|
||||
* fish
|
||||
*
|
||||
* Revision 1.1 1991/03/13 00:48:21 chrisb
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.6 1991/03/10 09:31:26 rich
|
||||
* Modified Files:
|
||||
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
|
||||
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
|
||||
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
|
||||
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
|
||||
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
|
||||
*
|
||||
* As of this round of changes, ld now builds on all hosts of (Intel960)
|
||||
* interest and copy passes my copy test on big endian hosts again.
|
||||
*
|
||||
* Revision 1.5 1991/03/09 03:25:48 sac
|
||||
* Can now parse the -Ur flag
|
||||
*
|
||||
* Revision 1.4 1991/03/06 02:26:01 sac
|
||||
* Added support for constructor sections.
|
||||
* Remove parsing ambiguity.
|
||||
* Lint
|
||||
*
|
||||
* Revision 1.3 1991/02/22 17:15:13 sac
|
||||
* Added RCS keywords and copyrights
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
This is a YACC grammer intended to parse a superset of the AT&T
|
||||
linker scripting languaue.
|
||||
|
||||
|
||||
Written by Steve Chamberlain steve@cygnus.com
|
||||
*/
|
||||
|
||||
|
||||
/*SUPPRESS 166*/
|
||||
/*SUPPRESS 112*/
|
||||
|
||||
#include "sysdep.h"
|
||||
#include "bfd.h"
|
||||
|
||||
#include "ld.h"
|
||||
#include "ldexp.h"
|
||||
#include "ldversion.h"
|
||||
#include "ldlang.h"
|
||||
#include "ld-emul.h"
|
||||
#include "ldfile.h"
|
||||
#include "ldmisc.h"
|
||||
#define YYDEBUG 1
|
||||
|
||||
boolean option_v;
|
||||
|
||||
|
||||
extern unsigned int lineno;
|
||||
extern boolean trace_files;
|
||||
extern boolean write_map;
|
||||
|
||||
boolean hex_mode;
|
||||
|
||||
|
||||
|
||||
|
||||
lang_memory_region_type *region;
|
||||
|
||||
|
||||
lang_memory_region_type *lang_memory_region_lookup();
|
||||
lang_output_section_statement_type *lang_output_section_statement_lookup();
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
void lang_add_data(int type, union etree_union *exp);
|
||||
void lang_enter_output_section_statement(char *output_section_statement_name, etree_type *address_exp, bfd_vma block_value);
|
||||
|
||||
#else
|
||||
|
||||
void lang_add_data();
|
||||
void lang_enter_output_section_statement();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
extern args_type command_line;
|
||||
char *current_file;
|
||||
boolean ldgram_want_filename = true;
|
||||
boolean had_script = false;
|
||||
boolean force_make_executable = false;
|
||||
boolean ldgram_mustbe_filename = false;
|
||||
boolean ldgram_mustbe_symbolname = false;
|
||||
boolean ldgram_has_inputfile = false;
|
||||
|
||||
/* LOCALS */
|
||||
|
||||
|
||||
|
||||
|
||||
%}
|
||||
%union {
|
||||
bfd_vma integer;
|
||||
int voidval;
|
||||
char *name;
|
||||
int token;
|
||||
union etree_union *etree;
|
||||
asection *section;
|
||||
struct lang_output_section_statement_struct *output_section_statement;
|
||||
union lang_statement_union **statement_ptr;
|
||||
int lineno;
|
||||
struct {
|
||||
FILE *file;
|
||||
char *name;
|
||||
unsigned int lineno;
|
||||
} state;
|
||||
|
||||
|
||||
}
|
||||
|
||||
%type <etree> exp opt_exp exp_head
|
||||
%type <integer> fill_opt opt_block
|
||||
%type <name> memspec_opt
|
||||
%token <integer> INT CHAR
|
||||
%token <name> NAME
|
||||
%type <integer> length
|
||||
|
||||
%right <token> PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ
|
||||
%right <token> '?' ':'
|
||||
%left <token> OROR
|
||||
%left <token> ANDAND
|
||||
%left <token> '|'
|
||||
%left <token> '^'
|
||||
%left <token> '&'
|
||||
%left <token> EQ NE
|
||||
%left <token> '<' '>' LE GE
|
||||
%left <token> LSHIFT RSHIFT
|
||||
%left <token> '+' '-'
|
||||
%left <token> '*' '/' '%'
|
||||
%right UNARY
|
||||
%left <token> '('
|
||||
%token <token> ALIGN_K BLOCK LONG SHORT BYTE
|
||||
%token SECTIONS
|
||||
%token '{' '}'
|
||||
%token ALIGNMENT SIZEOF_HEADERS
|
||||
%token NEXT SIZEOF ADDR
|
||||
%token MEMORY
|
||||
%token DSECT NOLOAD COPY INFO OVERLAY
|
||||
%token NAME DEFINED TARGET_K SEARCH_DIR MAP ENTRY
|
||||
%token OPTION_e OPTION_c OPTION_noinhibit_exec OPTION_s OPTION_S OPTION_format
|
||||
%token OPTION_d OPTION_dc OPTION_dp OPTION_x OPTION_X
|
||||
%token OPTION_v OPTION_M OPTION_t STARTUP HLL SYSLIB FLOAT NOFLOAT OPTION_defsym
|
||||
%token OPTION_n OPTION_r OPTION_o OPTION_b OPTION_A
|
||||
%token <name> OPTION_l OPTION_L OPTION_T OPTION_Aarch OPTION_Tfile OPTION_Texp
|
||||
%token OPTION_Ur
|
||||
%token ORIGIN FILL OPTION_g
|
||||
%token LENGTH BIND SUBSECTION_ALIGN CREATE_OBJECT_SYMBOLS INPUT OUTPUT
|
||||
%type <token> assign_op SIZEOF NEXT ADDR
|
||||
%type <etree> assignment
|
||||
%type <name> filename
|
||||
|
||||
%{
|
||||
ld_config_type config;
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
|
||||
|
||||
file: command_line { lang_final(); };
|
||||
|
||||
|
||||
filename:
|
||||
{
|
||||
ldgram_mustbe_filename =true;
|
||||
}
|
||||
NAME
|
||||
{
|
||||
ldgram_mustbe_filename = false;
|
||||
$$ = $2;
|
||||
}
|
||||
|
||||
command_line:
|
||||
command_line command_line_option
|
||||
|
|
||||
;
|
||||
|
||||
command_line_option:
|
||||
OPTION_v
|
||||
{
|
||||
ldversion();
|
||||
option_v = true;
|
||||
}
|
||||
| OPTION_t {
|
||||
trace_files = true;
|
||||
}
|
||||
| OPTION_M {
|
||||
write_map = true;
|
||||
}
|
||||
| OPTION_n {
|
||||
config.magic_demand_paged = false;
|
||||
config.make_executable = false;
|
||||
}
|
||||
| OPTION_s {
|
||||
strip_symbols = STRIP_ALL;
|
||||
}
|
||||
| OPTION_S {
|
||||
strip_symbols = STRIP_DEBUGGER;
|
||||
}
|
||||
|
||||
| OPTION_r {
|
||||
config.relocateable_output = true;
|
||||
config.build_constructors = false;
|
||||
config.magic_demand_paged = false;
|
||||
}
|
||||
| OPTION_Ur {
|
||||
config.relocateable_output = true;
|
||||
config.build_constructors = true;
|
||||
config.magic_demand_paged = false;
|
||||
}
|
||||
| OPTION_o filename
|
||||
{
|
||||
lang_add_output($2);
|
||||
}
|
||||
| OPTION_e NAME
|
||||
{ lang_add_entry($2);
|
||||
}
|
||||
| OPTION_X {
|
||||
discard_locals = DISCARD_L;
|
||||
}
|
||||
| OPTION_x {
|
||||
discard_locals = DISCARD_ALL;
|
||||
}
|
||||
|
||||
| OPTION_noinhibit_exec
|
||||
{
|
||||
force_make_executable = true;
|
||||
}
|
||||
| OPTION_d {
|
||||
command_line.force_common_definition = true;
|
||||
}
|
||||
| OPTION_dc
|
||||
{
|
||||
command_line.force_common_definition = true;
|
||||
}
|
||||
| OPTION_g
|
||||
{
|
||||
/* Ignored */
|
||||
}
|
||||
| OPTION_dp
|
||||
{
|
||||
command_line.force_common_definition = true;
|
||||
}
|
||||
| OPTION_format NAME
|
||||
{
|
||||
lang_add_target($2);
|
||||
}
|
||||
|
||||
| OPTION_Texp { hex_mode =true; }
|
||||
exp_head
|
||||
{ lang_section_start($1, $3);
|
||||
hex_mode = false; }
|
||||
|
||||
| OPTION_Aarch
|
||||
{ ldfile_add_arch($1); }
|
||||
| OPTION_b NAME
|
||||
{
|
||||
lang_add_target($2);
|
||||
}
|
||||
| OPTION_L
|
||||
{
|
||||
ldfile_add_library_path($1);
|
||||
}
|
||||
| ifile_p1
|
||||
| input_list
|
||||
| OPTION_c filename
|
||||
{ ldfile_open_command_file($2); }
|
||||
| OPTION_Tfile
|
||||
{ ldfile_open_command_file($1); }
|
||||
|
||||
| OPTION_T filename
|
||||
{ ldfile_open_command_file($2); }
|
||||
|
||||
| OPTION_l
|
||||
{
|
||||
lang_add_input_file($1,
|
||||
lang_input_file_is_l_enum,
|
||||
(char *)NULL);
|
||||
}
|
||||
| OPTION_A filename
|
||||
{
|
||||
lang_add_input_file($2,
|
||||
lang_input_file_is_symbols_only_enum,
|
||||
(char *)NULL);
|
||||
}
|
||||
| OPTION_defsym assignment_with_nospaces
|
||||
;
|
||||
|
||||
|
||||
input_section_spec:
|
||||
NAME
|
||||
{
|
||||
lang_add_wild((char *)NULL, $1);
|
||||
}
|
||||
| '['
|
||||
{
|
||||
current_file = (char *)NULL;
|
||||
}
|
||||
file_NAME_list
|
||||
']'
|
||||
| NAME
|
||||
{
|
||||
current_file =$1;
|
||||
}
|
||||
'(' file_NAME_list ')'
|
||||
| '*'
|
||||
{
|
||||
current_file = (char *)NULL;
|
||||
}
|
||||
'(' file_NAME_list ')'
|
||||
;
|
||||
|
||||
|
||||
|
||||
file_NAME_list:
|
||||
NAME
|
||||
{ lang_add_wild($1, current_file); }
|
||||
| file_NAME_list opt_comma NAME
|
||||
{ lang_add_wild($3, current_file); }
|
||||
;
|
||||
|
||||
|
||||
|
||||
ifile_p1:
|
||||
memory
|
||||
| sections
|
||||
| startup
|
||||
| high_level_library
|
||||
| low_level_library
|
||||
| floating_point_support
|
||||
| assignment end
|
||||
| TARGET_K '(' NAME ')'
|
||||
{ lang_add_target($3); }
|
||||
| SEARCH_DIR '(' filename ')'
|
||||
{ ldfile_add_library_path($3); }
|
||||
| OUTPUT '(' filename ')'
|
||||
{ lang_add_output($3); }
|
||||
| INPUT '(' input_list ')'
|
||||
| MAP '(' filename ')'
|
||||
{ lang_add_map($3); }
|
||||
;
|
||||
|
||||
input_list:
|
||||
NAME
|
||||
{ lang_add_input_file($1,lang_input_file_is_file_enum,
|
||||
(char *)NULL); }
|
||||
| input_list ',' NAME
|
||||
{ lang_add_input_file($3,lang_input_file_is_file_enum,
|
||||
(char *)NULL); }
|
||||
| input_list NAME
|
||||
{ lang_add_input_file($2, lang_input_file_is_file_enum,
|
||||
(char *)NULL); }
|
||||
;
|
||||
|
||||
sections:
|
||||
SECTIONS '{'sec_or_group_p1 '}'
|
||||
;
|
||||
|
||||
sec_or_group_p1:
|
||||
sec_or_group_p1 section
|
||||
| sec_or_group_p1 statement_anywhere
|
||||
|
|
||||
;
|
||||
|
||||
statement_anywhere:
|
||||
ENTRY '(' NAME ')'
|
||||
{ lang_add_entry($3); }
|
||||
| assignment end
|
||||
;
|
||||
|
||||
statement:
|
||||
statement assignment end
|
||||
| statement CREATE_OBJECT_SYMBOLS
|
||||
{ lang_add_attribute(lang_object_symbols_statement_enum); }
|
||||
| statement input_section_spec
|
||||
| statement length '(' exp_head ')'
|
||||
{
|
||||
lang_add_data($2,$4);
|
||||
}
|
||||
|
||||
| statement FILL '(' exp_head ')'
|
||||
{
|
||||
lang_add_fill
|
||||
(exp_get_value_int($4,
|
||||
0,
|
||||
"fill value",
|
||||
lang_first_phase_enum));
|
||||
}
|
||||
|
|
||||
;
|
||||
|
||||
length:
|
||||
LONG
|
||||
{ $$ = $1; }
|
||||
| SHORT
|
||||
{ $$ = $1; }
|
||||
| BYTE
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
fill_opt:
|
||||
'=' exp_head
|
||||
{
|
||||
$$ = exp_get_value_int($2,
|
||||
0,
|
||||
"fill value",
|
||||
lang_first_phase_enum);
|
||||
}
|
||||
| { $$ = 0; }
|
||||
;
|
||||
|
||||
|
||||
|
||||
assign_op:
|
||||
PLUSEQ
|
||||
{ $$ = '+'; }
|
||||
| MINUSEQ
|
||||
{ $$ = '-'; }
|
||||
| MULTEQ
|
||||
{ $$ = '*'; }
|
||||
| DIVEQ
|
||||
{ $$ = '/'; }
|
||||
| LSHIFTEQ
|
||||
{ $$ = LSHIFT; }
|
||||
| RSHIFTEQ
|
||||
{ $$ = RSHIFT; }
|
||||
| ANDEQ
|
||||
{ $$ = '&'; }
|
||||
| OREQ
|
||||
{ $$ = '|'; }
|
||||
|
||||
;
|
||||
|
||||
end: ';' | ','
|
||||
;
|
||||
|
||||
assignment_with_nospaces:
|
||||
{ ldgram_want_filename = false; }
|
||||
assignment
|
||||
{ ldgram_want_filename = true; }
|
||||
;
|
||||
|
||||
assignment:
|
||||
|
||||
NAME '=' exp_head
|
||||
{
|
||||
lang_add_assignment(exp_assop($2,$1,$3));
|
||||
}
|
||||
| NAME assign_op exp_head
|
||||
{
|
||||
lang_add_assignment(exp_assop('=',$1,exp_binop($2,exp_nameop(NAME,$1),$3)));
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
|
||||
opt_comma:
|
||||
',' | ;
|
||||
|
||||
|
||||
memory:
|
||||
MEMORY '{' memory_spec memory_spec_list '}'
|
||||
;
|
||||
|
||||
memory_spec_list:
|
||||
memory_spec_list memory_spec
|
||||
| memory_spec_list ',' memory_spec
|
||||
|
|
||||
;
|
||||
|
||||
|
||||
memory_spec:
|
||||
NAME
|
||||
{ region = lang_memory_region_lookup($1); }
|
||||
attributes_opt ':' origin_spec opt_comma length_spec
|
||||
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
;
|
||||
origin_spec:
|
||||
ORIGIN '=' exp
|
||||
{ region->current =
|
||||
region->origin =
|
||||
exp_get_vma($3, 0L,"origin", lang_first_phase_enum); }
|
||||
;
|
||||
length_spec:
|
||||
LENGTH '=' exp
|
||||
{ region->length = exp_get_vma($3,
|
||||
~((bfd_vma)0),
|
||||
"length",
|
||||
lang_first_phase_enum);
|
||||
}
|
||||
|
||||
|
||||
attributes_opt:
|
||||
'(' NAME ')'
|
||||
{
|
||||
lang_set_flags(®ion->flags, $2);
|
||||
}
|
||||
|
|
||||
|
||||
;
|
||||
|
||||
startup:
|
||||
STARTUP '(' filename ')'
|
||||
{ lang_startup($3); }
|
||||
;
|
||||
|
||||
high_level_library:
|
||||
HLL '(' high_level_library_NAME_list ')'
|
||||
| HLL '(' ')'
|
||||
{ ldemul_hll((char *)NULL); }
|
||||
;
|
||||
|
||||
high_level_library_NAME_list:
|
||||
high_level_library_NAME_list opt_comma filename
|
||||
{ ldemul_hll($3); }
|
||||
| filename
|
||||
{ ldemul_hll($1); }
|
||||
|
||||
;
|
||||
|
||||
low_level_library:
|
||||
SYSLIB '(' low_level_library_NAME_list ')'
|
||||
;
|
||||
low_level_library_NAME_list:
|
||||
low_level_library_NAME_list opt_comma filename
|
||||
{ ldemul_syslib($3); }
|
||||
|
|
||||
;
|
||||
|
||||
floating_point_support:
|
||||
FLOAT
|
||||
{ lang_float(true); }
|
||||
| NOFLOAT
|
||||
{ lang_float(false); }
|
||||
;
|
||||
|
||||
|
||||
|
||||
|
||||
exp :
|
||||
'-' exp %prec UNARY
|
||||
{ $$ = exp_unop('-', $2); }
|
||||
| '(' exp ')'
|
||||
{ $$ = $2; }
|
||||
| NEXT '(' exp ')' %prec UNARY
|
||||
{ $$ = exp_unop($1,$3); }
|
||||
| '!' exp %prec UNARY
|
||||
{ $$ = exp_unop('!', $2); }
|
||||
| '+' exp %prec UNARY
|
||||
{ $$ = $2; }
|
||||
| '~' exp %prec UNARY
|
||||
{ $$ = exp_unop('~', $2);}
|
||||
|
||||
| exp '*' exp
|
||||
{ $$ = exp_binop('*', $1, $3); }
|
||||
| exp '/' exp
|
||||
{ $$ = exp_binop('/', $1, $3); }
|
||||
| exp '%' exp
|
||||
{ $$ = exp_binop('%', $1, $3); }
|
||||
| exp '+' exp
|
||||
{ $$ = exp_binop('+', $1, $3); }
|
||||
| exp '-' exp
|
||||
{ $$ = exp_binop('-' , $1, $3); }
|
||||
| exp LSHIFT exp
|
||||
{ $$ = exp_binop(LSHIFT , $1, $3); }
|
||||
| exp RSHIFT exp
|
||||
{ $$ = exp_binop(RSHIFT , $1, $3); }
|
||||
| exp EQ exp
|
||||
{ $$ = exp_binop(EQ , $1, $3); }
|
||||
| exp NE exp
|
||||
{ $$ = exp_binop(NE , $1, $3); }
|
||||
| exp LE exp
|
||||
{ $$ = exp_binop(LE , $1, $3); }
|
||||
| exp GE exp
|
||||
{ $$ = exp_binop(GE , $1, $3); }
|
||||
| exp '<' exp
|
||||
{ $$ = exp_binop('<' , $1, $3); }
|
||||
| exp '>' exp
|
||||
{ $$ = exp_binop('>' , $1, $3); }
|
||||
| exp '&' exp
|
||||
{ $$ = exp_binop('&' , $1, $3); }
|
||||
| exp '^' exp
|
||||
{ $$ = exp_binop('^' , $1, $3); }
|
||||
| exp '|' exp
|
||||
{ $$ = exp_binop('|' , $1, $3); }
|
||||
| exp '?' exp ':' exp
|
||||
{ $$ = exp_trinop('?' , $1, $3, $5); }
|
||||
| exp ANDAND exp
|
||||
{ $$ = exp_binop(ANDAND , $1, $3); }
|
||||
| exp OROR exp
|
||||
{ $$ = exp_binop(OROR , $1, $3); }
|
||||
| DEFINED '(' NAME ')'
|
||||
{ $$ = exp_nameop(DEFINED, $3); }
|
||||
| INT
|
||||
{ $$ = exp_intop($1); }
|
||||
|
||||
| SIZEOF '(' NAME ')'
|
||||
{ $$ = exp_nameop($1,$3); }
|
||||
| ADDR '(' NAME ')'
|
||||
{ $$ = exp_nameop($1,$3); }
|
||||
| ALIGN_K '(' exp ')'
|
||||
{ $$ = exp_unop($1,$3); }
|
||||
| NAME
|
||||
{ $$ = exp_nameop(NAME,$1); }
|
||||
;
|
||||
|
||||
|
||||
|
||||
|
||||
section: NAME opt_exp opt_block ':' opt_things'{'
|
||||
{
|
||||
lang_enter_output_section_statement($1,$2,$3);
|
||||
}
|
||||
statement '}' fill_opt memspec_opt
|
||||
{
|
||||
lang_leave_output_section_statement($10, $11);
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
opt_things:
|
||||
{
|
||||
|
||||
}
|
||||
;
|
||||
|
||||
exp_head:
|
||||
{ ldgram_mustbe_symbolname = true; }
|
||||
exp
|
||||
{ ldgram_mustbe_symbolname = false;
|
||||
$$ = $2;
|
||||
}
|
||||
|
||||
opt_exp:
|
||||
exp
|
||||
{ $$ = $1; }
|
||||
| { $$= (etree_type *)NULL; }
|
||||
;
|
||||
|
||||
opt_block:
|
||||
BLOCK '(' exp_head ')'
|
||||
{ $$ = exp_get_value_int($3,
|
||||
1L,
|
||||
"block",
|
||||
lang_first_phase_enum);
|
||||
}
|
||||
| { $$ = 1; }
|
||||
;
|
||||
|
||||
memspec_opt:
|
||||
'>' NAME
|
||||
{ $$ = $2; }
|
||||
| { $$ = "*default*"; }
|
||||
;
|
||||
|
2231
ld/ldlang.c
Normal file
2231
ld/ldlang.c
Normal file
File diff suppressed because it is too large
Load diff
347
ld/ldlang.h
Normal file
347
ld/ldlang.h
Normal file
|
@ -0,0 +1,347 @@
|
|||
/* ldlang.h -
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
|
||||
typedef enum {
|
||||
lang_input_file_is_l_enum,
|
||||
lang_input_file_is_symbols_only_enum,
|
||||
lang_input_file_is_marker_enum,
|
||||
lang_input_file_is_fake_enum,
|
||||
lang_input_file_is_search_file_enum,
|
||||
lang_input_file_is_file_enum } lang_input_file_enum_type;
|
||||
|
||||
typedef unsigned short fill_type;
|
||||
typedef struct statement_list {
|
||||
union lang_statement_union *head;
|
||||
union lang_statement_union **tail;
|
||||
} lang_statement_list_type;
|
||||
|
||||
|
||||
typedef struct {
|
||||
boolean flag_read;
|
||||
boolean flag_write;
|
||||
boolean flag_executable;
|
||||
boolean flag_loadable;
|
||||
} lang_section_flags_type;
|
||||
|
||||
typedef struct memory_region_struct {
|
||||
char *name;
|
||||
struct memory_region_struct *next;
|
||||
bfd_vma origin;
|
||||
bfd_offset length;
|
||||
bfd_vma current;
|
||||
lang_section_flags_type flags;
|
||||
} lang_memory_region_type ;
|
||||
|
||||
typedef struct lang_statement_header_struct
|
||||
{
|
||||
union lang_statement_union *next;
|
||||
enum statement_enum {
|
||||
lang_output_section_statement_enum,
|
||||
lang_assignment_statement_enum,
|
||||
lang_input_statement_enum,
|
||||
lang_address_statement_enum,
|
||||
lang_wild_statement_enum,
|
||||
lang_input_section_enum,
|
||||
lang_common_statement_enum,
|
||||
lang_object_symbols_statement_enum,
|
||||
lang_fill_statement_enum,
|
||||
lang_data_statement_enum,
|
||||
lang_target_statement_enum,
|
||||
lang_output_statement_enum,
|
||||
lang_padding_statement_enum,
|
||||
|
||||
lang_afile_asection_pair_statement_enum
|
||||
} type;
|
||||
|
||||
} lang_statement_header_type;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
lang_statement_header_type header;
|
||||
union etree_union *exp;
|
||||
} lang_assignment_statement_type;
|
||||
|
||||
|
||||
typedef struct lang_target_statement_struct {
|
||||
lang_statement_header_type header;
|
||||
char *target;
|
||||
} lang_target_statement_type;
|
||||
|
||||
|
||||
typedef struct lang_output_statement_struct {
|
||||
lang_statement_header_type header;
|
||||
char *name;
|
||||
} lang_output_statement_type;
|
||||
|
||||
|
||||
typedef struct lang_output_section_statement_struct
|
||||
{
|
||||
lang_statement_header_type header;
|
||||
union etree_union *addr_tree;
|
||||
lang_statement_list_type children;
|
||||
char *memspec;
|
||||
union lang_statement_union *next;
|
||||
char *name;
|
||||
unsigned long subsection_alignment;
|
||||
boolean processed;
|
||||
|
||||
asection *bfd_section;
|
||||
lang_section_flags_type flags;
|
||||
struct memory_region_struct *region;
|
||||
size_t block_value;
|
||||
fill_type fill;
|
||||
} lang_output_section_statement_type;
|
||||
|
||||
|
||||
typedef struct {
|
||||
lang_statement_header_type header;
|
||||
} lang_common_statement_type;
|
||||
|
||||
typedef struct {
|
||||
lang_statement_header_type header;
|
||||
} lang_object_symbols_statement_type;
|
||||
|
||||
typedef struct {
|
||||
lang_statement_header_type header;
|
||||
fill_type fill;
|
||||
} lang_fill_statement_type;
|
||||
|
||||
typedef struct {
|
||||
lang_statement_header_type header;
|
||||
unsigned int type;
|
||||
union etree_union *exp;
|
||||
bfd_vma value;
|
||||
asection *output_section;
|
||||
bfd_vma output_vma;
|
||||
} lang_data_statement_type;
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct lang_input_statement_struct
|
||||
{
|
||||
lang_statement_header_type header;
|
||||
/* Name of this file. */
|
||||
char *filename;
|
||||
/* Name to use for the symbol giving address of text start */
|
||||
/* Usually the same as filename, but for a file spec'd with -l
|
||||
this is the -l switch itself rather than the filename. */
|
||||
char *local_sym_name;
|
||||
|
||||
/* Describe the layout of the contents of the file */
|
||||
|
||||
/* The file's a.out header. */
|
||||
/* struct exec header;*/
|
||||
/* Offset in file of GDB symbol segment, or 0 if there is none. */
|
||||
int symseg_offset;
|
||||
|
||||
/* Describe data from the file loaded into core */
|
||||
|
||||
bfd *the_bfd;
|
||||
|
||||
boolean closed;
|
||||
file_ptr passive_position;
|
||||
|
||||
/* Symbol table of the file. */
|
||||
asymbol **asymbols;
|
||||
unsigned int symbol_count;
|
||||
|
||||
/* Next two used only if `relocatable_output' or if needed for */
|
||||
/* output of undefined reference line numbers. */
|
||||
/* Text reloc info saved by `write_text' for `coptxtrel'. */
|
||||
|
||||
|
||||
/* Offset in bytes in the output file symbol table
|
||||
of the first local symbol for this file. Set by `write_file_symbols'. */
|
||||
int local_syms_offset;
|
||||
|
||||
/* For library members only */
|
||||
|
||||
/* For a library, points to chain of entries for the library members. */
|
||||
struct lang_input_statement_struct *subfiles;
|
||||
/* For a library member, offset of the member within the archive.
|
||||
Zero for files that are not library members. */
|
||||
/* int starting_offset;*/
|
||||
/* Size of contents of this file, if library member. */
|
||||
int total_size;
|
||||
/* For library member, points to the library's own entry. */
|
||||
struct lang_input_statement_struct *superfile;
|
||||
/* For library member, points to next entry for next member. */
|
||||
struct lang_input_statement_struct *chain;
|
||||
/* Point to the next file - whatever it is, wanders up and down archives */
|
||||
union lang_statement_union *next;
|
||||
/* Point to the next file, but skips archive contents */
|
||||
union lang_statement_union *next_real_file;
|
||||
|
||||
boolean is_archive;
|
||||
|
||||
/* 1 if file's header has been read into this structure. */
|
||||
boolean header_read_flag;
|
||||
|
||||
/* 1 means search a set of directories for this file. */
|
||||
boolean search_dirs_flag;
|
||||
|
||||
/* 1 means this is base file of incremental load.
|
||||
Do not load this file's text or data.
|
||||
Also default text_start to after this file's bss. */
|
||||
boolean just_syms_flag;
|
||||
|
||||
boolean loaded;
|
||||
|
||||
|
||||
/* unsigned int globals_in_this_file;*/
|
||||
char *target;
|
||||
boolean real;
|
||||
|
||||
asection *common_section;
|
||||
asection *common_output_section;
|
||||
} lang_input_statement_type;
|
||||
|
||||
typedef struct {
|
||||
lang_statement_header_type header;
|
||||
asection *section;
|
||||
lang_input_statement_type *ifile;
|
||||
} lang_input_section_type;
|
||||
|
||||
|
||||
typedef struct {
|
||||
lang_statement_header_type header;
|
||||
asection *section;
|
||||
union lang_statement_union *file;
|
||||
} lang_afile_asection_pair_statement_type;
|
||||
|
||||
typedef struct lang_wild_statement_struct {
|
||||
lang_statement_header_type header;
|
||||
char *section_name;
|
||||
char *filename;
|
||||
lang_statement_list_type children;
|
||||
} lang_wild_statement_type;
|
||||
|
||||
typedef struct lang_address_statement_struct {
|
||||
lang_statement_header_type header;
|
||||
char *section_name;
|
||||
union etree_union *address;
|
||||
} lang_address_statement_type;
|
||||
|
||||
typedef struct {
|
||||
lang_statement_header_type header;
|
||||
bfd_vma output_offset;
|
||||
size_t size;
|
||||
asection *output_section;
|
||||
fill_type fill;
|
||||
} lang_padding_statement_type;
|
||||
|
||||
typedef union lang_statement_union
|
||||
{
|
||||
lang_statement_header_type header;
|
||||
union lang_statement_union *next;
|
||||
lang_wild_statement_type wild_statement;
|
||||
lang_data_statement_type data_statement;
|
||||
lang_address_statement_type address_statement;
|
||||
lang_output_section_statement_type output_section_statement;
|
||||
lang_afile_asection_pair_statement_type afile_asection_pair_statement;
|
||||
lang_assignment_statement_type assignment_statement;
|
||||
lang_input_statement_type input_statement;
|
||||
lang_target_statement_type target_statement;
|
||||
lang_output_statement_type output_statement;
|
||||
lang_input_section_type input_section;
|
||||
lang_common_statement_type common_statement;
|
||||
lang_object_symbols_statement_type object_symbols_statement;
|
||||
lang_fill_statement_type fill_statement;
|
||||
lang_padding_statement_type padding_statement;
|
||||
} lang_statement_union_type;
|
||||
|
||||
|
||||
|
||||
PROTO(void,lang_init,(void));
|
||||
PROTO(struct memory_region_struct ,*lang_memory_region_lookup,(char *));
|
||||
PROTO(struct lang_output_section_statement_struct *,lang_output_section_find,(char *));
|
||||
|
||||
PROTO(void ,lang_map,(struct _iobuf *));
|
||||
PROTO(void,lang_set_flags,(lang_section_flags_type *, char *));
|
||||
PROTO(void,lang_add_output,(char *));
|
||||
|
||||
PROTO(void,lang_final,(void));
|
||||
PROTO(struct symbol_cache_entry *,create_symbol,(char *, unsigned int, struct sec_struct *));
|
||||
PROTO(void ,lang_process,(void));
|
||||
PROTO(void ,lang_section_start,(char *, union etree_union *));
|
||||
PROTO(void,lang_add_entry,(char *));
|
||||
PROTO(void,lang_add_target,(char *));
|
||||
PROTO(void,lang_add_wild,(char *, char *));
|
||||
PROTO(void,lang_add_map,(char *));
|
||||
PROTO(void,lang_add_fill,(int));
|
||||
PROTO(void,lang_add_assignment,(union etree_union *));
|
||||
PROTO(void,lang_add_attribute,(enum statement_enum));
|
||||
PROTO(void,lang_startup,(char *));
|
||||
PROTO(void,lang_float,(enum boolean));
|
||||
PROTO(void,lang_leave_output_section_statement,(bfd_vma, char *));
|
||||
PROTO(void,lang_abs_symbol_at_end_of,(char *, char *));
|
||||
PROTO(void,lang_statement_append,(struct statement_list *, union lang_statement_union *, union lang_statement_union **));
|
||||
PROTO(void, lang_for_each_file,(void (*dothis)(lang_input_statement_type *)));
|
||||
|
||||
#define LANG_FOR_EACH_ASYMBOL(asymbol) \
|
||||
|
||||
#define LANG_FOR_EACH_INPUT_STATEMENT(statement) \
|
||||
extern lang_statement_list_type file_chain; \
|
||||
lang_input_statement_type *statement; \
|
||||
for (statement = (lang_input_statement_type *)file_chain.head;\
|
||||
statement != (lang_input_statement_type *)NULL; \
|
||||
statement = (lang_input_statement_type *)statement->next)\
|
||||
|
||||
#define LANG_FOR_EACH_INPUT_SECTION(statement, abfd, section, x) \
|
||||
{ extern lang_statement_list_type file_chain; \
|
||||
lang_input_statement_type *statement; \
|
||||
for (statement = (lang_input_statement_type *)file_chain.head;\
|
||||
statement != (lang_input_statement_type *)NULL; \
|
||||
statement = (lang_input_statement_type *)statement->next)\
|
||||
{ \
|
||||
asection *section; \
|
||||
bfd *abfd = statement->the_bfd; \
|
||||
for (section = abfd->sections; \
|
||||
section != (asection *)NULL; \
|
||||
section = section->next) { \
|
||||
x; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define LANG_FOR_EACH_OUTPUT_SECTION(section, x) \
|
||||
{ extern bfd *output_bfd; \
|
||||
asection *section; \
|
||||
for (section = output_bfd->sections; \
|
||||
section != (asection *)NULL; \
|
||||
section = section->next) \
|
||||
{ x; } \
|
||||
}
|
||||
|
||||
|
||||
PROTO(void, lang_process,(void));
|
||||
PROTO(void, ldlang_add_file,(lang_input_statement_type *));
|
||||
|
||||
PROTO(lang_output_section_statement_type *,lang_output_section_find,());
|
||||
|
||||
PROTO(lang_input_statement_type *,
|
||||
lang_add_input_file,(char *name,
|
||||
lang_input_file_enum_type file_type,
|
||||
char *target));
|
||||
PROTO(lang_output_section_statement_type *,
|
||||
lang_output_section_statement_lookup,(char *name));
|
26
ld/ldlex.h
Normal file
26
ld/ldlex.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* ldlex.h -
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
PROTO(int, lex_input, (void));
|
||||
PROTO(void, lex_unput, (int));
|
||||
PROTO(int ,yywrap,(void));
|
||||
PROTO(void, parse_args,(int, char **));
|
||||
PROTO(void, parse_line,(char*));
|
||||
|
490
ld/ldlex.l
Normal file
490
ld/ldlex.l
Normal file
|
@ -0,0 +1,490 @@
|
|||
%{
|
||||
/* Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.1 1991/03/21 21:28:50 gumby
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.3 1991/03/16 22:27:24 rich
|
||||
* fish
|
||||
*
|
||||
* Revision 1.2 1991/03/15 18:45:55 rich
|
||||
* foo
|
||||
*
|
||||
* Revision 1.1 1991/03/13 00:48:27 chrisb
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.6 1991/03/10 09:31:32 rich
|
||||
* Modified Files:
|
||||
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
|
||||
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
|
||||
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
|
||||
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
|
||||
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
|
||||
*
|
||||
* As of this round of changes, ld now builds on all hosts of (Intel960)
|
||||
* interest and copy passes my copy test on big endian hosts again.
|
||||
*
|
||||
* Revision 1.5 1991/03/09 03:25:49 sac
|
||||
* Can now parse the -Ur flag
|
||||
*
|
||||
* Revision 1.4 1991/03/06 02:26:04 sac
|
||||
* Added support for constructor sections.
|
||||
* Remove parsing ambiguity.
|
||||
* Lint
|
||||
*
|
||||
* Revision 1.3 1991/02/22 17:15:14 sac
|
||||
* Added RCS keywords and copyrights
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*SUPPRESS 529*/
|
||||
/*SUPPRESS 26*/
|
||||
/*SUPPRESS 29*/
|
||||
#define LEXDEBUG
|
||||
#include "sysdep.h"
|
||||
#include "bfd.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include "ldlex.h"
|
||||
|
||||
#include "ld.h"
|
||||
#include "ldexp.h"
|
||||
#include "ldgram.tab.h"
|
||||
#include "ldmisc.h"
|
||||
|
||||
#undef input
|
||||
#undef unput
|
||||
#define input lex_input
|
||||
#define unput lex_unput
|
||||
int debug;
|
||||
extern boolean ldgram_want_filename;
|
||||
extern boolean ldgram_mustbe_filename;
|
||||
extern boolean ldgram_mustbe_symbolname;
|
||||
static char *command_line;
|
||||
|
||||
extern int fgetc();
|
||||
extern int yyparse();
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int value;
|
||||
} keyword_type;
|
||||
#define RTOKEN(x) { yylval.token = x; return x; }
|
||||
keyword_type keywords[] =
|
||||
{
|
||||
"MEMORY",MEMORY,
|
||||
"ORIGIN",ORIGIN,
|
||||
"BLOCK",BLOCK,
|
||||
"LENGTH",LENGTH,
|
||||
"ALIGN",ALIGN_K,
|
||||
"SUBSECTION_ALIGN",SUBSECTION_ALIGN,
|
||||
"ADDR",ADDR,
|
||||
"ENTRY",ENTRY,
|
||||
"NEXT",NEXT,
|
||||
"MAP",MAP,
|
||||
"SIZEOF",SIZEOF,
|
||||
"TARGET",TARGET_K,
|
||||
"SEARCH_DIR",SEARCH_DIR,
|
||||
"OUTPUT",OUTPUT,
|
||||
"INPUT",INPUT,
|
||||
"DEFINED",DEFINED,
|
||||
"CREATE_OBJECT_SYMBOLS",CREATE_OBJECT_SYMBOLS,
|
||||
"SECTIONS",SECTIONS,
|
||||
"FILL",FILL,
|
||||
"STARTUP",STARTUP,
|
||||
"HLL",HLL,
|
||||
"SYSLIB",SYSLIB,
|
||||
"FLOAT",FLOAT,
|
||||
"LONG", LONG,
|
||||
"SHORT", SHORT,
|
||||
"BYTE", BYTE,
|
||||
"NOFLOAT",NOFLOAT,
|
||||
"o",ORIGIN,
|
||||
"org",ORIGIN,
|
||||
"l", LENGTH,
|
||||
"len", LENGTH,
|
||||
0,0};
|
||||
unsigned int lineno;
|
||||
extern boolean hex_mode;
|
||||
FILE *ldlex_input_stack;
|
||||
static unsigned int have_pushback;
|
||||
#define NPUSHBACK 10
|
||||
int pushback[NPUSHBACK];
|
||||
int thischar;
|
||||
extern char *ldfile_input_filename;
|
||||
|
||||
int
|
||||
lex_input()
|
||||
{
|
||||
/*
|
||||
When we know that the next token must be a filename we force the
|
||||
input routine to return a '#' character, which will cause the special
|
||||
filname regexp to match the following chars even if they don't look
|
||||
much like a filename to any sane person.
|
||||
*/
|
||||
if (ldgram_mustbe_filename) {
|
||||
ldgram_mustbe_filename = false;
|
||||
return '#';
|
||||
}
|
||||
|
||||
if (have_pushback > 0)
|
||||
{
|
||||
have_pushback --;
|
||||
return thischar = pushback[have_pushback];
|
||||
}
|
||||
if (ldlex_input_stack) {
|
||||
thischar = fgetc(ldlex_input_stack);
|
||||
|
||||
if (thischar == EOF) {
|
||||
fclose(ldlex_input_stack);
|
||||
ldlex_input_stack = (FILE *)NULL;
|
||||
ldfile_input_filename = (char *)NULL;
|
||||
thischar = lex_input();
|
||||
|
||||
}
|
||||
}
|
||||
else if (command_line && *command_line) {
|
||||
thischar = *(command_line++);
|
||||
}
|
||||
else thischar = 0;
|
||||
if(thischar == '\t') thischar = ' ';
|
||||
return thischar ;
|
||||
}
|
||||
|
||||
void
|
||||
lex_unput(c)
|
||||
int c;
|
||||
{
|
||||
if (have_pushback > NPUSHBACK) {
|
||||
info("%F%P Too many pushbacks\n");
|
||||
}
|
||||
|
||||
pushback[have_pushback] = c;
|
||||
have_pushback ++;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
yywrap()
|
||||
{ return 1; }
|
||||
/*VARARGS*/
|
||||
|
||||
void
|
||||
allprint(x)
|
||||
int x;
|
||||
{
|
||||
fprintf(yyout,"%d",x);
|
||||
}
|
||||
|
||||
void
|
||||
sprint(x)
|
||||
char *x;
|
||||
{
|
||||
fprintf(yyout,"%s",x);
|
||||
}
|
||||
|
||||
int thischar;
|
||||
|
||||
void parse_line(arg)
|
||||
char *arg;
|
||||
{
|
||||
command_line = arg;
|
||||
have_pushback = 0;
|
||||
yyparse();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
parse_args(ac, av)
|
||||
int ac;
|
||||
char **av;
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
size_t size = 0;
|
||||
char *dst;
|
||||
debug = 1;
|
||||
for (i= 1; i < ac; i++) {
|
||||
size += strlen(av[i]) + 2;
|
||||
}
|
||||
dst = p = (char *)ldmalloc(size + 2);
|
||||
/* Put a space arount each option */
|
||||
|
||||
|
||||
for (i =1; i < ac; i++) {
|
||||
|
||||
unsigned int s = strlen(av[i]);
|
||||
*dst++ = ' ';
|
||||
memcpy(dst, av[i], s);
|
||||
dst[s] = ' ';
|
||||
dst += s + 1;
|
||||
}
|
||||
*dst = 0;
|
||||
parse_line(p);
|
||||
|
||||
free(p);
|
||||
|
||||
|
||||
}
|
||||
|
||||
long number(text, base)
|
||||
char *text;
|
||||
int base;
|
||||
{
|
||||
unsigned long l = 0;
|
||||
char *p;
|
||||
for (p = text; *p != 0; p++) {
|
||||
if (*p == 'K') {
|
||||
l =l * 1024;
|
||||
}
|
||||
else if(*p== 'M') {
|
||||
l =l * 1024 * 1024;
|
||||
}
|
||||
else {
|
||||
l =l * base;
|
||||
if (isdigit(*p)) {
|
||||
l += *p - '0';
|
||||
}
|
||||
else if (islower(*p)) {
|
||||
l += *p - 'a' + 10;
|
||||
}
|
||||
else {
|
||||
l += *p - 'A' + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
%}
|
||||
|
||||
%a 4000
|
||||
%o 5000
|
||||
FILENAMECHAR [a-zA-Z0-9\/\.\-\_\+]
|
||||
FILENAME {FILENAMECHAR}+
|
||||
|
||||
|
||||
WHITE [ \t]+
|
||||
|
||||
%%
|
||||
"\n" { lineno++; }
|
||||
|
||||
|
||||
"\ -defsym" { return OPTION_defsym; }
|
||||
"\ -noinhibit_exec" { return OPTION_noinhibit_exec; }
|
||||
"\ -format" { return OPTION_format; }
|
||||
"\ -n" { return OPTION_n; }
|
||||
"\ -r" { return OPTION_r; }
|
||||
"\ -Ur" { return OPTION_Ur; }
|
||||
"\ -o" { return OPTION_o; }
|
||||
"\ -g" { return OPTION_g; }
|
||||
"\ -e" { return OPTION_e; }
|
||||
"\ -b" { return OPTION_b; }
|
||||
"\ -dc" { return OPTION_dc; }
|
||||
"\ -dp" { return OPTION_dp; }
|
||||
"\ -d" { return OPTION_d; }
|
||||
"\ -v" { return OPTION_v; }
|
||||
"\ -M" { return OPTION_M; }
|
||||
"\ -t" { return OPTION_t; }
|
||||
"\ -X" { return OPTION_X; }
|
||||
"\ -x" { return OPTION_x; }
|
||||
"\ -c" { return OPTION_c; }
|
||||
"\ -s" { return OPTION_s; }
|
||||
"\ -S" { return OPTION_S; }
|
||||
"\ -l"{FILENAME} {
|
||||
yylval.name = buystring(yytext+3);
|
||||
return OPTION_l;
|
||||
}
|
||||
|
||||
"\ -L"{FILENAME} {
|
||||
yylval.name = buystring(yytext+3);
|
||||
return OPTION_L;
|
||||
}
|
||||
"\ -Ttext" {
|
||||
yylval.name = ".text";
|
||||
return OPTION_Texp;
|
||||
}
|
||||
"\ -Tdata" {
|
||||
yylval.name = ".data";
|
||||
return OPTION_Texp;
|
||||
}
|
||||
"\ -Tbss" {
|
||||
yylval.name = ".bss";
|
||||
return OPTION_Texp;
|
||||
}
|
||||
|
||||
"\ -T"{FILENAME} {
|
||||
yylval.name = buystring(yytext+3);
|
||||
return OPTION_Tfile;
|
||||
}
|
||||
"\ -T" {
|
||||
return OPTION_T;
|
||||
}
|
||||
|
||||
"\ -A"{FILENAME} {
|
||||
yylval.name = buystring(yytext+3);
|
||||
return OPTION_Aarch;
|
||||
}
|
||||
" " { }
|
||||
"<<=" { RTOKEN(LSHIFTEQ);}
|
||||
">>=" { RTOKEN(RSHIFTEQ);}
|
||||
"||" { RTOKEN(OROR);}
|
||||
"==" { RTOKEN(EQ);}
|
||||
"!=" { RTOKEN(NE);}
|
||||
">=" { RTOKEN(GE);}
|
||||
"<=" { RTOKEN(LE);}
|
||||
"<<" { RTOKEN(LSHIFT);}
|
||||
">>" { RTOKEN(RSHIFT);}
|
||||
"+=" { RTOKEN(PLUSEQ);}
|
||||
"-=" { RTOKEN(MINUSEQ);}
|
||||
"*=" { RTOKEN(MULTEQ);}
|
||||
"/=" { RTOKEN(DIVEQ);}
|
||||
"&=" { RTOKEN(ANDEQ);}
|
||||
"|=" { RTOKEN(OREQ);}
|
||||
|
||||
"&&" { RTOKEN(ANDAND);}
|
||||
">" { RTOKEN('>');}
|
||||
"," { RTOKEN(',');}
|
||||
"&" { RTOKEN('&');}
|
||||
"|" { RTOKEN('|');}
|
||||
"~" { RTOKEN('~');}
|
||||
"!" { RTOKEN('!');}
|
||||
"?" { RTOKEN('?');}
|
||||
"*" { RTOKEN('*');}
|
||||
"%" { RTOKEN('%');}
|
||||
"<" { RTOKEN('<');}
|
||||
"+" { RTOKEN('+');}
|
||||
">" { RTOKEN('>');}
|
||||
"}" { RTOKEN('}') ; }
|
||||
"{" { RTOKEN('{'); }
|
||||
")" { RTOKEN(')');}
|
||||
"(" { RTOKEN('(');}
|
||||
"]" { RTOKEN(']');}
|
||||
"[" { RTOKEN('[');}
|
||||
":" { RTOKEN(':'); }
|
||||
";" { RTOKEN(';');}
|
||||
"-" { RTOKEN('-');}
|
||||
"=" { RTOKEN('=');}
|
||||
|
||||
|
||||
"/*" {
|
||||
while (1) {
|
||||
int ch;
|
||||
ch = input();
|
||||
while (ch != '*') {
|
||||
if (ch == '\n') {lineno++; }
|
||||
ch = input();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (input() == '/') {
|
||||
break;
|
||||
}
|
||||
unput(yytext[yyleng-1]);
|
||||
}
|
||||
}
|
||||
|
||||
"\""[^\"]*"\"" {
|
||||
|
||||
yylval.name = buystring(yytext+1);
|
||||
yylval.name[yyleng-2] = 0; /* Fry final quote */
|
||||
return NAME;
|
||||
}
|
||||
[0][0-7KM]* {
|
||||
|
||||
yylval.integer = number(yytext+1, 8);
|
||||
return INT;
|
||||
}
|
||||
|
||||
[0-9]+[KM]? {
|
||||
if (hex_mode == true) {
|
||||
yylval.integer = number(yytext, 16);
|
||||
}
|
||||
else {
|
||||
yylval.integer = number(yytext, 10);
|
||||
}
|
||||
return INT;
|
||||
}
|
||||
|
||||
0[Xx][0-9a-fA-FKM]+ {
|
||||
|
||||
yylval.integer = number(yytext+2,16);
|
||||
return INT;
|
||||
}
|
||||
|
||||
"\#"{WHITE}*{FILENAMECHAR}+ {
|
||||
char *p = yytext+1;
|
||||
while(*p ==' ' || *p == '\t') p++;
|
||||
yylval.name = buystring(p);
|
||||
return NAME;
|
||||
}
|
||||
|
||||
|
||||
{FILENAMECHAR} {
|
||||
|
||||
int ch;
|
||||
keyword_type *k;
|
||||
if (yytext[0] == '/' && ldgram_mustbe_symbolname)
|
||||
{ RTOKEN('/');}
|
||||
ch = input();
|
||||
while (true) {
|
||||
if (isalpha(ch) || isdigit(ch) || ch == '.' || ch == '_') {
|
||||
yytext[yyleng++] = ch;
|
||||
}
|
||||
else if (ch == '-' && ldgram_want_filename == true) {
|
||||
yytext[yyleng++] = ch;
|
||||
}
|
||||
else if (ch == '+' && ldgram_want_filename == true) {
|
||||
yytext[yyleng++] = ch;
|
||||
}
|
||||
|
||||
else if (ch == '/' && ldgram_want_filename == true) {
|
||||
yytext[yyleng++] = ch;
|
||||
}
|
||||
|
||||
else break;
|
||||
ch = input();
|
||||
}
|
||||
|
||||
yytext[yyleng] = 0;
|
||||
unput(ch);
|
||||
|
||||
for(k = keywords; k ->name != (char *)NULL; k++) {
|
||||
|
||||
if (strcmp(k->name, yytext)==0) {
|
||||
yylval.token = k->value;
|
||||
return k->value;
|
||||
}
|
||||
}
|
||||
yylval.name = buystring(yytext);
|
||||
return NAME;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%%
|
806
ld/ldmain.c
Normal file
806
ld/ldmain.c
Normal file
|
@ -0,0 +1,806 @@
|
|||
/* Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*
|
||||
* Written by Steve Chamberlain steve@cygnus.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.1 1991/03/21 21:28:52 gumby
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.1 1991/03/13 00:48:27 chrisb
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.7 1991/03/10 19:15:45 sac
|
||||
* Fixed a prototype problem
|
||||
*
|
||||
* Revision 1.6 1991/03/10 09:31:32 rich
|
||||
* Modified Files:
|
||||
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
|
||||
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
|
||||
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
|
||||
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
|
||||
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
|
||||
*
|
||||
* As of this round of changes, ld now builds on all hosts of (Intel960)
|
||||
* interest and copy passes my copy test on big endian hosts again.
|
||||
*
|
||||
* Revision 1.5 1991/03/09 03:31:02 sac
|
||||
* After a fatal info message, the output file is deleted.
|
||||
*
|
||||
* Revision 1.4 1991/03/06 02:28:31 sac
|
||||
* Fixed partial linking and error messages.
|
||||
*
|
||||
* Revision 1.3 1991/02/22 17:15:02 sac
|
||||
* Added RCS keywords and copyrights
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "sysdep.h"
|
||||
#include "bfd.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "ld.h"
|
||||
#include "ldmain.h"
|
||||
#include "ldmisc.h"
|
||||
#include "ldwrite.h"
|
||||
#include "ldgram.h"
|
||||
#include "ldsym.h"
|
||||
#include "ldlang.h"
|
||||
#include "ld-emul.h"
|
||||
#include "ldlex.h"
|
||||
#include "ldfile.h"
|
||||
|
||||
/* IMPORTS */
|
||||
extern boolean lang_has_input_file;
|
||||
|
||||
/* EXPORTS */
|
||||
|
||||
char *default_target;
|
||||
char *output_filename = "a.out";
|
||||
/* Name this program was invoked by. */
|
||||
char *program_name;
|
||||
|
||||
/* The file that we're creating */
|
||||
bfd *output_bfd;
|
||||
|
||||
extern boolean option_v;
|
||||
|
||||
/* The local symbol prefix */
|
||||
char lprefix = 'L';
|
||||
|
||||
/* Count the number of global symbols multiply defined. */
|
||||
int multiple_def_count;
|
||||
|
||||
|
||||
/* Count the number of symbols defined through common declarations.
|
||||
This count is referenced in symdef_library, linear_library, and
|
||||
modified by enter_global_ref.
|
||||
|
||||
It is incremented when a symbol is created as a common, and
|
||||
decremented when the common declaration is overridden
|
||||
|
||||
Another way of thinking of it is that this is a count of
|
||||
all ldsym_types with a ->scoms field
|
||||
*/
|
||||
unsigned int commons_pending;
|
||||
|
||||
|
||||
/* Count the number of global symbols referenced and not defined.
|
||||
common symbols are not included in this count.
|
||||
*/
|
||||
|
||||
unsigned int undefined_global_sym_count;
|
||||
|
||||
|
||||
|
||||
/* Count the number of warning symbols encountered. */
|
||||
int warning_count;
|
||||
|
||||
/* have we had a load script ? */
|
||||
extern boolean had_script;
|
||||
|
||||
|
||||
|
||||
/* Nonzero means print names of input files as processed. */
|
||||
boolean trace_files;
|
||||
|
||||
|
||||
|
||||
/* 1 => write load map. */
|
||||
boolean write_map;
|
||||
|
||||
|
||||
int unix_relocate;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Force the make_executable to be output, even if there are non-fatal
|
||||
errors */
|
||||
boolean force_make_executable;
|
||||
|
||||
|
||||
/* A count of the total number of local symbols ever seen - by adding
|
||||
the symbol_count field of each newly read afile.*/
|
||||
|
||||
|
||||
unsigned int total_symbols_seen;
|
||||
|
||||
/* A count of the number of read files - the same as the number of elements
|
||||
in file_chain
|
||||
*/
|
||||
unsigned int total_files_seen;
|
||||
|
||||
|
||||
/* IMPORTS */
|
||||
args_type command_line;
|
||||
ld_config_type config;
|
||||
int
|
||||
main (argc, argv)
|
||||
char **argv;
|
||||
int argc;
|
||||
{
|
||||
char *emulation;
|
||||
program_name = argv[0];
|
||||
output_filename = "a.out";
|
||||
|
||||
emulation = getenv(EMULATION_ENVIRON);
|
||||
|
||||
/* Initialize the data about options. */
|
||||
strip_symbols = STRIP_NONE;
|
||||
trace_files = false;
|
||||
discard_locals = DISCARD_NONE;
|
||||
|
||||
write_map = false;
|
||||
config.relocateable_output = false;
|
||||
unix_relocate = 0;
|
||||
command_line.force_common_definition = false;
|
||||
|
||||
ldfile_add_arch("");
|
||||
|
||||
config.make_executable = true;
|
||||
force_make_executable = false;
|
||||
|
||||
|
||||
/* Initialize the cumulative counts of symbols. */
|
||||
undefined_global_sym_count = 0;
|
||||
warning_count = 0;
|
||||
multiple_def_count = 0;
|
||||
commons_pending = 0;
|
||||
|
||||
config.magic_demand_paged = true ;
|
||||
config.make_executable = true;
|
||||
|
||||
if (emulation == (char *)NULL) {
|
||||
emulation= DEFAULT_EMULATION;
|
||||
}
|
||||
ldemul_choose_mode(emulation);
|
||||
|
||||
default_target = ldemul_choose_target();
|
||||
|
||||
lang_init();
|
||||
ldemul_before_parse();
|
||||
|
||||
lang_has_input_file = false;
|
||||
parse_args(argc, argv);
|
||||
|
||||
if (lang_has_input_file == false) {
|
||||
info("%P%F: No input files\n");
|
||||
}
|
||||
|
||||
ldemul_after_parse();
|
||||
|
||||
lang_process();
|
||||
|
||||
|
||||
|
||||
|
||||
/* Print error messages for any missing symbols, for any warning
|
||||
symbols, and possibly multiple definitions */
|
||||
|
||||
/* Print a map, if requested. */
|
||||
|
||||
if (write_map) {
|
||||
ldsym_print_symbol_table ();
|
||||
lang_map(stdout);
|
||||
}
|
||||
|
||||
|
||||
if (config.relocateable_output) {
|
||||
output_bfd->flags &= ~( D_PAGED);
|
||||
output_bfd->flags |= EXEC_P;
|
||||
ldwrite();
|
||||
bfd_close(output_bfd);
|
||||
}
|
||||
else {
|
||||
output_bfd->flags |= EXEC_P;
|
||||
|
||||
ldwrite();
|
||||
bfd_close(output_bfd);
|
||||
if (config.make_executable == false && force_make_executable == false) {
|
||||
unlink(output_filename);
|
||||
}
|
||||
return (!config.make_executable);
|
||||
}
|
||||
|
||||
return(0);
|
||||
} /* main() */
|
||||
|
||||
|
||||
void
|
||||
Q_read_entry_symbols (desc, entry)
|
||||
bfd *desc;
|
||||
struct lang_input_statement_struct *entry;
|
||||
{
|
||||
if (entry->asymbols == (asymbol **)NULL) {
|
||||
size_t table_size = get_symtab_upper_bound(desc);
|
||||
entry->asymbols = (asymbol **)ldmalloc(table_size);
|
||||
|
||||
entry->symbol_count = bfd_canonicalize_symtab(desc, entry->asymbols) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* turn this item into a reference
|
||||
*/
|
||||
static void
|
||||
refize(sp, nlist_p)
|
||||
ldsym_type *sp;
|
||||
asymbol **nlist_p;
|
||||
{
|
||||
asymbol *sym = *nlist_p;
|
||||
sym->value = 0;
|
||||
sym->flags = BSF_UNDEFINED;
|
||||
sym->section = (asection *)NULL;
|
||||
sym->udata =(void *)( sp->srefs_chain);
|
||||
sp->srefs_chain = nlist_p;
|
||||
}
|
||||
/*
|
||||
This function is called for each name which is seen which has a global
|
||||
scope. It enters the name into the global symbol table in the correct
|
||||
symbol on the correct chain. Remember that each ldsym_type has three
|
||||
chains attatched, one of all definitions of a symbol, one of all
|
||||
references of a symbol and one of all common definitions of a symbol.
|
||||
|
||||
When the function is over, the supplied is left connected to the bfd
|
||||
to which is was born, with its udata field pointing to the next member
|
||||
on the chain in which it has been inserted.
|
||||
|
||||
A certain amount of jigery pokery is necessary since commons come
|
||||
along and upset things, we only keep one item in the common chain; the
|
||||
one with the biggest size seen sofar. When another common comes along
|
||||
it either bumps the previous definition into the ref chain, since it
|
||||
is bigger, or gets turned into a ref on the spot since the one on the
|
||||
common chain is already bigger. If a real definition comes along then
|
||||
the common gets bumped off anyway.
|
||||
|
||||
Whilst all this is going on we keep a count of the number of multiple
|
||||
definitions seen, undefined global symbols and pending commons.
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
Q_enter_global_ref (nlist_p)
|
||||
asymbol **nlist_p;
|
||||
|
||||
{
|
||||
asymbol *sym = *nlist_p;
|
||||
char *name = sym->name;
|
||||
ldsym_type *sp = ldsym_get (name);
|
||||
|
||||
flagword this_symbol_flags = sym->flags;
|
||||
|
||||
|
||||
ASSERT(sym->udata == 0);
|
||||
|
||||
/* Just place onto correct chain */
|
||||
if (flag_is_common(this_symbol_flags)) {
|
||||
/* If we have a definition of this symbol already then
|
||||
* this common turns into a reference. Also we only
|
||||
* ever point to the largest common, so if we
|
||||
* have a common, but it's bigger that the new symbol
|
||||
* the turn this into a reference too.
|
||||
*/
|
||||
if (sp->sdefs_chain)
|
||||
{
|
||||
/* This is a common symbol, but we already have a definition
|
||||
for it, so just link it into the ref chain as if
|
||||
it were a reference
|
||||
*/
|
||||
refize(sp, nlist_p);
|
||||
}
|
||||
else if (sp->scoms_chain) {
|
||||
/* If we have a previous common, keep only the biggest */
|
||||
if ( (*(sp->scoms_chain))->value > sym->value) {
|
||||
/* other common is bigger, throw this one away */
|
||||
refize(sp, nlist_p);
|
||||
}
|
||||
else if (sp->scoms_chain != nlist_p) {
|
||||
/* other common is smaller, throw that away */
|
||||
refize(sp, sp->scoms_chain);
|
||||
sp->scoms_chain = nlist_p;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* This is the first time we've seen a common, so
|
||||
* remember it - if it was undefined before, we know it's defined now
|
||||
*/
|
||||
if (sp->srefs_chain)
|
||||
undefined_global_sym_count--;
|
||||
|
||||
commons_pending++;
|
||||
sp->scoms_chain = nlist_p;
|
||||
}
|
||||
}
|
||||
|
||||
else if (flag_is_defined(this_symbol_flags)) {
|
||||
/* This is the definition of a symbol, add to def chain */
|
||||
if (sp->sdefs_chain && (*(sp->sdefs_chain))->section != sym->section) {
|
||||
/* Multiple definition */
|
||||
asymbol *sy = *(sp->sdefs_chain);
|
||||
lang_input_statement_type *stat = (lang_input_statement_type *) sy->the_bfd->usrdata;
|
||||
lang_input_statement_type *stat1 = (lang_input_statement_type *) sym->the_bfd->usrdata;
|
||||
asymbol ** stat1_symbols = stat1 ? stat1->asymbols: 0;
|
||||
asymbol ** stat_symbols = stat ? stat->asymbols:0;
|
||||
|
||||
multiple_def_count++;
|
||||
info("%C: multiple definition of `%T'\n",
|
||||
sym->the_bfd,
|
||||
sym->section,
|
||||
stat1_symbols,
|
||||
sym->value,
|
||||
sym);
|
||||
|
||||
info("%C: first seen here\n",
|
||||
sy->the_bfd,
|
||||
sy->section,
|
||||
stat_symbols,
|
||||
sy->value);
|
||||
}
|
||||
else {
|
||||
sym->udata =(void *)( sp->sdefs_chain);
|
||||
sp->sdefs_chain = nlist_p;
|
||||
}
|
||||
/* A definition overrides a common symbol */
|
||||
if (sp->scoms_chain) {
|
||||
refize(sp, sp->scoms_chain);
|
||||
sp->scoms_chain = 0;
|
||||
commons_pending--;
|
||||
}
|
||||
else if (sp->srefs_chain) {
|
||||
/* If previously was undefined, then remember as defined */
|
||||
undefined_global_sym_count--;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (sp->scoms_chain == (asymbol **)NULL
|
||||
&& sp->srefs_chain == (asymbol **)NULL
|
||||
&& sp->sdefs_chain == (asymbol **)NULL) {
|
||||
/* And it's the first time we've seen it */
|
||||
undefined_global_sym_count++;
|
||||
|
||||
}
|
||||
|
||||
refize(sp, nlist_p);
|
||||
}
|
||||
|
||||
ASSERT(sp->sdefs_chain == 0 || sp->scoms_chain == 0);
|
||||
ASSERT(sp->scoms_chain ==0 || (*(sp->scoms_chain))->udata == 0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
Q_enter_file_symbols (entry)
|
||||
lang_input_statement_type *entry;
|
||||
{
|
||||
asymbol **q ;
|
||||
entry->common_section =
|
||||
bfd_make_section(entry->the_bfd, "COMMON");
|
||||
|
||||
ldlang_add_file(entry);
|
||||
|
||||
|
||||
if (trace_files || option_v) {
|
||||
info("%I\n", entry);
|
||||
}
|
||||
|
||||
total_symbols_seen += entry->symbol_count;
|
||||
total_files_seen ++;
|
||||
for (q = entry->asymbols; *q; q++)
|
||||
{
|
||||
asymbol *p = *q;
|
||||
|
||||
if (flag_is_undefined_or_global_or_common(p->flags))
|
||||
{
|
||||
|
||||
Q_enter_global_ref(q);
|
||||
}
|
||||
ASSERT(p->flags != 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Searching libraries */
|
||||
|
||||
struct lang_input_statement_struct *decode_library_subfile ();
|
||||
void linear_library (), symdef_library ();
|
||||
|
||||
/* Search the library ENTRY, already open on descriptor DESC.
|
||||
This means deciding which library members to load,
|
||||
making a chain of `struct lang_input_statement_struct' for those members,
|
||||
and entering their global symbols in the hash table. */
|
||||
|
||||
void
|
||||
search_library (entry)
|
||||
struct lang_input_statement_struct *entry;
|
||||
{
|
||||
|
||||
/* No need to load a library if no undefined symbols */
|
||||
if (!undefined_global_sym_count) return;
|
||||
|
||||
if (bfd_has_map(entry->the_bfd))
|
||||
symdef_library (entry);
|
||||
else
|
||||
linear_library (entry);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Q_read_file_symbols (entry)
|
||||
struct lang_input_statement_struct *entry;
|
||||
{
|
||||
if (entry->asymbols == (asymbol **)NULL
|
||||
&&entry->real == true
|
||||
&& entry->filename != (char *)NULL)
|
||||
{
|
||||
ldfile_open_file (entry);
|
||||
|
||||
if (bfd_check_format(entry->the_bfd, bfd_object))
|
||||
{
|
||||
entry->the_bfd->usrdata = (void*)entry;
|
||||
|
||||
|
||||
Q_read_entry_symbols (entry->the_bfd, entry);
|
||||
Q_enter_file_symbols (entry);
|
||||
}
|
||||
else if (bfd_check_format(entry->the_bfd, bfd_archive))
|
||||
{
|
||||
entry->the_bfd->usrdata = (void *)entry;
|
||||
|
||||
entry->subfiles = (lang_input_statement_type *)NULL;
|
||||
search_library (entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
info("%F%I: malformed input file (not rel or archive) \n", entry);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Construct and return a lang_input_statement_struct for a library member.
|
||||
The library's lang_input_statement_struct is library_entry,
|
||||
and the library is open on DESC.
|
||||
SUBFILE_OFFSET is the byte index in the library of this member's header.
|
||||
We store the length of the member into *LENGTH_LOC. */
|
||||
|
||||
lang_input_statement_type *
|
||||
decode_library_subfile (library_entry, subfile_offset)
|
||||
struct lang_input_statement_struct *library_entry;
|
||||
bfd *subfile_offset;
|
||||
{
|
||||
register struct lang_input_statement_struct *subentry;
|
||||
subentry = (struct lang_input_statement_struct *) ldmalloc (sizeof (struct lang_input_statement_struct));
|
||||
subentry->filename = subfile_offset -> filename;
|
||||
subentry->local_sym_name = subfile_offset->filename;
|
||||
subentry->asymbols = 0;
|
||||
subentry->the_bfd = subfile_offset;
|
||||
subentry->subfiles = 0;
|
||||
subentry->next = 0;
|
||||
subentry->superfile = library_entry;
|
||||
subentry->is_archive = false;
|
||||
subentry->header_read_flag = false;
|
||||
subentry->just_syms_flag = false;
|
||||
subentry->loaded = false;
|
||||
subentry->chain = 0;
|
||||
|
||||
return subentry;
|
||||
}
|
||||
|
||||
boolean subfile_wanted_p ();
|
||||
void
|
||||
clear_syms(entry, offset)
|
||||
struct lang_input_statement_struct *entry;
|
||||
file_ptr offset;
|
||||
{
|
||||
carsym *car;
|
||||
unsigned long indx = bfd_get_next_mapent(entry->the_bfd,
|
||||
BFD_NO_MORE_SYMBOLS,
|
||||
&car);
|
||||
while (indx != BFD_NO_MORE_SYMBOLS) {
|
||||
if (car->file_offset == offset) {
|
||||
car->name = 0;
|
||||
}
|
||||
indx = bfd_get_next_mapent(entry->the_bfd, indx, &car);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Search a library that has a map
|
||||
*/
|
||||
void
|
||||
symdef_library (entry)
|
||||
struct lang_input_statement_struct *entry;
|
||||
|
||||
{
|
||||
register struct lang_input_statement_struct *prev = 0;
|
||||
|
||||
boolean not_finished = true;
|
||||
|
||||
|
||||
while (not_finished == true)
|
||||
{
|
||||
carsym *exported_library_name;
|
||||
bfd *prev_archive_member_bfd = 0;
|
||||
|
||||
int idx = bfd_get_next_mapent(entry->the_bfd,
|
||||
BFD_NO_MORE_SYMBOLS,
|
||||
&exported_library_name);
|
||||
|
||||
not_finished = false;
|
||||
|
||||
while (idx != BFD_NO_MORE_SYMBOLS && undefined_global_sym_count)
|
||||
{
|
||||
|
||||
if (exported_library_name->name)
|
||||
{
|
||||
|
||||
ldsym_type *sp = ldsym_get_soft (exported_library_name->name);
|
||||
|
||||
/* If we find a symbol that appears to be needed, think carefully
|
||||
about the archive member that the symbol is in. */
|
||||
/* So - if it exists, and is referenced somewhere and is
|
||||
undefined or */
|
||||
if (sp && sp->srefs_chain && !sp->sdefs_chain)
|
||||
{
|
||||
bfd *archive_member_bfd = bfd_get_elt_at_index(entry->the_bfd, idx);
|
||||
struct lang_input_statement_struct *archive_member_lang_input_statement_struct;
|
||||
|
||||
if (archive_member_bfd && bfd_check_format(archive_member_bfd, bfd_object))
|
||||
{
|
||||
|
||||
/* Don't think carefully about any archive member
|
||||
more than once in a given pass. */
|
||||
if (prev_archive_member_bfd != archive_member_bfd)
|
||||
{
|
||||
|
||||
prev_archive_member_bfd = archive_member_bfd;
|
||||
|
||||
/* Read the symbol table of the archive member. */
|
||||
|
||||
if (archive_member_bfd->usrdata != (void *)NULL) {
|
||||
|
||||
archive_member_lang_input_statement_struct =(lang_input_statement_type *) archive_member_bfd->usrdata;
|
||||
}
|
||||
else {
|
||||
|
||||
archive_member_lang_input_statement_struct =
|
||||
decode_library_subfile (entry, archive_member_bfd);
|
||||
archive_member_bfd->usrdata = (void *) archive_member_lang_input_statement_struct;
|
||||
|
||||
}
|
||||
|
||||
if (archive_member_lang_input_statement_struct == 0) {
|
||||
info ("%F%I contains invalid archive member %s\n",
|
||||
entry,
|
||||
sp->name);
|
||||
}
|
||||
|
||||
if (archive_member_lang_input_statement_struct->loaded == false)
|
||||
{
|
||||
|
||||
Q_read_entry_symbols (archive_member_bfd, archive_member_lang_input_statement_struct);
|
||||
/* Now scan the symbol table and decide whether to load. */
|
||||
|
||||
|
||||
if (subfile_wanted_p (archive_member_lang_input_statement_struct) == true)
|
||||
|
||||
{
|
||||
/* This member is needed; load it.
|
||||
Since we are loading something on this pass,
|
||||
we must make another pass through the symdef data. */
|
||||
|
||||
not_finished = true;
|
||||
|
||||
Q_enter_file_symbols (archive_member_lang_input_statement_struct);
|
||||
|
||||
if (prev)
|
||||
prev->chain = archive_member_lang_input_statement_struct;
|
||||
else
|
||||
entry->subfiles = archive_member_lang_input_statement_struct;
|
||||
|
||||
|
||||
prev = archive_member_lang_input_statement_struct;
|
||||
|
||||
|
||||
/* Clear out this member's symbols from the symdef data
|
||||
so that following passes won't waste time on them. */
|
||||
clear_syms(entry, exported_library_name->file_offset);
|
||||
archive_member_lang_input_statement_struct->loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
idx = bfd_get_next_mapent(entry->the_bfd, idx, &exported_library_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
linear_library (entry)
|
||||
struct lang_input_statement_struct *entry;
|
||||
{
|
||||
boolean more_to_do = true;
|
||||
register struct lang_input_statement_struct *prev = 0;
|
||||
|
||||
while (more_to_do) {
|
||||
|
||||
bfd * archive = bfd_openr_next_archived_file(entry->the_bfd,0);
|
||||
|
||||
more_to_do = false;
|
||||
while (archive) {
|
||||
if (bfd_check_format(archive, bfd_object))
|
||||
{
|
||||
register struct lang_input_statement_struct *subentry;
|
||||
|
||||
subentry = decode_library_subfile (entry,
|
||||
archive);
|
||||
|
||||
archive->usrdata = (void *) subentry;
|
||||
if (!subentry) return;
|
||||
if (subentry->loaded == false) {
|
||||
Q_read_entry_symbols (archive, subentry);
|
||||
|
||||
if (subfile_wanted_p (subentry) == true)
|
||||
{
|
||||
Q_enter_file_symbols (subentry);
|
||||
|
||||
if (prev)
|
||||
prev->chain = subentry;
|
||||
else
|
||||
entry->subfiles = subentry;
|
||||
prev = subentry;
|
||||
|
||||
more_to_do = true;
|
||||
subentry->loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
archive = bfd_openr_next_archived_file(entry->the_bfd,archive);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ENTRY is an entry for a library member.
|
||||
Its symbols have been read into core, but not entered.
|
||||
Return nonzero if we ought to load this member. */
|
||||
|
||||
boolean
|
||||
subfile_wanted_p (entry)
|
||||
struct lang_input_statement_struct *entry;
|
||||
{
|
||||
asymbol **q;
|
||||
|
||||
for (q = entry->asymbols; *q; q++)
|
||||
{
|
||||
asymbol *p = *q;
|
||||
|
||||
/* If the symbol has an interesting definition, we could
|
||||
potentially want it. */
|
||||
|
||||
if (p->flags & BSF_FORT_COMM
|
||||
|| p->flags & BSF_GLOBAL)
|
||||
{
|
||||
register ldsym_type *sp = ldsym_get_soft (p->name);
|
||||
|
||||
|
||||
/* If this symbol has not been hashed,
|
||||
we can't be looking for it. */
|
||||
if (sp != (ldsym_type *)NULL
|
||||
&& sp->sdefs_chain == (asymbol **)NULL) {
|
||||
if (sp->srefs_chain != (asymbol **)NULL
|
||||
|| sp->scoms_chain != (asymbol **)NULL)
|
||||
{
|
||||
/* This is a symbol we are looking for. It is either
|
||||
not yet defined or common. */
|
||||
|
||||
if (flag_is_common(p->flags))
|
||||
{
|
||||
/* This libary member has something to
|
||||
say about this element. We should
|
||||
remember if its a new size */
|
||||
/* Move something from the ref list to the com list */
|
||||
if(sp->scoms_chain) {
|
||||
/* Already a common symbol, maybe update it */
|
||||
if (p->value > (*(sp->scoms_chain))->value) {
|
||||
(*(sp->scoms_chain))->value = p->value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Take a value from the ref chain
|
||||
Here we are moving a symbol from the owning bfd
|
||||
to another bfd. We must set up the
|
||||
common_section portion of the bfd thing */
|
||||
|
||||
|
||||
|
||||
sp->scoms_chain = sp->srefs_chain;
|
||||
sp->srefs_chain =
|
||||
(asymbol **)((*(sp->srefs_chain))->udata);
|
||||
(*(sp->scoms_chain))->udata = (void*)NULL;
|
||||
|
||||
(*( sp->scoms_chain))->flags = BSF_FORT_COMM;
|
||||
commons_pending++;
|
||||
undefined_global_sym_count--;
|
||||
} {
|
||||
asymbol *com = *(sp->scoms_chain);
|
||||
if (((lang_input_statement_type *)
|
||||
(com->the_bfd->usrdata))->common_section ==
|
||||
(asection *)NULL) {
|
||||
((lang_input_statement_type *)
|
||||
(com->the_bfd->usrdata))->common_section =
|
||||
bfd_make_section(com->the_bfd, "COMMON");
|
||||
}
|
||||
}
|
||||
ASSERT(p->udata == 0);
|
||||
}
|
||||
|
||||
else {
|
||||
if (write_map)
|
||||
{
|
||||
info("%I needed due to %s\n",entry, sp->name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
23
ld/ldmain.h
Normal file
23
ld/ldmain.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* ldmain.h -
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
PROTO(void, Q_enter_global_ref,(asymbol **));
|
||||
PROTO(void, Q_read_file_symbols,(struct lang_input_statement_struct *));
|
||||
|
303
ld/ldmisc.c
Normal file
303
ld/ldmisc.c
Normal file
|
@ -0,0 +1,303 @@
|
|||
/* Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.1 1991/03/21 21:28:55 gumby
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.2 1991/03/15 18:45:55 rich
|
||||
* foo
|
||||
*
|
||||
* Revision 1.1 1991/03/13 00:48:30 chrisb
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.7 1991/03/10 09:31:34 rich
|
||||
* Modified Files:
|
||||
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
|
||||
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
|
||||
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
|
||||
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
|
||||
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
|
||||
*
|
||||
* As of this round of changes, ld now builds on all hosts of (Intel960)
|
||||
* interest and copy passes my copy test on big endian hosts again.
|
||||
*
|
||||
* Revision 1.6 1991/03/09 03:31:01 sac
|
||||
* After a fatal info message, the output file is deleted.
|
||||
*
|
||||
* Revision 1.5 1991/03/06 21:59:54 sac
|
||||
* Made %C print function name if available
|
||||
*
|
||||
* Revision 1.4 1991/03/06 02:27:45 sac
|
||||
* Added support for linenumber printing via %C
|
||||
*
|
||||
* Revision 1.3 1991/02/22 17:15:03 sac
|
||||
* Added RCS keywords and copyrights
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
ldmisc.c
|
||||
|
||||
*/
|
||||
|
||||
#include "sysdep.h"
|
||||
#include <varargs.h>
|
||||
#include "bfd.h"
|
||||
|
||||
#include "ld.h"
|
||||
#include "ldmisc.h"
|
||||
#include "ldlang.h"
|
||||
|
||||
/* IMPORTS */
|
||||
|
||||
extern char *program_name;
|
||||
|
||||
extern FILE *ldlex_input_stack;
|
||||
extern char *ldfile_input_filename;
|
||||
extern ld_config_type config;
|
||||
|
||||
void
|
||||
yyerror(arg)
|
||||
char *arg;
|
||||
{
|
||||
info("%P%F: %S %s\n",arg);
|
||||
}
|
||||
|
||||
extern int errno;
|
||||
extern int sys_nerr;
|
||||
extern char *sys_errlist[];
|
||||
|
||||
/*
|
||||
%F error is fatal
|
||||
%P print progam name
|
||||
%S print script file and linenumber
|
||||
%E current bfd error or errno
|
||||
%I filename from a lang_input_statement_type
|
||||
%B filename from a bfd
|
||||
%T symbol table entry
|
||||
%X no object output, fail return
|
||||
%V hex bfd_vma
|
||||
%C Clever filename:linenumber
|
||||
%
|
||||
*/
|
||||
void info(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
char *fmt;
|
||||
boolean fatal = false;
|
||||
va_list arg;
|
||||
va_start(arg);
|
||||
fmt = va_arg(arg, char *);
|
||||
while (*fmt) {
|
||||
while (*fmt != '%' && *fmt != '\0') {
|
||||
fputc(*fmt, stderr);
|
||||
fmt++;
|
||||
}
|
||||
if (*fmt == '%') {
|
||||
fmt ++;
|
||||
switch (*fmt++) {
|
||||
case 'X':
|
||||
config.make_executable = false;
|
||||
break;
|
||||
case 'V':
|
||||
fprintf(stderr,"%08lx", va_arg(arg, bfd_vma));
|
||||
break;
|
||||
case 'T':
|
||||
{
|
||||
asymbol *symbol = va_arg(arg, asymbol *);
|
||||
if (symbol) {
|
||||
asection *section = symbol->section;
|
||||
if ((symbol->flags & BSF_UNDEFINED) == 0) {
|
||||
char *section_name = section == (asection *)NULL ?
|
||||
"absolute" : section->name;
|
||||
fprintf(stderr,"%s (%s)", symbol->name, section_name);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,"%s", symbol->name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,"no symbol");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
{
|
||||
bfd *abfd = va_arg(arg, bfd *);
|
||||
if (abfd->my_archive) {
|
||||
fprintf(stderr,"%s(%s)", abfd->my_archive->filename,
|
||||
abfd->filename);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,"%s", abfd->filename);
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'F':
|
||||
fatal = true;
|
||||
break;
|
||||
case 'P':
|
||||
fprintf(stderr,"%s", program_name);
|
||||
break;
|
||||
case 'E':
|
||||
/* Replace with the most recent errno explanation */
|
||||
|
||||
|
||||
fprintf(stderr, bfd_errmsg(bfd_error));
|
||||
|
||||
|
||||
break;
|
||||
case 'I':
|
||||
{
|
||||
lang_input_statement_type *i =
|
||||
va_arg(arg,lang_input_statement_type *);
|
||||
|
||||
fprintf(stderr,"%s", i->local_sym_name);
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
/* Print source script file and line number */
|
||||
|
||||
if (ldlex_input_stack) {
|
||||
extern unsigned int lineno;
|
||||
if (ldfile_input_filename == (char *)NULL) {
|
||||
fprintf(stderr,"command line");
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,"%s:%u", ldfile_input_filename, lineno + 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,"command line ");
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
{
|
||||
char *filename;
|
||||
char *functionname;
|
||||
unsigned int linenumber;
|
||||
bfd *abfd = va_arg(arg, bfd *);
|
||||
asection *section = va_arg(arg, asection *);
|
||||
asymbol **symbols = va_arg(arg, asymbol **);
|
||||
bfd_vma offset = va_arg(arg, bfd_vma);
|
||||
|
||||
if (bfd_find_nearest_line(abfd,
|
||||
section,
|
||||
symbols,
|
||||
offset,
|
||||
&filename,
|
||||
&functionname,
|
||||
&linenumber))
|
||||
{
|
||||
if (filename == (char *)NULL)
|
||||
filename = abfd->filename;
|
||||
if (functionname != (char *)NULL)
|
||||
fprintf(stderr,"%s:%u: (%s)", filename, linenumber, functionname);
|
||||
else if (linenumber != 0)
|
||||
fprintf(stderr,"%s:%u", filename, linenumber);
|
||||
else
|
||||
fprintf(stderr,"%s", filename);
|
||||
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,"%s", abfd->filename);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
fprintf(stderr,"%s", va_arg(arg, char *));
|
||||
break;
|
||||
case 'd':
|
||||
fprintf(stderr,"%d", va_arg(arg, int));
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"%s", va_arg(arg, char *));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fatal == true) {
|
||||
extern char *output_filename;
|
||||
if (output_filename)
|
||||
unlink(output_filename);
|
||||
exit(1);
|
||||
}
|
||||
va_end(arg);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
info_assert(file, line)
|
||||
char *file;
|
||||
unsigned int line;
|
||||
{
|
||||
info("%F%P internal error %s %d\n", file,line);
|
||||
}
|
||||
|
||||
/* Return a newly-allocated string
|
||||
whose contents concatenate those of S1, S2, S3. */
|
||||
|
||||
char *
|
||||
concat (s1, s2, s3)
|
||||
char *s1, *s2, *s3;
|
||||
{
|
||||
size_t len1 = strlen (s1);
|
||||
size_t len2 = strlen (s2);
|
||||
size_t len3 = strlen (s3);
|
||||
char *result = ldmalloc (len1 + len2 + len3 + 1);
|
||||
|
||||
if (len1 != 0)
|
||||
memcpy(result, s1, len1);
|
||||
if (len2 != 0)
|
||||
memcpy(result+len1, s2, len2);
|
||||
if (len3 != 0)
|
||||
memcpy(result+len1+len2, s2, len3);
|
||||
*(result + len1 + len2 + len3) = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
char *ldmalloc (size)
|
||||
size_t size;
|
||||
{
|
||||
char * result = malloc (size);
|
||||
|
||||
if (result == (char *)NULL && size != 0)
|
||||
info("%F%P virtual memory exhausted\n");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
char *buystring(x)
|
||||
char *x;
|
||||
{
|
||||
size_t l = strlen(x)+1;
|
||||
char *r = ldmalloc(l);
|
||||
memcpy(r, x,l);
|
||||
return r;
|
||||
}
|
34
ld/ldmisc.h
Normal file
34
ld/ldmisc.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* ldmisc.h -
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
|
||||
|
||||
/* VARARGS*/
|
||||
PROTO(void,info,());
|
||||
PROTO(void,info_assert,(char *, unsigned int));
|
||||
PROTO(void,yyerror,(char *));
|
||||
PROTO(char *,concat,(char *, char *, char *));
|
||||
PROTO(char *, ldmalloc,(size_t));
|
||||
PROTO(char *,buystring,(char *));
|
||||
#define ASSERT(x) \
|
||||
{ if (!(x)) info_assert(__FILE__,__LINE__); }
|
||||
|
||||
#define FAIL() \
|
||||
{ info_assert(__FILE__,__LINE__); }
|
441
ld/ldwrite.c
Normal file
441
ld/ldwrite.c
Normal file
|
@ -0,0 +1,441 @@
|
|||
/* Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.1 1991/03/21 21:29:04 gumby
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.2 1991/03/15 18:45:55 rich
|
||||
* foo
|
||||
*
|
||||
* Revision 1.1 1991/03/13 00:48:37 chrisb
|
||||
* Initial revision
|
||||
*
|
||||
* Revision 1.7 1991/03/10 19:15:03 sac
|
||||
* Took out the abort() which had been put in the wrong place
|
||||
* Updated the version #.
|
||||
*
|
||||
* Revision 1.6 1991/03/10 09:31:41 rich
|
||||
* Modified Files:
|
||||
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
|
||||
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
|
||||
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
|
||||
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
|
||||
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
|
||||
*
|
||||
* As of this round of changes, ld now builds on all hosts of (Intel960)
|
||||
* interest and copy passes my copy test on big endian hosts again.
|
||||
*
|
||||
* Revision 1.5 1991/03/09 03:25:08 sac
|
||||
* Added support for LONG, SHORT and BYTE keywords in scripts
|
||||
*
|
||||
* Revision 1.4 1991/03/06 21:59:34 sac
|
||||
* Completed G++ support
|
||||
*
|
||||
* Revision 1.3 1991/03/06 02:29:52 sac
|
||||
* Added support for partial linking.
|
||||
*
|
||||
* Revision 1.2 1991/02/22 17:15:11 sac
|
||||
* Added RCS keywords and copyrights
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
This module writes out the final image by reading sections from the
|
||||
input files, relocating them and writing them out
|
||||
|
||||
There are two main paths through this module, one for normal
|
||||
operation and one for partial linking.
|
||||
|
||||
During normal operation, raw section data is read along with the
|
||||
associated relocation information, the relocation info applied and
|
||||
the section data written out on a section by section basis.
|
||||
|
||||
When partially linking, all the relocation records are read to work
|
||||
out how big the output relocation vector will be. Then raw data is
|
||||
read, relocated and written section by section.
|
||||
|
||||
Written by Steve Chamberlain steve@cygnus.com
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "sysdep.h"
|
||||
#include "bfd.h"
|
||||
|
||||
#include "ldlang.h"
|
||||
#include "ld.h"
|
||||
#include "ldwrite.h"
|
||||
#include "ldmisc.h"
|
||||
#include "ldsym.h"
|
||||
#include "ldgram.tab.h"
|
||||
|
||||
|
||||
|
||||
char *ldmalloc();
|
||||
/* Static vars for do_warnings and subroutines of it */
|
||||
int list_unresolved_refs; /* List unresolved refs */
|
||||
int list_warning_symbols; /* List warning syms */
|
||||
int list_multiple_defs; /* List multiple definitions */
|
||||
extern int errno;
|
||||
extern char *sys_errlist[];
|
||||
|
||||
extern unsigned int undefined_global_sym_count;
|
||||
|
||||
extern bfd *output_bfd;
|
||||
|
||||
extern struct lang_output_section_statement_struct * create_object_symbols;
|
||||
|
||||
extern char lprefix;
|
||||
|
||||
#ifdef __STDC__
|
||||
void lang_for_each_statement(void (*func)());
|
||||
#else /* __STDC__ */
|
||||
void lang_for_each_statement();
|
||||
#endif /* __STDC__ */
|
||||
|
||||
extern size_t largest_section;
|
||||
ld_config_type config;
|
||||
|
||||
extern unsigned int global_symbol_count;
|
||||
|
||||
boolean trace_files;
|
||||
|
||||
static void perform_relocation(input_bfd,
|
||||
input_section,
|
||||
data,
|
||||
symbols)
|
||||
bfd *input_bfd;
|
||||
asection *input_section;
|
||||
void *data;
|
||||
asymbol **symbols;
|
||||
{
|
||||
static asymbol *error_symbol = (asymbol *)NULL;
|
||||
static unsigned int error_count = 0;
|
||||
#define MAX_ERRORS_IN_A_ROW 5
|
||||
size_t reloc_size = get_reloc_upper_bound(input_bfd, input_section);
|
||||
|
||||
arelent **reloc_vector = (arelent **)ldmalloc(reloc_size);
|
||||
arelent **parent;
|
||||
bfd *ob = output_bfd;
|
||||
asection *os = input_section->output_section;
|
||||
if (config.relocateable_output == false) ob = (bfd *)NULL;
|
||||
|
||||
if (bfd_canonicalize_reloc(input_bfd,
|
||||
input_section,
|
||||
reloc_vector,
|
||||
symbols) )
|
||||
{
|
||||
for (parent = reloc_vector; *parent; parent++)
|
||||
{
|
||||
|
||||
bfd_reloc_status_enum_type r=
|
||||
bfd_perform_relocation(input_bfd,
|
||||
*parent,
|
||||
data,
|
||||
input_section,
|
||||
ob);
|
||||
|
||||
if (r == bfd_reloc_ok) {
|
||||
if (ob != (bfd *)NULL) {
|
||||
/* A parital link, so keep the relocs */
|
||||
os->orelocation[os->reloc_count] = *parent;
|
||||
os->reloc_count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
asymbol *s;
|
||||
arelent *p = *parent;
|
||||
|
||||
if (ob != (bfd *)NULL) {
|
||||
/* A parital link, so keep the relocs */
|
||||
os->orelocation[os->reloc_count] = *parent;
|
||||
os->reloc_count++;
|
||||
}
|
||||
|
||||
if (p->sym_ptr_ptr != (asymbol **)NULL) {
|
||||
s = *(p->sym_ptr_ptr);
|
||||
}
|
||||
else {
|
||||
s = (asymbol *)NULL;
|
||||
}
|
||||
switch (r)
|
||||
{
|
||||
case bfd_reloc_undefined:
|
||||
/* We remember the symbol, and never print more than
|
||||
a reasonable number of them in a row */
|
||||
if (s == error_symbol) {
|
||||
error_count++;
|
||||
}
|
||||
else {
|
||||
error_count = 0;
|
||||
error_symbol = s;
|
||||
}
|
||||
if (error_count < MAX_ERRORS_IN_A_ROW) {
|
||||
info("%C: undefined reference to `%T'\n",
|
||||
input_bfd,
|
||||
input_section,
|
||||
symbols,
|
||||
(*parent)->address,
|
||||
s);
|
||||
config.make_executable = false;
|
||||
}
|
||||
else if (error_count == MAX_ERRORS_IN_A_ROW) {
|
||||
info("%C: more undefined references to `%T' follow\n",
|
||||
input_bfd,
|
||||
input_section,
|
||||
symbols,
|
||||
(*parent)->address,
|
||||
s);
|
||||
}
|
||||
else {
|
||||
/* Don't print any more */
|
||||
}
|
||||
break;
|
||||
case bfd_reloc_dangerous:
|
||||
info("%B: relocation may be wrong `%T'\n",
|
||||
input_bfd,
|
||||
s);
|
||||
break;
|
||||
case bfd_reloc_outofrange:
|
||||
info("%B:%s relocation address out of range %T (%x)\n",
|
||||
input_bfd,
|
||||
input_section->name,
|
||||
s,
|
||||
p->address);
|
||||
break;
|
||||
case bfd_reloc_overflow:
|
||||
info("%B:%s relocation overflow in %T reloc type %d\n",
|
||||
input_bfd,
|
||||
input_section->name,
|
||||
s,
|
||||
p->howto->type);
|
||||
break;
|
||||
default:
|
||||
info("%F%B: relocation error, symbol `%T'\n",
|
||||
input_bfd,
|
||||
s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free((char *)reloc_vector);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void *data_area;
|
||||
|
||||
static void
|
||||
copy_and_relocate(statement)
|
||||
lang_statement_union_type *statement;
|
||||
{
|
||||
switch (statement->header.type) {
|
||||
case lang_fill_statement_enum:
|
||||
{
|
||||
#if 0
|
||||
bfd_byte play_area[SHORT_SIZE];
|
||||
unsigned int i;
|
||||
bfd_putshort(output_bfd, statement->fill_statement.fill, play_area);
|
||||
/* Write out all entire shorts */
|
||||
for (i = 0;
|
||||
i < statement->fill_statement.size - SHORT_SIZE + 1;
|
||||
i+= SHORT_SIZE)
|
||||
{
|
||||
bfd_set_section_contents(output_bfd,
|
||||
statement->fill_statement.output_section,
|
||||
play_area,
|
||||
statement->data_statement.output_offset +i,
|
||||
SHORT_SIZE);
|
||||
|
||||
}
|
||||
|
||||
/* Now write any remaining byte */
|
||||
if (i < statement->fill_statement.size)
|
||||
{
|
||||
bfd_set_section_contents(output_bfd,
|
||||
statement->fill_statement.output_section,
|
||||
play_area,
|
||||
statement->data_statement.output_offset +i,
|
||||
1);
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case lang_data_statement_enum:
|
||||
{
|
||||
bfd_vma value = statement->data_statement.value;
|
||||
bfd_byte play_area[LONG_SIZE];
|
||||
unsigned int size;
|
||||
switch (statement->data_statement.type) {
|
||||
case LONG:
|
||||
bfd_putlong(output_bfd, value, play_area);
|
||||
size = LONG_SIZE;
|
||||
break;
|
||||
case SHORT:
|
||||
bfd_putshort(output_bfd, value, play_area);
|
||||
size = SHORT_SIZE;
|
||||
break;
|
||||
case BYTE:
|
||||
bfd_putchar(output_bfd, value, play_area);
|
||||
size = BYTE_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
bfd_set_section_contents(output_bfd,
|
||||
statement->data_statement.output_section,
|
||||
play_area,
|
||||
statement->data_statement.output_vma,
|
||||
size);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
case lang_input_section_enum:
|
||||
{
|
||||
|
||||
asection *i = statement->input_section.section;
|
||||
asection *output_section = i->output_section;
|
||||
lang_input_statement_type *ifile = statement->input_section.ifile;
|
||||
bfd *inbfd = ifile->the_bfd;
|
||||
if (output_section->flags & SEC_LOAD && i->size != 0)
|
||||
{
|
||||
if(bfd_get_section_contents(inbfd,
|
||||
i,
|
||||
data_area,
|
||||
0L,
|
||||
i->size) == false)
|
||||
{
|
||||
info("%F%B error reading section contents %E\n",
|
||||
inbfd);
|
||||
}
|
||||
perform_relocation (inbfd, i, data_area, ifile->asymbols);
|
||||
|
||||
|
||||
if(bfd_set_section_contents(output_bfd,
|
||||
output_section,
|
||||
data_area,
|
||||
(file_ptr)i->output_offset,
|
||||
i->size) == false)
|
||||
{
|
||||
info("%F%B error writing section contents of %E\n",
|
||||
output_bfd);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* All the other ones fall through */
|
||||
;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
write_norel()
|
||||
{
|
||||
/* Output the text and data segments, relocating as we go. */
|
||||
lang_for_each_statement(copy_and_relocate);
|
||||
}
|
||||
|
||||
|
||||
static void read_relocs(abfd, section, symbols)
|
||||
bfd *abfd;
|
||||
asection *section;
|
||||
asymbol **symbols;
|
||||
{
|
||||
/* Work out the output section ascociated with this input section */
|
||||
asection *output_section = section->output_section;
|
||||
|
||||
size_t reloc_size = get_reloc_upper_bound(abfd, section);
|
||||
arelent **reloc_vector = (arelent **)ldmalloc(reloc_size);
|
||||
|
||||
if (bfd_canonicalize_reloc(abfd,
|
||||
section,
|
||||
reloc_vector,
|
||||
symbols)) {
|
||||
output_section->reloc_count += section->reloc_count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
write_rel()
|
||||
{
|
||||
/*
|
||||
Run through each section of each file and work work out the total
|
||||
number of relocation records which will finally be in each output
|
||||
section
|
||||
*/
|
||||
|
||||
LANG_FOR_EACH_INPUT_SECTION
|
||||
(statement, abfd, section,
|
||||
(read_relocs(abfd, section, statement->asymbols)));
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Now run though all the output sections and allocate the space for
|
||||
all the relocations
|
||||
*/
|
||||
LANG_FOR_EACH_OUTPUT_SECTION
|
||||
(section,
|
||||
(section->orelocation =
|
||||
(arelent **)ldmalloc((size_t)(sizeof(arelent **)*
|
||||
section->reloc_count)),
|
||||
section->reloc_count = 0,
|
||||
section->flags |= SEC_HAS_CONTENTS));
|
||||
|
||||
|
||||
/*
|
||||
Copy the data, relocating as we go
|
||||
*/
|
||||
lang_for_each_statement(copy_and_relocate);
|
||||
}
|
||||
|
||||
void
|
||||
ldwrite ()
|
||||
{
|
||||
data_area = (void*) ldmalloc(largest_section);
|
||||
if (config.relocateable_output == true)
|
||||
{
|
||||
write_rel();
|
||||
}
|
||||
else
|
||||
{
|
||||
write_norel();
|
||||
}
|
||||
free(data_area);
|
||||
/* Output the symbol table (both globals and locals). */
|
||||
ldsym_write ();
|
||||
|
||||
}
|
||||
|
24
ld/ldwrite.h
Normal file
24
ld/ldwrite.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/* ldwrite.h -
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GLD, the Gnu Linker.
|
||||
|
||||
GLD is free software; you can 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.
|
||||
|
||||
GLD is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GLD; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
|
||||
|
||||
|
||||
PROTO(void, ldwrite, (void));
|
Loading…
Add table
Reference in a new issue