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:
nobody 1991-04-04 18:19:54 +00:00
parent b37af01c89
commit 3a69b3aca6
88 changed files with 47908 additions and 0 deletions

249
gas/COPYING Normal file
View 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

File diff suppressed because it is too large Load Diff

584
gas/Makefile.in Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

494
gas/config/obj-coff.h Normal file
View 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

File diff suppressed because it is too large Load Diff

29
gas/config/tc-a29k.h Normal file
View 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
View File

15
gas/config/tc-generic.h Normal file
View 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

File diff suppressed because it is too large Load Diff

247
gas/config/tc-i386.h Normal file
View 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

File diff suppressed because it is too large Load Diff

14
gas/config/tc-i860.h Normal file
View 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

File diff suppressed because it is too large Load Diff

279
gas/config/tc-i960.h Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

26
gas/config/tc-m68k.h Normal file
View 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

File diff suppressed because it is too large Load Diff

57
gas/config/tc-ns32k.h Normal file
View 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

File diff suppressed because it is too large Load Diff

42
gas/config/tc-sparc.h Normal file
View 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

File diff suppressed because it is too large Load Diff

14
gas/config/tc-vax.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

966
gas/expr.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

137
gas/read.h Normal file
View 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
View 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
View 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
View 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
View 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(&notes, name, name_length);
preserved_copy_of_name = obstack_finish(&notes);
symbolP = (symbolS *)obstack_alloc(&notes, 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
View 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
View 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

File diff suppressed because it is too large Load Diff

130
gas/write.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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(&region->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

File diff suppressed because it is too large Load Diff

347
ld/ldlang.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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));