diff options
36 files changed, 7385 insertions, 3 deletions
diff --git a/gas/.gdbinit b/gas/.gdbinit new file mode 100644 index 0000000..2044214 --- /dev/null +++ b/gas/.gdbinit @@ -0,0 +1,4 @@ +break as_warn +break as_bad +break as_fatal +set caution off diff --git a/gas/GNUmakefile-host b/gas/GNUmakefile-host new file mode 100755 index 0000000..386c869 --- /dev/null +++ b/gas/GNUmakefile-host @@ -0,0 +1,6 @@ +ALL := $(shell ls -d =*) + +%: + $(foreach subdir,$(ALL),$(MAKE) -C $(subdir) $@ &&) true + +gas: diff --git a/gas/Makefile.loic b/gas/Makefile.loic new file mode 100755 index 0000000..4de7da1 --- /dev/null +++ b/gas/Makefile.loic @@ -0,0 +1,203 @@ +# Makefile for GAS. +# Copyright (C) 1989, Free Software Foundation +# +# This file is part of GAS, the GNU Assembler. +# +# GAS is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. +# +# GAS is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GAS; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +BINDIR = /usr/local/bin + +BINARY = gas + +# +# Add these flags to XCFLAGS below for specific use. +# +# If you machine does not have vfprintf, but does have _doprnt(), +# -DNO_VARARGS +# +# If the return-type of a signal-hander is void (instead of int), +# -DSIGTY +# +# To include the mc68851 mmu coprocessor instructions in the 68020 assembler, +# -Dm68851 +# +# If you want the 80386 assembler to correctly handle fsub/fsubr and fdiv/fdivr +# opcodes (unlike most 80386 assemblers) +# -DNON_BROKEN_WORDS +# +XCFLAGS = + +# Your favorite compiler +CC = gcc + +# Uncomment the following lines if you use USG + +INCLUDE_DIRS = -I. +COFF_OBJECTS = stack.o +CPPFLAGS = -DUSG +CFLAGS = -g $(CPPFLAGS) $(XCFLAGS) +LDFLAGS = +#LOADLIBES = -lPW + +# Uncomment the following lines if you use BSD +#INCLUDE_DIRS = -I. +#CPPFLAGS = +#CFLAGS = -g $(CPPFLAGS) $(XCFLAGS) +#LDFLAGS = +#LOADLIBES = + +CONFIG_FILES = \ + machine.c machine.h atof.c obj-format.c obj-format.h opcode.h + +OBJECTS = \ + as.o xrealloc.o xmalloc.o hash.o hex-value.o \ + atof-generic.o append.o messages.o expr.o app.o \ + frags.o input-file.o input-scrub.o output-file.o \ + subsegs.o symbols.o version.o flonum-const.o flonum-copy.o \ + flonum-mult.o strstr.o bignum-copy.o obstack.o write.o read.o \ + obj-format.o machine.o atof.o $(COFF_OBJECTS) + +SOURCES = $(OBJECTS:.o=.c) + +all : $(BINARY) + +install : all + cp $(BINARY) $(BINDIR) + +clean : + rm -f $(OBJECTS) + +clobber : clean + rm -f $(BINARY) $(CONFIG_FILES) dependencies TAGS m68k.h + +$(BINARY) : $(OBJECTS) + $(CC) -o $(BINARY) $(LDFLAGS) $(OBJECTS) $(LOADLIBES) + +TAGS : $(SOURCES) + etags $(SOURCES) *.h + +CXREF : $(SOURCES) + cxref -c $(INCLUDE_DIRS) $(SOURCES) + +stack.o: stack.c + $(CC) $(CFLAGS) -c stack.c + +atof.o: \ + flonum.h \ + bignum.h +obj-format.o: \ + as.h \ + md.h \ + aout.h \ + a.out.gnu.h \ + struc-symbol.h \ + write.h \ + append.h +read.o: \ + obj-format.h \ + a.out.gnu.h \ + as.h \ + read.h \ + md.h \ + hash.h \ + obstack.h \ + frags.h \ + flonum.h \ + bignum.h \ + struc-symbol.h \ + expr.h \ + symbols.h \ + sparc.h +write.o: \ + obj-format.h \ + a.out.gnu.h \ + as.h \ + md.h \ + subsegs.h \ + obstack.h \ + struc-symbol.h \ + write.h \ + symbols.h \ + append.h \ + sparc.h +obstack.o: \ + obstack.h +bignum-copy.o: \ + bignum.h +flonum-mult.o: \ + flonum.h \ + bignum.h +flonum-copy.o: \ + flonum.h \ + bignum.h +flonum-const.o: \ + flonum.h \ + bignum.h +symbols.o: \ + obj-format.h \ + a.out.gnu.h \ + as.h \ + hash.h \ + obstack.h \ + struc-symbol.h \ + symbols.h \ + frags.h +subsegs.o: \ + obj-format.h \ + a.out.gnu.h \ + as.h \ + subsegs.h \ + obstack.h \ + frags.h \ + struc-symbol.h \ + write.h +input-scrub.o: \ + as.h \ + read.h \ + input-file.h +input-file.o: \ + input-file.h +frags.o: \ + obj-format.h \ + a.out.gnu.h \ + as.h \ + subsegs.h \ + obstack.h \ + frags.h \ + struc-symbol.h +expr.o: \ + obj-format.h \ + a.out.gnu.h \ + as.h \ + flonum.h \ + bignum.h \ + read.h \ + struc-symbol.h \ + expr.h \ + obstack.h \ + symbols.h +messages.o: \ + as.h +atof-generic.o: \ + flonum.h \ + bignum.h +hash.o: \ + hash.h +as.o: \ + obj-format.h \ + a.out.gnu.h \ + as.h \ + struc-symbol.h \ + write.h diff --git a/gas/Makefile.old b/gas/Makefile.old new file mode 100644 index 0000000..9cbb532 --- /dev/null +++ b/gas/Makefile.old @@ -0,0 +1,434 @@ +# Makefile for GAS. +# Copyright (C) 1989, Free Software Foundation +# +# This file is part of GAS, the GNU Assembler. +# +# GAS is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. +# +# GAS is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GAS; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# This makefile may be used to make the VAX, 68020, 80386, +# SPARC, AMD 29000, ns32k, or i860 assembler(s). +ALL = asm29k avax a68 a386 asparc a32k a860 a960 +MDSRC=vax.c m68k.c i386.c sparc.c am29k.c ns32k.c + +BINDIR = $(DESTDIR)/bin + +# If you are on a BSD system, un-comment the next two lines, and comment out +# the lines for SystemV and HPUX below +#G0 = -g -I. #-O -Wall +#LDFLAGS = $(CFLAGS) +# +# To compile gas on a System Five machine, comment out the two lines above +# and un-comment out the next three lines +# Comment out the -lPW on the LOADLIBES line if you are using GCC. +G0 = -g -I. -DUSG +LDFLAGS = $(CFLAGS) +LOADLIBES = # -lmalloc -lPW +# +# To compile gas for HPUX, link m-hpux.h to m68k.h , and un-comment the +# next two lines. (If you are using GCC, comment out the alloca.o part) +# (Get alloca from the emacs distribution, or use GCC.) +# HPUX 7.0 may have a bug in setvbuf. gas gives an error message like +# 1:"Unknown operator" -- Statement 'NO_APP' ignored +# if setvbuf is broken. Re-compile input-file.c (and only input-file.c +# with -DVMS and the problem should go away. +# +# G0 = -g -I. -DUSG +# LOADLIBES = alloca.o +# +# To compile gas for a Sequent Symmetry, comment out all the above lines, +# and un-comment the next two lines. +# G0 = -g -I. -DUSE_SYSTEM_HDR -DEXEC_VERSION=1 +# LOADLIBES = -lc /usr/att/lib/libc.a + +# Use these lines to build gas using hc. +#CC=hc29 -cmdlink.cmd -Dconst= -I../include/msdos +#CC=gcc29k +#LOADLIBES= ../binutils/alloca.o + +# If you just want to compile the vax assembler, type 'make avax' + +# If you just want to compile the i386 assembler, type 'make a386' + +# If you just want to compile the ns32k assembler, type 'make a32k' + +# If you just want to compile the sparc assembler, type 'make asparc' + +# If you just want to compile the AMD 29000 assembler, type 'make asm29k' + +# If you just want to compile the a860 assembler, type 'make a860' + +# If you just want to compile the a960 assembler, type 'make a960' + +# If you just want to compile the mc68020 assembler, make sure m68k.h +# is correctly set up, and type type 'make a68' (Except on HPUX machines, +# where you will have to make the changes marked below before typing +# 'make a68' +# m68k.h should be a symbolic or hard-link to one of +# m-sun3.h , m-hpux.h or m-generic.h +# depending on which machine you want to compile the 68020 assembler for. +# +# If you want the 68k assembler to be completely compatable with the the +# SUN one, un-comment the -DLOCAL_LABELS_FB and -DLOCAL_LABELS_DOLLAR +# lines below. +# +# Gas prefers STDARG's, but if your machine doesn't have stdarg.h, you +# should define remove the # from the -DNO_STDARG line below. In this +# case gas will try to use VARARGS instead. (but keep reading). +# +# If your machine does not have vfprintf, but does have _doprnt(), +# remove the # from the -DNO_VARARGS line below. +# +# If the return-type of a signal-hander is void (instead of int), +# remove the # from the -DSIGTY line below. +# +# To include the mc68851 mmu coprocessor instructions in the 68020 assembler, +# remove the # from the -Dm68851 line below. +# +# If you want the 68020 assembler use a register prefix character, un-comment +# the REGISTER_PREFIX line, and (maybe) change the '%' to the appropriate +# character. +# +# If you want the assembler to treat .L* or ..* symbols as local, instead of +# the usual L* symbols, un-comment the DOT_LABEL_PREFIX line. +# +# If you want the 80386 assembler to correctly handle fsub/fsubr and fdiv/fdivr +# opcodes (unlike most 80386 assemblers), remove the # from +# the -DNON_BROKEN_WORDS line below. +# +# To compile 80386 Gas for the Sequent Symmetry, un-comment the -DEXEC_VERSION +# and the -DUSE_SYSTEM_HDR lines below. +# +# To compile gas for the HP 9000/300 un-comment the -DUSE_HP_HDR line below. +# +# For the ns32k, the options are 32532 or 32032 CPU and 32381 or 32081 FPU. +# To select the NS32532, remove the # from the -DNS32532 line below. +# To compile in tne NS32381 opcodes in addition to the NS32081 opcodes +# (the 32381 is a superset of the 32081), remove the # from the -DNS32381 +# line below. +# +# For the ns32k on a Sequent, uncomment the SEQUENT_COMPATABILITY line below. +# +# If you want character constants to *require* closing single quotes, +# eg 'c' rather than 'c then use the -DREQUIRE_CHAR_CLOSE_QUOTE lines +# below. The default is for the closing quote to be optional. +# +# To produce intel's b.out format, use the B_OUT line below. +# +# if you want to allow "\v" to mean a control-k, use the BACKSLASH_V +# line below. + +# [Why is there a distinction between "Ox" and "Gx"? It would seem easier +# to not have to figure out that your code isn't working because some +# define's are only seen by some modules and you tested it in a module +# where it never gets defined... gnu@cygnus.com] + +O1 = -DNO_STDARG +O2 = # -DNO_VARARGS +O3 = # -DNON_BROKEN_WORDS +O4 = # -Dm68851 +O5 = # -DEXEC_VERSION=1 +O6 = # -DSIGTY=void +O6 = # -DNS32532 +O7 = # -DNS32381 +O8 = # -DDOT_LABEL_PREFIX +O9 = # -DSEQUENT_COMPATABILITY + +G1 = # -DREGISTER_PREFIX=\'%\' +G2 = # -DUSE_SYSTEM_HDR +G3 = # -DUSE_HP_HDR +G4 = # -DLOCAL_LABELS_DOLLAR +G5 = # -DLOCAL_LABELS_FB +G6 = # -DDEBUG +G7 = # -DREQUIRE_CHAR_CLOSE_QUOTE +G8 = -DB_OUT +G9 = -DBACKSLASH_V + +OPTIONS = $(O1) $(O2) $(O3) $(O4) $(O5) $(O6) $(O7) $(O8) $(O9) + +CFLAGS = $(G0) $(G1) $(G2) $(G3) $(G4) $(G5) $(G6) $(G7) $(G8) $(G9) $(OPTIONS) + +# +# To make the 68020 assembler compile as the default, un-comment the next +# line, and comment out all the other lines that start with DEFAULT_GAS +#DEFAULT_GAS=a68 +# +# To make the VAX assembler compile as the default, un-comment the next +# line and commment out all the other lines that start with DEFAULT_GAS +#DEFAULT_GAS=avax +# +# To make the 80386 assembler compile as the default, un-comment the next +# line and commment out all the other lines that start with DEFAULT_GAS +#DEFAULT_GAS=a386 +# +# To make the ns32k assembler compile as the default, un-comment the next +# line and commment out all the other lines that start with DEFAULT_GAS +#DEFAULT_GAS=a32k +# +# To make the sparc assembler compile as the default, un-comment the next +# line and commment out all the other lines that start with DEFAULT_GAS +#DEFAULT_GAS=asparc +# +# +# To make the i860 assembler compile as the default, un-comment the next +# line and comment out all the other lines that start with DEFAULT_GAS +#DEFAULT_GAS=a860 +# +# To make the asm29k assembler compile as the default, un-comment the next +# line and commment out all the other lines that start with DEFAULT_GAS +#DEFAULT_GAS=asm29k +# +# To make the i960 assembler compile as the default, un-comment the next +# line and commment out all the other lines that start with DEFAULT_GAS +#DEFAULT_GAS=a960 + +# Global Sources ------------------------------------------------------------- + +a =\ +as.o xrealloc.o xmalloc.o hash.o hex-value.o \ +atof-generic.o messages.o expr.o app.o \ +frags.o input-file.o input-scrub.o output-file.o \ +subsegs.o symbols.o version.o \ +flonum-const.o flonum-copy.o flonum-mult.o strstr.o bignum-copy.o \ +obstack.o cond.o +#gdb.o gdb-file.o gdb-symbols.o gdb-blocks.o gdb-lines.o + +a: $(DEFAULT_GAS) + @rm -f a + @ln $(DEFAULT_GAS) a + +# i960 GAS ------------------------------------------------------------------ +t = i960.o i960-opcode.o atof-ieee.o ver960.o read-i960.o write-i960.o + +T = i960.c i960-opcode.c atof-ieee.c ver960.c + +i960.o: i960.c i960-opcode.h as.h frags.h struc-symbol.h +i960.o: flonum.h expr.h hash.h md.h write.h read.h symbols.h + $(CC) -c $(CFLAGS) -DI80960 i960.c + +write-i960.o: write.c + $(CC) -c $(CFLAGS) write.c + mv write.o write-i960.o + +read-i960.o: read.c + $(CC) -c $(CFLAGS) read.c + mv read.o read-i960.o + +a960_cheat: $a $t + $(CC) -o a960 $(LDFLAGS) $a $t $(LOADLIBES) + +a960: force + $(MAKE) 'CFLAGS=$(CFLAGS) -DI80960' a960_cheat + +force: + +# AM29K GAS ------------------------------------------------------------------ +u = am29k.o atof-ieee.o write.o read.o + +U = am29k.c am29k-opcode.h + +am29k.o: am29k.c a.out.gnu.h as.h expr.h flonum.h frags.h hash.h +am29k.o: am29k-opcode.h md.h obstack.h struc-symbol.h + $(CC) $(CFLAGS) -c am29k.c + +asm29k: $a $u + $(CC) -o asm29k $(LDFLAGS) $a $u $(LOADLIBES) + +# I860 GAS ------------------------------------------------------------------ +u = i860.o atof-ieee.o write.o read.o + +U = i860.c i860-opcode.h + +i860.o: i860.c i860-opcode.h as.h frags.h struc-symbol.h +i860.o: flonum.h expr.h hash.h md.h write.h read.h symbols.h + $(CC) -c $(CFLAGS) i860.c + +atof-ieee.o: flonum.h + +a860: $a $u + $(CC) -o a860 $(LDFLAGS) $a $u $(LOADLIBES) + +# SPARC GAS ------------------------------------------------------------------ +v = sparc.o atof-ieee.o write.o read.o + +V = sparc.c sparc-opcode.h + +atof-ieee.o: flonum.h +sparc.o: sparc.c reloc.h sparc-opcode.h as.h frags.h struc-symbol.h +sparc.o: flonum.h expr.h hash.h md.h write.h read.h symbols.h + $(CC) -c $(CFLAGS) -DSPARC sparc.c + +asparc: $a $v + $(CC) -o asparc $(LDFLAGS) $a $v $(LOADLIBES) + +# NS32K GAS ------------------------------------------------------------------ +w = ns32k.o atof-ieee.o write-ns32k.o read-ns32k.o + +W = ns32k.c ns32k-opcode.h + +atof-ieee.o: flonum.h +ns32k.o: as.h frags.h struc-symbol.h flonum.h expr.h md.h hash.h +ns32k.o: write.h symbols.h ns32k-opcode.h ns32k.c + $(CC) $(CFLAGS) $(OPTIONS) -c ns32k.c + +write-ns32k.o: write.c + rm -f write-ns32k.c + cp write.c write-ns32k.c + $(CC) -c -DNS32K $(CFLAGS) write-ns32k.c + rm -f write-ns32k.c + +read-ns32k.o: read.c + rm -f read-ns32k.c + cp read.c read-ns32k.c + $(CC) -c -DNS32K $(CFLAGS) read-ns32k.c + rm -f read-ns32k.c + +a32k: $a $w + $(CC) -o a32k $(LDFLAGS) $a $w $(LOADLIBES) + +# 80386 GAS ------------------------------------------------------------------ +x = i386.o atof-ieee.o write.o read.o + +X = i386.c i386.h i386-opcode.h + +i386.o: i386.c as.h read.h flonum.h frags.h struc-symbol.h expr.h +i386.o: symbols.h hash.h md.h i386.h i386-opcode.h + $(CC) $(CFLAGS) $(OPTIONS) -c i386.c + +atof-ieee.o: flonum.h + +a386: $a $x + $(CC) -o a386 $(LDFLAGS) $a $x $(LOADLIBES) + +# 68020 GAS ------------------------------------------------------------------ +y = m68k.o atof-ieee.o write.o read.o + +Y = m68k.c atof-ieee.c m68k-opcode.h m-hpux.h m-sun3.h m-generic.h + +atof-ieee.o: flonum.h + +m68k.o: m68k.c a.out.gnu.h as.h expr.h flonum.h frags.h hash.h +m68k.o: m68k-opcode.h m68k.h md.h obstack.h struc-symbol.h + $(CC) $(CFLAGS) $(OPTIONS) -c m68k.c + +a68: $a $y + $(CC) -o a68 $(LDFLAGS) $a $y $(LOADLIBES) + +# VAX GAS -------------------------------------------------------------------- +z = vax.o atof-vax.o write.o read.o + +Z = vax.c atof-vax.c vax-opcode.h vax-inst.h \ + make-gas.com objrecdef.h vms.c vms-dbg.c README-vms-dbg + +vax.o: vax.c a.out.gnu.h as.h expr.h flonum.h frags.h md.h obstack.h +vax.o: read.h struc-symbol.h symbols.h vax-inst.h vax-opcode.h +atof-vax.o: as.h flonum.h read.h + +avax: $a $z + $(CC) -o avax $(LDFLAGS) $a $z $(LOADLIBES) + +# global files --------------------------------------------------------------- + +hash.o: hash.c + $(CC) $(CFLAGS) -Derror=as_fatal -c hash.c + +xmalloc.o: xmalloc.c + $(CC) $(CFLAGS) -Derror=as_fatal -c xmalloc.c + +xrealloc.o: xrealloc.c + $(CC) $(CFLAGS) -Derror=as_fatal -c xrealloc.c + +A =\ +as.c xrealloc.c xmalloc.c hash.c hex-value.c \ +atof-generic.c messages.c expr.c bignum-copy.c \ +frags.c input-file.c input-scrub.c output-file.c read.c \ +subsegs.c symbols.c write.c strstr.c \ +flonum-const.c flonum-copy.c flonum-mult.c app.c version.c \ +obstack.c cond.c \ +#gdb.c gdb-file.c gdb-symbols.c gdb-blocks.c \ +#gdb-lines.c + +H = \ +a.out.gnu.h as.h bignum.h expr.h flonum.h \ +frags.h hash.h input-file.h md.h \ +obstack.h read.h reloc.h struc-symbol.h subsegs.h \ +symbols.h write.h + +dist: COPYING README ChangeLog $A $H $U $V $W $X $Y $Z Makefile + echo gas-`sed -n -e '/ version /s/[^0-9.]*\([0-9.]*\).*/\1/p' < version.c` > .fname + mkdir `cat .fname` + + ln COPYING README ChangeLog $A $H $U $V $W $X $Y $Z Makefile `cat .fname` + tar cvhZf `cat .fname`.tar.Z `cat .fname` + -rm -rf .fname `cat .fname` + +clean: + rm -f a avax a68 a386 a32k asparc asm29k a860 a960 $a $u $v $w $x $y $z a core gmon.out bugs a.out + +all: $(ALL) + +install: install_tools +install_tools: a + cp a $(BINDIR)/as + +# For things like: emacs `make mdsrc` +mdsrc: + @ls $(MDSRC) + +LINT = /usr/5bin/lint +LINTFLAGS = + +lint: + $(LINT) $(LINTFLAGS) $(CFLAGS) $A + +# General .o-->.h dependencies + +app.o: as.h +as.o: a.out.gnu.h as.h read.h struc-symbol.h write.h +atof-generic.o: flonum.h +bignum-copy.o: bignum.h +expr.o: a.out.gnu.h as.h expr.h flonum.h obstack.h read.h struc-symbol.h +expr.o: symbols.h +flonum-const.o: flonum.h +flonum-copy.o: flonum.h +flonum-mult.o: flonum.h +flonum-normal.o:flonum.h +flonum-print.o: flonum.h +frags.o: a.out.gnu.h as.h frags.h obstack.h struc-symbol.h subsegs.h +#gdb.o: as.h +#gdb-blocks.o: as.h +#gdb-lines.o: as.h frags.h obstack.h +#gdb-symbols.o: a.out.gnu.h as.h struc-symbol.h +hash.o: hash.h +input-file.o: input-file.h +input-scrub.o: as.h input-file.h read.h +messages.o: as.h +obstack.o: obstack.h +read.o: a.out.gnu.h as.h expr.h flonum.h frags.h hash.h md.h obstack.h +read.o: read.h struc-symbol.h symbols.h reloc.h +subsegs.o: a.out.gnu.h as.h frags.h obstack.h struc-symbol.h subsegs.h write.h +symbols.o: a.out.gnu.h as.h frags.h hash.h obstack.h struc-symbol.h symbols.h +write.o: a.out.gnu.h as.h md.h obstack.h struc-symbol.h subsegs.h +write.o: symbols.h write.h reloc.h + +flonum.h: bignum.h + +etags tags: TAGS + +TAGS: force + etags Makefile* README* config.gas *.[hc] + +force: + +# End of Makefile diff --git a/gas/NOTES b/gas/NOTES new file mode 100644 index 0000000..0669aa7 --- /dev/null +++ b/gas/NOTES @@ -0,0 +1,19 @@ +to do: + +fucked up on a.out.gnu.h, etc. +fucked up on foo-opcode.h. +remove the ifdef's from fx_callj tests? +what are callj tests? +search for (), build prototypes. +space tighten sparc alignment. +convert md_ri_to_chars to not pass structs. +convert md_ri_to_chars to emit fixP's. +fix number_to_chars, & family to have no side effects. +prototype. +md_ => tp_ +use CROSS_ASSEMBLE +multiple segments. +share b.out with a.out. + + +stack: diff --git a/gas/NOTES.config b/gas/NOTES.config new file mode 100644 index 0000000..e12797d --- /dev/null +++ b/gas/NOTES.config @@ -0,0 +1,52 @@ + + The GAS Configuration Plan + +Theory: + +The goal of the new configuration scheme is to bury all object format, +target processor, and host machine dependancies in object, target, and +host specific files. That is, to move all #ifdef's out of the gas +common code. + +Here's how it works. There is a .h and a .c file for each object file +format, a .h and a .c file for each target processor, and a .h for +each host. config.gas creates {sym}links in the current directory to +the appropriate files in the config directory. config.gas also serves +as a list of triplets {host, target, object-format} that have been +tested at one time or another. I also recommend that config.gas be +used to document triplet specific notes as to purpose of the triplet, +etc. + +Implementation: + +host.h is a {sym}link to .../config/xm-yourhost.h. It is intended to +be used to hide host compiler, system header file, and system library +differences between host machines. If your host needs actual c source +files, then either: these are generally useful functions, in which +case you should probably build a local library outside of the gas +source tree, or someone, perhaps me, is confused about what is needed +by different hosts. + +obj-format.h is a {sym}link to .../config/obj-something.h. It is intended + +All gas .c files include as.h. + +as.h #define's "gas", includes host.h, defines a number of gas +specific structures and types, and then includes tp.h, obj.h, and +target-environment.h. + +target-environment.h defines a target environment specific +preprocessor flag, eg, TE_SUN, and then includes obj-format.h. + +obj-format.h defines an object format specific preprocessor flag, eg, +OBJ_AOUT, OBJ_BOUT, OBJ_COFF, includes "target-processor.h", and then +defines the object specific macros, functions, types, and structures. + +target-processor.h + +target-processor. + +Porting: + +There appear to be four major types of ports; new hosts, new target +processors, new object file formats, and new target environments. diff --git a/gas/README-vms-dbg b/gas/README-vms-dbg new file mode 100644 index 0000000..61ab6dd --- /dev/null +++ b/gas/README-vms-dbg @@ -0,0 +1,127 @@ + 1) You should be aware that GNU-C, as with any other decent compiler, +will do things when optimization is turned on that you may not expect. +Sometimes intermediate results are not written to variables, if they are only +used in one place, and sometimes variables that are not used at all will not be +written to the symbol table. Also, parameters to inline functions are often +inaccessible. You can see the assembly code equivalent by using KP7 in the +debugger, and from this you can tell if in fact a variable should have the +value that you expect. You can find out if a variable lives withing a register +by doing a 'show symbol/addr'. + + 2) Overly complex data types, such as: + +int (*(*(*(*(*(* sarr6)[1])[1])[2])[3])[4])[5]; + +will not be debugged properly, since the debugging record overflows an internal +debugger buffer. gcc-as will convert these to *void as far as the debugger +symbol table is concerned, which will avoid any problems, and the assembler +will give you a message informing you that this has happened. + + 3) You must, of course, compile and link with /debug. If you link +without debug, you still get traceback table in the executable, but there is no +symbol table for variables. + + 4) Included in the patches to VMS.C are fixes to two bugs that are +unrelated to the changes that I have made. One of these made it impossible to +debug small programs sometimes, and the other caused the debugger to become +confused about which routine it was in, and give this incorrect info in +tracebacks. + + 5) If you are using the GNU-C++ compiler, you should modify the +compiler driver file GNU_CC:[000000]GCC.COM (or GXX.COM). If you have a +seperate GXX.COM, then you need to change one line in GXX.COM to: +$ if f$locate("D",p2) .ne. P2_Length then Debug = " ""-G0""" + Notice zero---> ^ +If you are using a GCC.COM that does both C and C++, add the following lines to +GCC.COM: + +$! +$! Use old style debugging records for VMS +$! +$ if (Debug.nes."" ).and. Plus then Debug = " ""-G0""" + +after the variables Plus and Debug are set. The reason for this, is that C++ +compiler by default generates debugging records that are more complex, +with many new syntactical elements that allow for the new features of the +language. The -G0 switch tells the C++ compiler to use the old style debugging +records. Until the debugger understands C++ there is not any point to try and +use the expanded syntax. + + 6) When you have nested scopes, i.e.: +main(){ + int i; + {int i; + {int i; +};};} +and you say "EXAM i" the debugger needs to figure out which variable you +actually want to reference. I have arranged things to define a block to the +debugger when you use brackets to enter a new scope, so in the example above, +the variables would be described as: +TEST\main\i +TEST\main\$0\i +TEST\main\$0\$0\i +At each level, the block name is a number with a dollar sign prefix, the +numbers start with 0 and count upward. When you say EXAM i, the debugger looks +at the current PC, and decides which block it is currently in. It works from +the innermost level outward until it finds a block that has the variable "i" +defined. You can always specify the scope explicitly. + + 7) With C++, there can be a lot of inline functions, and it would be +rather restrictive to force the user to debug the program by converting all of +the inline functions to normal functions. What I have done is to essentially +"add" (with the debugger) source lines from the include files that contain the +inline functions. Thus when you step into an inline function it appears as if +you have called the function, and you can examine variables and so forth. +There are several *very* important differences, however. First of all, since +there is no function call involved, you cannot step over the inline function +call - you always step into it. Secondly, since the same source lines are used +in many locations, there is a seperate copy of the source for *each* usage. +Without this, breakpoints do not work, since we must have a 1-to-1 mapping +between source lines and PC. + Since you cannot step over inline function calls, it can be a real pain +if you are not really interested in what is going on for that function call. +What I have done is to use the "-D" switch for the assembler to toggle the +following behavior. With the "-D" switch, all inline functions are included in +the object file, and you can debug everything. Without the "-D" switch +(default case with VMS implementation), inline functions are included *only* if +they did not come from system header files (i.e. from GNU_CC_INCLUDE: or +GNU_GXX_INCLUDE:). Thus, without the switch the user only debugs his/her own +inline functions, and not the system ones. (This is especially useful if you do +a lot of stream I/O in C++). This probably will not provide enough granularity +for many users, but for now this is still somewhat experimental, and I would +like to reflect upon it and get some feedback before I go any further. +Possible solutions include an interactive prompting, a logical name, or a new +command line option in gcc.c (which is then passed through somehow to the guts +of the assembler). + The inline functions from header files appear after the source code +for the source file. This has the advantage that the source file itself is +numbered with the same line numbers that you get with an editor. In addition, +the entire header file is not included, since the assembler makes a list of +the min and max source lines that are used, and only includes those lines from +the first to the last actually used. (It is easy to change it to include the +whole file). + + 8) When you are debugging C++ objects, the object "this" is refered to +as "$this". Actually, the compiler writes it as ".this", but the period is +not good for the debugger, so I have a routine to convert it to a $. (It +actually converts all periods to $, but only for variables, since this was +intended to allow us to access "this". + + 9) If you use the asm("...") keyword for global symbols, you will not +be able to see that symbol with the debugger. The reason is that there are two +records for the symbol stored in the data structures of the assembler. One +contains the info such as psect number and offset, and the other one contains +the information having to do with the data type of the variable. In order to +debug as symbol, you need to be able to coorelate these records, and the only +way to do this is by name. The record with the storage attributes will take +the name used in the asm directive, and the record that specifies the data type +has the actual variable name, and thus when you use the asm directive to change +a variable name, the symbol becomes invisible. + + 10) Older versions of the compiler ( GNU-C 1.37.92 and earlier) place +global constants in the text psect. This is unfortunate, since to the linker +this appears to be an entry point. I sent a patch to the compiler to RMS, +which will generate a .const section for these variables, and patched the +assembler to put these variables into a psect just like that for normal +variables, except that they are marked NOWRT. static constants are still +placed in the text psect, since there is no need for any external access. diff --git a/gas/README.coff b/gas/README.coff new file mode 100644 index 0000000..46c61cd --- /dev/null +++ b/gas/README.coff @@ -0,0 +1,79 @@ +The coff patches intend to do the following : + + . Generate coff files very compatible with vanilla linker. + . Understands coff debug directives. + +Here are the guidelines of the work I have done : + + . Encapsulate format dependent code in macros where it is possible. + . Where not possible differenciate with #ifdef + . try not to change the calling conventions of the existing functions. + I made one exception : symbol_new. I would be pleased to hear about + a better solution. (symbols.c) + . Extend the use of N_TYPE_seg seg_N_TYPE tables so that segments can + be manipulated without using their format dependent name. (subsegs.c) + . Write a function to parse the .def debug directives + . Write two small peaces of code to handle the .ln directive. + . In write.c try to move all the cross compilation specifics (md_..) to + format dependent files. + . Encapsulate the data structures using generic types, macros calls. + . Added too much code to resolve the complexity of the symbol table + generated. Most of the code deals with debug stuff. + . Create another makefile, shorter, cleaner. + . Create a config.gas shell script to mimic the gcc,gdb... configuration + mechanism. This reduce the complexity of the makefile. + . Isolate the format dependent code in two files + coff.c coff.h + aout.c aout.h + elf.c elf.h [ Not yet ;-] + . added a little stack management routine for coff in file stack.c + . isolate os specific flags in m- files + +If further development is planed on it is should solve the following problems : + + . Encapsulate DESC & OTHER tests in a macro call. I'm not aware + of their exact semantics. + . Clean up the seg_N_TYPE N_TYPE_seg naming scheme + . Try to remove as much reference to segment dependent names as possible + . Find a cleaner solution for symbol_new. + . Report the modifications on vax, ns32k, sparc machine dependent files. + To acheive this goal, search for \<N_, sy_, symbol_new and symbolS. + . Allow an arbitrary number of segments (spare sections .ctor .dtor .bletch) + . Find a way to extend the debug information without breaking sdb + compatibility. Mainly intended for G++. + . should it do something to generate shared libraries objects ? + +I have tested this code on the following processor/os. gcc-1.37.1 was + used for all the tests. + +386 SCO unix ODT + gcc-1.37.1, gas, emacs-18.55 + +386 Esix rev C + gas-1.37/write.s + +386 Ix 2.02 + gas, all the X11R4 mit clients + +386 CTIX 3.2 + xsol (X11R4 solitary game), gas + +68030 unisoft 1.3 + the kernel (V.3.2) + tcp/ip extensions + bash-1.05, bison-1.11, compress-4.0, cproto, shar-3.49, diff-1.14, + dist-18.55, flex-2.3, gas-1.37, gcc-1.37.1, gdb-3.6, grep-1.5, + kermit, make-3.58, makedep, patch, printf, makeinfo, g++-1.37.1, + tar-1.08, texi2roff, uuencode, uutraf-1.2, libg++-1.37.2, groff-0.5 + +68020 sunos 3.5 (no, not coff, just to be sure that I didn't + introduce errors) + gcc-1.37.1, gas, emacs-18.55, gdb-3.6, bison-1.11, diff-1.14, + make-3.58, tar-1.08 + +68030 sunos 4.0.3 (idem) + gas + +I would be glad to hear about new experiences + + Loic (loic@adesign.uucp or loic@afp.uucp) + diff --git a/gas/README.rich b/gas/README.rich new file mode 100644 index 0000000..1ac53c7 --- /dev/null +++ b/gas/README.rich @@ -0,0 +1,143 @@ + + + The Code Pedigree of This Directory + + +This directory contains a big merge of several development lines of +gas as well as a few bug fixes and some configuration that I've added +in order to retain my own sanity. + +A little history. + +The only common baseline of all versions was gas-1.31. + +From 1.31, Intel branched off and added: + + support for the Intel 80960 (i960) processor. + support for b.out object files. + some bug fixes. + sloppy mac MPW support + Intel gnu/960 makefiles and version numbering. + +Many of the bug fixes found their way into the main development line +prior to 1.36. ALL intel changes were ifdef'd I80960. This was good +as it isolated the changes, but bad in that it connected the b.out +support to the i960 support, and bad in that the bug fixes were only +active in the i960+b.out executables of gas, (although most of these +were nicely marked with comments indicating that they were probably +general bug fixes.) + +To pick up the main FSF development line again, along the way to 1.36, +several new processors were added, many bugs fixed, and the world was +a somewhat better place in general. + +From gas-1.36, Loic at Axis Design (france!) encapsulated object +format specific actions, added coff versions of those encapsulations, +and a config.gas style configuration and Makefile. This was a big +change and a lot of work. + +Then along came the FIRST FSF release of gas-1.37. I say this because +there have been at least two releases of gas-1.37. Only two of them +do we care about for this story, so let's call them gas-1.37.1 and +gas-1.37.2. + +Here starts the confusion. Firstly, gas-1.37.1 did not compile. + +In the meantime, John Gilmore at Cygnus Support had been hacking +gas-1.37.1. He got it to compile. He added support for the AMD 29000 +processor. AND he started encapsulating some of the a.out specific +pieces of code mostly into functions. AND he rebuilt the relocation +info to be generic. AND he restructured somewhat so that for a single +host, cross assemblers could be built for all targets in the same +directory. Useful work but a considerable nuisance because the a29k +changes were not partitioned from the encapsulation changes, the +encapsulation changes were incomplete, and the encapsulation required +functions where alternate structuring might have used macros. Let's +call this version gas-1.37.1+a29k. + +By the time gas-1.37.2 was "released", (remember that it TOO was +labelled by FSF as gas-1.37), it compiled, but it also added i860 +support and ansi style const declarations. + +At this point, Loic rolled his changes into gas-1.37.2. + +What I've done. + +I collected all the stray versions of gas that sounded relevant to my +goals of cross assembly and alternate object file formats and the FSF +releases from which the stray versions had branched. + +I rolled the Intel i960 changes from 1.31 into versions that I call +1.34+i960, 1.36+i960, and then 1.37.1+i960. + +Then I merged 1.37.1+i960 with 1.37.1+a29k to produce what I call +1.37.1+i960+a29k or 1.37.3. + +From 1.37.3, I pulled in Loic's stuff. This wasn't easy as Loic's +stuff hit all the same points as John's encapsulations. Loic's goal +was to split the a.out from coff dependancies for native assembly on +coff, while John's was to split for multiple cross assembly from a +single host. + +Loic's config arranged files much like emacs into m-*, etc. I've +rearranged these somewhat. + +Theory: + +The goal of the new configuration scheme is to bury all object format, +target processor, and host machine dependancies in object, target, and +host specific files. That is, to move all #ifdef's out of the gas +common code. + +Here's how it works. There is a .h and a .c file for each object file +format, a .h and a .c file for each target processor, and a .h for +each host. config.gas creates {sym}links in the current directory to +the appropriate files in the config directory. config.gas also serves +as a list of triplets {host, target, object-format} that have been +tested at one time or another. I also recommend that config.gas be +used to document triplet specific notes as to purpose of the triplet, +etc. + +Implementation: + +host.h is a {sym}link to .../config/xm-yourhost.h. It is intended to +be used to hide host compiler, system header file, and system library +differences between host machines. If your host needs actual c source +files, then either: these are generally useful functions, in which +case you should probably build a local library outside of the gas +source tree, or someone, perhaps me, is confused about what is needed +by different hosts. + +obj-format.h is a {sym}link to .../config/obj-something.h. It is intended + +All gas .c files include as.h. + +as.h #define's "gas", includes host.h, defines a number of gas +specific structures and types, and then includes tp.h, obj.h, and +target-environment.h. + +target-environment.h defines a target environment specific +preprocessor flag, eg, TE_SUN, and then includes obj-format.h. + +obj-format.h defines an object format specific preprocessor flag, eg, +OBJ_AOUT, OBJ_BOUT, OBJ_COFF, includes "target-processor.h", and then +defines the object specific macros, functions, types, and structures. + +target-processor.h + +target-processor. + +Porting: + +There appear to be four major types of ports; new hosts, new target +processors, new object file formats, and new target environments. + + +----- + +reloc now stored internally as generic. (symbols too?) (segment types +vs. names?) + +I don't mean to overlook anyone here. There have also been several +other development lines here that I looked at and elected to bypass. +Specifically, xxx's stabs in coff stuff was particularly tempting. diff --git a/gas/VERSION b/gas/VERSION new file mode 100755 index 0000000..5625e59 --- /dev/null +++ b/gas/VERSION @@ -0,0 +1 @@ +1.2 diff --git a/gas/config/ho-ansi.h b/gas/config/ho-ansi.h index b7fc587..977808f 100644 --- a/gas/config/ho-ansi.h +++ b/gas/config/ho-ansi.h @@ -31,7 +31,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * $Log$ - * Revision 1.1 1991/04/04 18:15:38 rich + * Revision 1.1.1.1 1991/04/04 18:15:39 rich + * new gas main line + * + * Revision 1.1 1991/04/04 18:15:38 rich * Initial revision * * diff --git a/gas/config/ho-cygnus.h b/gas/config/ho-cygnus.h index 9b39153..e2667a0 100755 --- a/gas/config/ho-cygnus.h +++ b/gas/config/ho-cygnus.h @@ -32,7 +32,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * $Log$ - * Revision 1.1 1991/04/04 18:15:40 rich + * Revision 1.1.1.1 1991/04/04 18:15:42 rich + * new gas main line + * + * Revision 1.1 1991/04/04 18:15:40 rich * Initial revision * * diff --git a/gas/config/ho-decstation.h b/gas/config/ho-decstation.h new file mode 100644 index 0000000..f307e20 --- /dev/null +++ b/gas/config/ho-decstation.h @@ -0,0 +1,25 @@ +/* ho-pmax.h Host-specific header file for decstation 3100. + 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. */ + +#include <string.h> + +extern char *malloc(); +extern int free(); + +/* end of ho-pmax.h */ diff --git a/gas/config/ho-generic.h b/gas/config/ho-generic.h index 40c49e9..c474665 100644 --- a/gas/config/ho-generic.h +++ b/gas/config/ho-generic.h @@ -23,7 +23,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * $Log$ - * Revision 1.1 1991/04/04 18:15:42 rich + * Revision 1.1.1.1 1991/04/04 18:15:43 rich + * new gas main line + * + * Revision 1.1 1991/04/04 18:15:42 rich * Initial revision * * diff --git a/gas/config/ho-rs6000.h b/gas/config/ho-rs6000.h new file mode 100644 index 0000000..8f624f4 --- /dev/null +++ b/gas/config/ho-rs6000.h @@ -0,0 +1,22 @@ +/* ho-rs6000.h Rs6000 host-specific header file. + 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. */ + +#define M_RS6000 1 + +/* end of ho-rs6000.h */ diff --git a/gas/config/ho-vax.h b/gas/config/ho-vax.h new file mode 100644 index 0000000..735a215 --- /dev/null +++ b/gas/config/ho-vax.h @@ -0,0 +1,29 @@ +/* ho-vax.h Intended for vax ultrix + 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. */ + +#define M_VAX 1 + +#ifndef __STDC__ +#define NO_STDARG +#endif /* not ansi */ + +extern char *malloc(); +extern int free(); + +/* end of ho-vax.h */ diff --git a/gas/config/mh-cygnus b/gas/config/mh-cygnus new file mode 100755 index 0000000..774d205 --- /dev/null +++ b/gas/config/mh-cygnus @@ -0,0 +1,8 @@ +CC = gcc -b$(target) -Wall -nostdinc -nostdlib \ + -I$(srcdir)/../clib/ansi/include -I$(srcdir)/../os-layer/include + +CLIB = $(srcdir)/../clib/Host-$(host)/Target-$(target)/libc.a \ + $(srcdir)/../gcc/Host-sun4/Target-$(target)/gnulib + +LDFLAGS = /lib/crt0.o + diff --git a/gas/config/mh-i386 b/gas/config/mh-i386 new file mode 100644 index 0000000..3375d42 --- /dev/null +++ b/gas/config/mh-i386 @@ -0,0 +1 @@ +ALLOCA=alloca.o diff --git a/gas/config/obj-bfd-sunos.c b/gas/config/obj-bfd-sunos.c new file mode 100644 index 0000000..0bbc600 --- /dev/null +++ b/gas/config/obj-bfd-sunos.c @@ -0,0 +1,51 @@ +#include "as.h" + +static + +const short seg_N_TYPE[] = { + N_ABS, + N_TEXT, + N_DATA, + N_BSS, + N_UNDF, /* unknown */ + N_UNDF, /* absent */ + N_UNDF, /* pass1 */ + N_UNDF, /* error */ + N_UNDF, /* bignum/flonum */ + N_UNDF, /* difference */ + N_REGISTER, /* register */ +}; + +const segT N_TYPE_seg [N_TYPE+2] = { /* N_TYPE == 0x1E = 32-2 */ + SEG_UNKNOWN, /* N_UNDF == 0 */ + SEG_GOOF, + SEG_ABSOLUTE, /* N_ABS == 2 */ + SEG_GOOF, + SEG_TEXT, /* N_TEXT == 4 */ + SEG_GOOF, + SEG_DATA, /* N_DATA == 6 */ + SEG_GOOF, + SEG_BSS, /* N_BSS == 8 */ + SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_REGISTER, /* dummy N_REGISTER for regs = 30 */ + SEG_GOOF, +}; + + +void obj_symbol_new_hook(symbolP) +symbolS *symbolP; +{ + return; +} /* obj_symbol_new_hook() */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-bfd-sunos.c */ diff --git a/gas/config/obj-bfd-sunos.h b/gas/config/obj-bfd-sunos.h new file mode 100644 index 0000000..0d32758 --- /dev/null +++ b/gas/config/obj-bfd-sunos.h @@ -0,0 +1,50 @@ +/* + * This file is obj-bfd-sunos.h. + */ + + /* define an obj specific macro off which target cpu back ends may key. */ +#define OBJ_BFD +#define OBJ_BFD_SUNOS + +#include "bfd.h" + + /* include whatever target cpu is appropriate. */ +#include "targ-cpu.h" + +/* + * SYMBOLS + */ + +/* + * If your object format needs to reorder symbols, define this. When + * defined, symbols are kept on a doubly linked list and functions are + * made available for push, insert, append, and delete. If not defined, + * symbols are kept on a singly linked list, only the append and clear + * facilities are available, and they are macros. + */ + + /* #define SYMBOLS_NEED_PACKPOINTERS */ + +typedef asymbol obj_symbol_type; +typedef void *object_headers; + +#define S_SET_NAME(s, v) ((s)->sy_symbol.name = (v)) +#define S_GET_NAME(s) ((s)->sy_symbol.name) +#define S_SET_SEGMENT(s,v) ((s)->sy_symbol.udata = (v)) +#define S_GET_SEGMENT(s) ((s)->sy_symbol.udata) +#define S_SET_EXTERNAL(s) ((s)->sy_symbol.flags |= BSF_GLOBAL) +#define S_SET_VALUE(s,v) ((s)->sy_symbol.value = (v)) +#define S_GET_VALUE(s) ((s)->sy_symbol.value) +#define S_IS_DEFINED(s) (!((s)->sy_symbol.flags & BSF_UNDEFINED)) + +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (0) /* your magic number */ +#define OBJ_EMIT_LINENO(a,b,c) /* must be *something*. This no-op's it out. */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-bfd-sunos.h */ diff --git a/gas/config/te-motor.h b/gas/config/te-motor.h new file mode 100755 index 0000000..2254841 --- /dev/null +++ b/gas/config/te-motor.h @@ -0,0 +1,4 @@ +/* Machine specific defines for the unisoft 680x0 V.3.2 version 1.3 */ + +/* Remove leading underscore from the gcc generated symbol names */ +#define STRIP_UNDERSCORE 1 diff --git a/gas/config/te-sco386.h b/gas/config/te-sco386.h new file mode 100644 index 0000000..8bcb688 --- /dev/null +++ b/gas/config/te-sco386.h @@ -0,0 +1,8 @@ +/* Machine specific defines for the SCO Unix V.3.2 ODT */ +#define scounix + +/* Return true if s (a non null string pointer), points to a local variable name. */ +#define LOCAL_LABEL(n) ((n)[0] == '.' && (n)[1] == 'L') + +/* Compiler does not generate symbol names with a leading underscore. */ +#define STRIP_UNDERSCORE 0 diff --git a/gas/config/te-sparc.h b/gas/config/te-sparc.h new file mode 100755 index 0000000..fcd3535 --- /dev/null +++ b/gas/config/te-sparc.h @@ -0,0 +1,52 @@ +/* sparc.h -- Header file for the SPARC + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * The following enum and struct were borrowed from + * sunOS /usr/include/sun4/a.out.h + * + */ + +enum reloc_type +{ + RELOC_8, RELOC_16, RELOC_32, RELOC_DISP8, + RELOC_DISP16, RELOC_DISP32, RELOC_WDISP30, RELOC_WDISP22, + RELOC_HI22, RELOC_22, RELOC_13, RELOC_LO10, + RELOC_SFA_BASE, RELOC_SFA_OFF13, RELOC_BASE10, RELOC_BASE13, + RELOC_BASE22, RELOC_PC10, RELOC_PC22, RELOC_JMP_TBL, + RELOC_SEGOFF16, RELOC_GLOB_DAT, RELOC_JMP_SLOT, RELOC_RELATIVE, + + NO_RELOC +}; + +struct reloc_info_sparc +{ + unsigned long r_address; +/* + * Using bit fields here is a bad idea because the order is not portable. :-( + */ + unsigned int r_index : 24; + unsigned int r_extern : 1; + unsigned int unused : 2; + enum reloc_type r_type : 5; + long r_addend; +}; + +#define relocation_info reloc_info_sparc + diff --git a/gas/config/te-unisoft.h b/gas/config/te-unisoft.h new file mode 100755 index 0000000..2254841 --- /dev/null +++ b/gas/config/te-unisoft.h @@ -0,0 +1,4 @@ +/* Machine specific defines for the unisoft 680x0 V.3.2 version 1.3 */ + +/* Remove leading underscore from the gcc generated symbol names */ +#define STRIP_UNDERSCORE 1 diff --git a/gas/config/tmake-sun3 b/gas/config/tmake-sun3 new file mode 100755 index 0000000..9681e6d --- /dev/null +++ b/gas/config/tmake-sun3 @@ -0,0 +1 @@ +# This line from make-sun3. diff --git a/gas/config/vms/objrecdef.h b/gas/config/vms/objrecdef.h new file mode 100644 index 0000000..fca8af4 --- /dev/null +++ b/gas/config/vms/objrecdef.h @@ -0,0 +1,255 @@ +/* + * + * $OBJRECDEF + * Generated automatically by "vms_struct Version 1.00" + * Created from VMS definition file "objrecdef.mar" + * Mon Oct 14 14:01:29 1985 + * + */ +struct OBJREC { + unsigned char obj$b_rectyp; + unsigned char obj$b_subtyp; + unsigned char obj$b_mhd_strlv; + unsigned char obj$b_mhd_recsz[2]; + unsigned char obj$t_mhd_name[1]; + }; + +#define OBJ$C_HDR 0 +#define OBJ$C_HDR_MHD 0 +#define OBJ$C_HDR_LNM 1 +#define OBJ$C_HDR_SRC 2 +#define OBJ$C_HDR_TTL 3 +#define OBJ$C_HDR_CPR 4 +#define OBJ$C_HDR_MTC 5 +#define OBJ$C_HDR_GTX 6 +#define OBJ$C_GSD 1 +#define OBJ$C_GSD_PSC 0 +#define OBJ$C_GSD_SYM 1 +#define OBJ$C_GSD_EPM 2 +#define OBJ$C_GSD_PRO 3 +#define OBJ$C_GSD_SYMW 4 +#define OBJ$C_GSD_EPMW 5 +#define OBJ$C_GSD_PROW 6 +#define OBJ$C_GSD_IDC 7 +#define OBJ$C_GSD_ENV 8 +#define OBJ$C_GSD_LSY 9 +#define OBJ$C_GSD_LEPM 10 +#define OBJ$C_GSD_LPRO 11 +#define OBJ$C_GSD_SPSC 12 +#define OBJ$C_TIR 2 +#define OBJ$C_EOM 3 +#define OBJ$C_DBG 4 +#define OBJ$C_TBT 5 +#define OBJ$C_LNK 6 +#define OBJ$C_EOMW 7 +#define OBJ$C_MAXRECTYP 7 +#define OBJ$K_SUBTYP 1 +#define OBJ$C_SUBTYP 1 +#define OBJ$C_MAXRECSIZ 2048 +#define OBJ$C_STRLVL 0 +#define OBJ$C_SYMSIZ 31 +#define OBJ$C_STOREPLIM -1 +#define OBJ$C_PSCALILIM 9 + +#define MHD$C_MHD 0 +#define MHD$C_LNM 1 +#define MHD$C_SRC 2 +#define MHD$C_TTL 3 +#define MHD$C_CPR 4 +#define MHD$C_MTC 5 +#define MHD$C_GTX 6 +#define MHD$C_MAXHDRTYP 6 + +#define GSD$K_ENTRIES 1 +#define GSD$C_ENTRIES 1 +#define GSD$C_PSC 0 +#define GSD$C_SYM 1 +#define GSD$C_EPM 2 +#define GSD$C_PRO 3 +#define GSD$C_SYMW 4 +#define GSD$C_EPMW 5 +#define GSD$C_PROW 6 +#define GSD$C_IDC 7 +#define GSD$C_ENV 8 +#define GSD$C_LSY 9 +#define GSD$C_LEPM 10 +#define GSD$C_LPRO 11 +#define GSD$C_SPSC 12 +#define GSD$C_SYMV 13 +#define GSD$C_EPMV 14 +#define GSD$C_PROV 15 +#define GSD$C_MAXRECTYP 15 + +#define GSY$M_WEAK 1 +#define GSY$M_DEF 2 +#define GSY$M_UNI 4 +#define GSY$M_REL 8 + +#define GPS$M_PIC 1 +#define GPS$M_LIB 2 +#define GPS$M_OVR 4 +#define GPS$M_REL 8 +#define GPS$M_GBL 16 +#define GPS$M_SHR 32 +#define GPS$M_EXE 64 +#define GPS$M_RD 128 +#define GPS$M_WRT 256 +#define GPS$M_VEC 512 +#define GPS$K_NAME 9 +#define GPS$C_NAME 9 + +#define TIR$C_STA_GBL 0 +#define TIR$C_STA_SB 1 +#define TIR$C_STA_SW 2 +#define TIR$C_STA_LW 3 +#define TIR$C_STA_PB 4 +#define TIR$C_STA_PW 5 +#define TIR$C_STA_PL 6 +#define TIR$C_STA_UB 7 +#define TIR$C_STA_UW 8 +#define TIR$C_STA_BFI 9 +#define TIR$C_STA_WFI 10 +#define TIR$C_STA_LFI 11 +#define TIR$C_STA_EPM 12 +#define TIR$C_STA_CKARG 13 +#define TIR$C_STA_WPB 14 +#define TIR$C_STA_WPW 15 +#define TIR$C_STA_WPL 16 +#define TIR$C_STA_LSY 17 +#define TIR$C_STA_LIT 18 +#define TIR$C_STA_LEPM 19 +#define TIR$C_MAXSTACOD 19 +#define TIR$C_MINSTOCOD 20 +#define TIR$C_STO_SB 20 +#define TIR$C_STO_SW 21 +#define TIR$C_STO_L 22 +#define TIR$C_STO_BD 23 +#define TIR$C_STO_WD 24 +#define TIR$C_STO_LD 25 +#define TIR$C_STO_LI 26 +#define TIR$C_STO_PIDR 27 +#define TIR$C_STO_PICR 28 +#define TIR$C_STO_RSB 29 +#define TIR$C_STO_RSW 30 +#define TIR$C_STO_RL 31 +#define TIR$C_STO_VPS 32 +#define TIR$C_STO_USB 33 +#define TIR$C_STO_USW 34 +#define TIR$C_STO_RUB 35 +#define TIR$C_STO_RUW 36 +#define TIR$C_STO_B 37 +#define TIR$C_STO_W 38 +#define TIR$C_STO_RB 39 +#define TIR$C_STO_RW 40 +#define TIR$C_STO_RIVB 41 +#define TIR$C_STO_PIRR 42 +#define TIR$C_MAXSTOCOD 42 +#define TIR$C_MINOPRCOD 50 +#define TIR$C_OPR_NOP 50 +#define TIR$C_OPR_ADD 51 +#define TIR$C_OPR_SUB 52 +#define TIR$C_OPR_MUL 53 +#define TIR$C_OPR_DIV 54 +#define TIR$C_OPR_AND 55 +#define TIR$C_OPR_IOR 56 +#define TIR$C_OPR_EOR 57 +#define TIR$C_OPR_NEG 58 +#define TIR$C_OPR_COM 59 +#define TIR$C_OPR_INSV 60 +#define TIR$C_OPR_ASH 61 +#define TIR$C_OPR_USH 62 +#define TIR$C_OPR_ROT 63 +#define TIR$C_OPR_SEL 64 +#define TIR$C_OPR_REDEF 65 +#define TIR$C_OPR_DFLIT 66 +#define TIR$C_MAXOPRCOD 66 +#define TIR$C_MINCTLCOD 80 +#define TIR$C_CTL_SETRB 80 +#define TIR$C_CTL_AUGRB 81 +#define TIR$C_CTL_DFLOC 82 +#define TIR$C_CTL_STLOC 83 +#define TIR$C_CTL_STKDL 84 +#define TIR$C_MAXCTLCOD 84 + +/* + * Debugger symbol definitions: These are done by hand, as no + * machine-readable version seems + * to be available. + */ +#define DST$C_C 7 /* Language == "C" */ +#define DST$C_VERSION 153 +#define DST$C_SOURCE 155 /* Source file */ +#define DST$C_PROLOG 162 +#define DST$C_BLKBEG 176 /* Beginning of block */ +#define DST$C_BLKEND 177 /* End of block */ +#define DST$C_ENTRY 181 +#define DST$C_PSECT 184 +#define DST$C_LINE_NUM 185 /* Line Number */ +#define DST$C_LBLORLIT 186 +#define DST$C_LABEL 187 +#define DST$C_MODBEG 188 /* Beginning of module */ +#define DST$C_MODEND 189 /* End of module */ +#define DST$C_RTNBEG 190 /* Beginning of routine */ +#define DST$C_RTNEND 191 /* End of routine */ +#define DST$C_DELTA_PC_W 1 /* Incr PC */ +#define DST$C_INCR_LINUM 2 /* Incr Line # */ +#define DST$C_INCR_LINUM_W 3 /* Incr Line # */ +#define DST$C_SET_LINUM_INCR 4 +#define DST$C_SET_LINUM_INCR_W 5 +#define DST$C_RESET_LINUM_INCR 6 +#define DST$C_BEG_STMT_MODE 7 +#define DST$C_END_STMT_MODE 8 +#define DST$C_SET_LINE_NUM 9 /* Set Line # */ +#define DST$C_SET_PC 10 +#define DST$C_SET_PC_W 11 +#define DST$C_SET_PC_L 12 +#define DST$C_SET_STMTNUM 13 +#define DST$C_TERM 14 /* End of lines */ +#define DST$C_TERM_W 15 /* End of lines */ +#define DST$C_SET_ABS_PC 16 /* Set PC */ +#define DST$C_DELTA_PC_L 17 /* Incr PC */ +#define DST$C_INCR_LINUM_L 18 /* Incr Line # */ +#define DST$C_SET_LINUM_B 19 /* Set Line # */ +#define DST$C_SET_LINUM_L 20 /* Set Line # */ +#define DST$C_TERM_L 21 /* End of lines */ +/* these are used with DST$C_SOURCE */ +#define DST$C_SRC_FORMFEED 16 /* ^L counts */ +#define DST$C_SRC_DECLFILE 1 /* Declare file */ +#define DST$C_SRC_SETFILE 2 /* Set file */ +#define DST$C_SRC_SETREC_L 3 /* Set record */ +#define DST$C_SRC_DEFLINES_W 10 /* # of line */ +/* the following are the codes for the various data types. Anything not on + * the list is included under 'advanced_type' + */ +#define DBG$C_UCHAR 0x02 +#define DBG$C_USINT 0x03 +#define DBG$C_ULINT 0x04 +#define DBG$C_SCHAR 0x06 +#define DBG$C_SSINT 0x07 +#define DBG$C_SLINT 0x08 +#define DBG$C_REAL4 0x0a +#define DBG$C_REAL8 0x0b +#define DBG$C_FUNCTION_ADDR 0x17 +#define DBG$C_ADVANCED_TYPE 0xa3 +/* These are the codes that are used to generate the definitions of struct + * union and enum records + */ +#define DBG$C_ENUM_ITEM 0xa4 +#define DBG$C_ENUM_START 0xa5 +#define DBG$C_ENUM_END 0xa6 +#define DBG$C_STRUCT_START 0xab +#define DBG$C_STRUCT_ITEM 0xff +#define DBG$C_STRUCT_END 0xac +/* These are the codes that are used in the suffix records to determine the + * actual data type + */ +#define DBG$C_BASIC 0x01 +#define DBG$C_BASIC_ARRAY 0x02 +#define DBG$C_STRUCT 0x03 +#define DBG$C_POINTER 0x04 +#define DBG$C_VOID 0x05 +#define DBG$C_COMPLEX_ARRAY 0x07 +/* These codes are used in the generation of the symbol definition records + */ +#define DBG$C_FUNCTION_PARAMETER 0xc9 +#define DBG$C_LOCAL_SYM 0xd9 diff --git a/gas/config/vms/vms-dbg.c b/gas/config/vms/vms-dbg.c new file mode 100644 index 0000000..19c6c93 --- /dev/null +++ b/gas/config/vms/vms-dbg.c @@ -0,0 +1,1125 @@ +#include <stdio.h> +#include "as.h" +#include "struc-symbol.h" +#include "symbols.h" +#include "objrecdef.h" +#include <stab.h> + +/* This file contains many of the routines needed to output debugging info into + * the object file that the VMS debugger needs to understand symbols. These + * routines are called very late in the assembly process, and thus we can be + * fairly lax about changing things, since the GSD and the TIR sections have + * already been output. + */ + +/* We need this info to cross correlate between the stabs def for a symbol and + * the actual symbol def. The actual symbol def contains the psect number and + * offset, which is needed to declare a variable to the debugger for global + * and static variables + */ +struct VMS_Symbol { + struct VMS_Symbol *Next; + struct symbol *Symbol; + int Size; + int Psect_Index; + int Psect_Offset; + }; +extern struct VMS_Symbol *VMS_Symbols; + +enum advanced_type {BASIC,POINTER,ARRAY,ENUM,STRUCT,UNION,FUNCTION,VOID,UNKNOWN}; + +/* this structure contains the information from the stabs directives, and the + * information is filled in by VMS_typedef_parse. Everything that is needed + * to generate the debugging record for a given symbol is present here. + * This could be done more efficiently, using nested struct/unions, but for now + * I am happy that it works. + */ +struct VMS_DBG_Symbol{ + struct VMS_DBG_Symbol * next; + enum advanced_type advanced; /* description of what this is */ + int dbx_type; /* this record is for this type */ + int type2; /* For advanced types this is the type referred to. + i.e. the type a pointer points to, or the type + of object that makes up an array */ + int VMS_type; /* Use this type when generating a variable def */ + int index_min; /* used for arrays - this will be present for all */ + int index_max; /* entries, but will be meaningless for non-arrays */ + int data_size; /* size in bytes of the data type. For an array, this + is the size of one element in the array */ + int struc_numb; /* Number of the structure/union/enum - used for ref */ +}; + +struct VMS_DBG_Symbol *VMS_Symbol_type_list={(struct VMS_DBG_Symbol*) NULL}; + +/* we need this structure to keep track of forward references to + * struct/union/enum that have not been defined yet. When they are ultimately + * defined, then we can go back and generate the TIR commands to make a back + * reference. + */ + +struct forward_ref{ + struct forward_ref * next; + int dbx_type; + int struc_numb; + char resolved; + }; + +struct forward_ref * f_ref_root={(struct forward_ref*) NULL}; + +static char * symbol_name; +static structure_count=0; + +/* this routine converts a number string into an integer, and stops when it + * sees an invalid character the return value is the address of the character + * just past the last character read. No error is generated. + */ +static char * cvt_integer(char* str,int * rtn){ + int ival, neg; + neg = *str == '-' ? ++str, -1 : 1; + ival=0; /* first get the number of the type for dbx */ + while((*str <= '9') && (*str >= '0')) + ival = 10*ival + *str++ -'0'; + *rtn = neg*ival; + return str; +} + +/* this routine fixes the names that are generated by C++, ".this" is a good + * example. The period does not work for the debugger, since it looks like + * the syntax for a structure element, and thus it gets mightily confused + */ +static fix_name(char* pnt){ + for( ;*pnt != 0; pnt++){ + if(*pnt == '.') *pnt = '$'; + }; +} + +/* this routine is used to compare the names of certain types to various + * fixed types that are known by the debugger. + */ +#define type_check(x) !strcmp( symbol_name , x ) + +/* When defining a structure, this routine is called to find the name of + * the actual structure. It is assumed that str points to the equal sign + * in the definition, and it moves backward until it finds the start of the + * name. If it finds a 0, then it knows that this structure def is in the + * outermost level, and thus symbol_name points to the symbol name. + */ +static char* get_struct_name(char* str){ + char* pnt; + pnt=str; + while((*pnt != ':') && (*pnt != '\0')) pnt--; + if(*pnt == '\0') return symbol_name; + *pnt-- = '\0'; + while((*pnt != ';') && (*pnt != '=')) pnt--; + if(*pnt == ';') return pnt+1; + while((*pnt < '0') || (*pnt > '9')) pnt++; + while((*pnt >= '0') && (*pnt <= '9')) pnt++; + return pnt; +} +/* search symbol list for type number dbx_type. Return a pointer to struct */ +static struct VMS_DBG_Symbol* find_symbol(int dbx_type){ + struct VMS_DBG_Symbol* spnt; + spnt=VMS_Symbol_type_list; + while (spnt!=(struct VMS_DBG_Symbol*) NULL){ + if(spnt->dbx_type==dbx_type) break; + spnt=spnt->next;}; + if(spnt==(struct VMS_DBG_Symbol*) NULL) return 0;/*Dunno what this is*/ + return spnt; +} + + +/* Many good programmers cringe when they see a fixed size array - since I am + * using this to generate the various descriptors for the data types present, + * you might argue that the descriptor could overflow the array for a + * complicated variable, and then I am in deep doo-doo. My answer to this is + * that the debugger records that we write have all sorts of length bytes + * stored in them all over the place, and if we exceed 127 bytes (since the top + * bit indicates data, rather than a command), we are dead anyhow. So I figure + * why not do this the easy way. Besides, to get 128 bytes, you need something + * like an array with 10 indicies, or something like + * char **************************************** var; + * Lets get real. If some idiot writes programs like that he/she gets what + * they deserve. (It is possible to overflow the record with a somewhat + * simpler example, like: int (*(*(*(*(*(* sarr6)[1])[1])[2])[3])[4])[5]; + * but still...). And if someone in the peanut gallery wants to know "What + * does VAX-C do with something like this?", I will tell you. It crashes. + * At least this code has the good sense to convert it to *void. + * In practice, I do not think that this presents too much of a problem, since + * struct/union/enum all use defined types, which sort of terminate the + * definition. It occurs to me that we could possibly do the same thing with + * arrays and pointers, but I don't know quite how it would be coded. + * + * And now back to the regularly scheduled program... + */ +#define MAX_DEBUG_RECORD 128 +static char Local[MAX_DEBUG_RECORD]; /* buffer for variable descriptor */ +static int Lpnt; /* index into Local */ +static char Asuffix[MAX_DEBUG_RECORD]; /* buffer for array descriptor */ +static int Apoint; /* index into Asuffix */ +static char overflow; /* flag to indicate we have written too much*/ +static int total_len; /* used to calculate the total length of variable + descriptor plus array descriptor - used for len byte*/ +static int struct_number; /* counter used to assign indexes to struct + unions and enums */ + +/* this routine puts info into either Local or Asuffix, depending on the sign + * of size. The reason is that it is easier to build the variable descriptor + * backwards, while the array descriptor is best built forwards. In the end + * they get put together, if there is not a struct/union/enum along the way + */ +push(int value, int size){ + char * pnt; + int i; + int size1; + long int val; + val=value; + pnt=(char*) &val; + size1 = size; + if (size < 0) {size1 = -size; pnt += size1-1;}; + if(size < 0) + for(i=0;i<size1;i++) { + Local[Lpnt--] = *pnt--; + if(Lpnt < 0) {overflow = 1; Lpnt = 1;};} + else for(i=0;i<size1;i++){ + Asuffix[Apoint++] = *pnt++; + if(Apoint >= MAX_DEBUG_RECORD) + {overflow = 1; Apoint =MAX_DEBUG_RECORD-1;};} +} + +/* this routine generates the array descriptor for a given array */ +static array_suffix(struct VMS_DBG_Symbol* spnt2){ + struct VMS_DBG_Symbol * spnt; + struct VMS_DBG_Symbol * spnt1; + int rank; + int total_size; + int i; + rank=0; + spnt=spnt2; + while(spnt->advanced != ARRAY) { + spnt=find_symbol(spnt->type2); + if(spnt == (struct VMS_DBG_Symbol *) NULL) return;}; + spnt1=spnt; + spnt1=spnt; + total_size= 1; + while(spnt1->advanced == ARRAY) {rank++; + total_size *= (spnt1->index_max - spnt1->index_min +1); + spnt1=find_symbol(spnt1->type2);}; + total_size = total_size * spnt1->data_size; + push(spnt1->data_size,2); + if(spnt1->VMS_type == 0xa3) push(0,1); + else push(spnt1->VMS_type,1); + push(4,1); + for(i=0;i<6;i++) push(0,1); + push(0xc0,1); + push(rank,1); + push(total_size,4); + push(0,4); + spnt1=spnt; + while(spnt1->advanced == ARRAY) { + push(spnt1->index_max - spnt1->index_min+1,4); + spnt1=find_symbol(spnt1->type2);}; + spnt1=spnt; + while(spnt1->advanced == ARRAY) { + push(spnt1->index_min,4); + push(spnt1->index_max,4); + spnt1=find_symbol(spnt1->type2);}; +} + +/* this routine generates the start of a variable descriptor based upon + * a struct/union/enum that has yet to be defined. We define this spot as + * a new location, and save four bytes for the address. When the struct is + * finally defined, then we can go back and plug in the correct address +*/ +static new_forward_ref(int dbx_type){ + struct forward_ref* fpnt; + fpnt = (struct forward_ref*) malloc(sizeof(struct forward_ref)); + fpnt->next = f_ref_root; + f_ref_root = fpnt; + fpnt->dbx_type = dbx_type; + fpnt->struc_numb = ++structure_count; + fpnt->resolved = 'N'; + push(3,-1); + total_len = 5; + push(total_len,-2); + struct_number = - fpnt->struc_numb; +} + +/* this routine generates the variable descriptor used to describe non-basic + * variables. It calls itself recursively until it gets to the bottom of it + * all, and then builds the descriptor backwards. It is easiest to do it this + *way since we must periodically write length bytes, and it is easiest if we know + *the value when it is time to write it. + */ +static int gen1(struct VMS_DBG_Symbol * spnt,int array_suffix_len){ + struct VMS_DBG_Symbol * spnt1; + int i; + switch(spnt->advanced){ + case VOID: + push(DBG$C_VOID,-1); + total_len += 1; + push(total_len,-2); + return 0; + case BASIC: + case FUNCTION: + if(array_suffix_len == 0) { + push(spnt->VMS_type,-1); + push(DBG$C_BASIC,-1); + total_len = 2; + push(total_len,-2); + return 1;}; + push(0,-4); + push(0xfa02,-2); + total_len = -2; + return 1; + case STRUCT: + case UNION: + case ENUM: + struct_number=spnt->struc_numb; + if(struct_number < 0) { + new_forward_ref(spnt->dbx_type); + return 1; + } + push(DBG$C_STRUCT,-1); + total_len = 5; + push(total_len,-2); + return 1; + case POINTER: + spnt1=find_symbol(spnt->type2); + i=1; + if(spnt1 == (struct VMS_DBG_Symbol *) NULL) + new_forward_ref(spnt->type2); + else i=gen1(spnt1,0); + if(i){ /* (*void) is a special case, do not put pointer suffix*/ + push(DBG$C_POINTER,-1); + total_len += 3; + push(total_len,-2); + }; + return 1; + case ARRAY: + spnt1=spnt; + while(spnt1->advanced == ARRAY) + {spnt1 = find_symbol(spnt1->type2); + if(spnt1 == (struct VMS_DBG_Symbol *) NULL) { + printf("gcc-as warning(debugger output):"); + printf("Forward reference error, dbx type %d\n", + spnt->type2); + return;} + }; +/* It is too late to generate forward references, so the user gets a message. + * This should only happen on a compiler error */ + i=gen1(spnt1,1); + i=Apoint; + array_suffix(spnt); + array_suffix_len = Apoint - i; + switch(spnt1->advanced){ + case BASIC: + case FUNCTION: + break; + default: + push(0,-2); + total_len += 2; + push(total_len,-2); + push(0xfa,-1); + push(0x0101,-2); + push(DBG$C_COMPLEX_ARRAY,-1); + }; + total_len += array_suffix_len + 8; + push(total_len,-2); + }; +} + +/* this generates a suffix for a variable. If it is not a defined type yet, + * then dbx_type contains the type we are expecting so we can generate a + * forward reference. This calls gen1 to build most of the descriptor, and + * then it puts the icing on at the end. It then dumps whatever is needed + * to get a complete descriptor (i.e. struct reference, array suffix ). + */ +static generate_suffix(struct VMS_DBG_Symbol * spnt,int dbx_type){ + int ilen; + int i; + char pvoid[6] = {5,0xaf,0,1,0,5}; + struct VMS_DBG_Symbol * spnt1; + Apoint=0; + Lpnt =MAX_DEBUG_RECORD-1; + total_len=0; + struct_number = 0; + overflow = 0; + if(spnt == (struct VMS_DBG_Symbol*) NULL) + new_forward_ref(dbx_type); + else{ + if(spnt->VMS_type != 0xa3) return 0; /* no suffix needed */ + gen1(spnt,0); + }; + push(0x00af,-2); + total_len += 4; + push(total_len,-1); +/* if the variable descriptor overflows the record, output a descriptor for + * a pointer to void. + */ + if((total_len >= MAX_DEBUG_RECORD) || overflow) { + printf(" Variable descriptor %d too complicated. Defined as *void ",spnt->dbx_type); + VMS_Store_Immediate_Data(pvoid, 6, OBJ$C_DBG); + return; + }; + i=0; + while(Lpnt < MAX_DEBUG_RECORD-1) Local[i++] = Local[++Lpnt]; + Lpnt = i; +/* we use this for a reference to a structure that has already been defined */ + if(struct_number > 0){ + VMS_Store_Immediate_Data(Local, Lpnt, OBJ$C_DBG);Lpnt=0; + VMS_Store_Struct(struct_number);}; +/* we use this for a forward reference to a structure that has yet to be +*defined. We store four bytes of zero to make room for the actual address once +* it is known +*/ + if(struct_number < 0){ + struct_number = -struct_number; + VMS_Store_Immediate_Data(Local, Lpnt,OBJ$C_DBG);Lpnt=0; + VMS_Def_Struct(struct_number); + for(i=0;i<4;i++) Local[Lpnt++] = 0; + VMS_Store_Immediate_Data(Local, Lpnt, OBJ$C_DBG);Lpnt=0; + }; + i=0; + while(i<Apoint) Local[Lpnt++] = Asuffix[i++]; + if(Lpnt != 0) + VMS_Store_Immediate_Data(Local, Lpnt, OBJ$C_DBG); + Lpnt=0; + } + +/* This routine generates a symbol definition for a C sybmol for the debugger. + * It takes a psect and offset for global symbols - if psect < 0, then this is + * a local variable and the offset is relative to FP. In this case it can + * be either a variable (Offset < 0) or a parameter (Offset > 0). + */ +VMS_DBG_record(struct VMS_DBG_Symbol* spnt,int Psect,int Offset, char* Name) +{ + char* pnt; + int j; + int maxlen; + int i=0; + if(Psect < 0) { /* this is a local variable, referenced to SP */ + maxlen=7+strlen(Name); + Local[i++] = maxlen; + Local[i++]=spnt->VMS_type; + if(Offset > 0) Local[i++] = DBG$C_FUNCTION_PARAMETER; + else Local[i++] = DBG$C_LOCAL_SYM; + pnt=(char*) &Offset; + for(j=0;j<4;j++) Local[i++]=*pnt++; /* copy the offset */ + } else { + maxlen=7+strlen(Name); /* symbols fixed in memory */ + Local[i++]=7+strlen(Name); + Local[i++]=spnt->VMS_type; + Local[i++]=1; + VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; + VMS_Set_Data(Psect,Offset,OBJ$C_DBG,0); + } + Local[i++]=strlen(Name); + pnt=Name; + fix_name(pnt); /* if there are bad characters in name, convert them */ + while(*pnt!='\0') Local[i++]=*pnt++; + VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); + if(spnt->VMS_type == DBG$C_ADVANCED_TYPE) generate_suffix(spnt,0); +} + + +/* This routine parses the stabs entries in order to make the definition + * for the debugger of local symbols and function parameters + */ +int VMS_local_stab_Parse(symbolS * sp){ + char *pnt; + char *pnt1; + char *str; + struct VMS_DBG_Symbol* spnt; + struct VMS_Symbol * vsp; + int dbx_type; + int VMS_type; + dbx_type=0; + str=sp->sy_nlist.n_un.n_name; + pnt=(char*) strchr(str,':'); + if(pnt==(char*) NULL) return; /* no colon present */ + pnt1=pnt++; /* save this for later, and skip colon */ + if(*pnt == 'c') return 0; /* ignore static constants */ +/* there is one little catch that we must be aware of. Sometimes function + * parameters are optimized into registers, and the compiler, in its infiite + * wisdom outputs stabs records for *both*. In general we want to use the + * register if it is present, so we must search the rest of the symbols for + * this function to see if this parameter is assigned to a register. + */ + { + char *str1; + char *pnt2; + symbolS * sp1; + if(*pnt == 'p'){ + for(sp1 = symbol_next(sp); sp1; sp1 = symbol_next(sp1)) { + if ((sp1->sy_nlist.n_type & N_STAB) == 0) continue; + if((unsigned char)sp1->sy_nlist.n_type == N_FUN) break; + if((unsigned char)sp1->sy_nlist.n_type != N_RSYM) continue; + str1=sp1->sy_nlist.n_un.n_name; /* and get the name */ + pnt2=str; + while(*pnt2 != ':') { + if(*pnt2 != *str1) break; + pnt2++; str1++;}; + if((*str1 != ':') || (*pnt2 != ':') ) continue; + return; /* they are the same! lets skip this one */ + }; /* for */ +/* first find the dbx symbol type from list, and then find VMS type */ + pnt++; /* skip p in case no register */ + };/* if */ }; /* p block */ + pnt = cvt_integer( pnt, &dbx_type); + spnt = find_symbol(dbx_type); + if(spnt==(struct VMS_DBG_Symbol*) NULL) return 0;/*Dunno what this is*/ + *pnt1='\0'; + VMS_DBG_record(spnt,-1,sp->sy_nlist.n_value,str); + *pnt1=':'; /* and restore the string */ + return 1; +} + +/* this routine parses a stabs entry to find the information required to define + * a variable. It is used for global and static variables. + * Basically we need to know the address of the symbol. With older versions + * of the compiler, const symbols are + * treated differently, in that if they are global they are written into the + * text psect. The global symbol entry for such a const is actually written + * as a program entry point (Yuk!!), so if we cannot find a symbol in the list + * of psects, we must search the entry points as well. static consts are even + * harder, since they are never assigned a memory address. The compiler passes + * a stab to tell us the value, but I am not sure what to do with it. + */ +static gave_compiler_message = 0; + +static int VMS_stab_parse(symbolS * sp,char expected_type, + int type1,int type2,int Text_Psect){ + char *pnt; + char *pnt1; + char *str; + symbolS * sp1; + struct VMS_DBG_Symbol* spnt; + struct VMS_Symbol * vsp; + int dbx_type; + int VMS_type; + dbx_type=0; + str=sp->sy_nlist.n_un.n_name; + pnt=(char*) strchr(str,':'); + if(pnt==(char*) NULL) return; /* no colon present */ + pnt1=pnt; /* save this for later*/ + pnt++; + if(*pnt==expected_type){ + pnt = cvt_integer(pnt+1,&dbx_type); + spnt = find_symbol(dbx_type); + if(spnt==(struct VMS_DBG_Symbol*) NULL) return 0;/*Dunno what this is*/ +/* now we need to search the symbol table to find the psect and offset for + * this variable. + */ + *pnt1='\0'; + vsp=VMS_Symbols; + while(vsp != (struct VMS_Symbol*) NULL) + {pnt=vsp->Symbol->sy_nlist.n_un.n_name; + if(pnt!=(char*) NULL) if(*pnt++ == '_') +/* make sure name is the same, and make sure correct symbol type */ + if((strlen(pnt) == strlen(str)) && (strcmp(pnt,str)==0) + && ((vsp->Symbol->sy_type == type1) || + (vsp->Symbol->sy_type == type2))) break; + vsp=vsp->Next;}; + if(vsp != (struct VMS_Symbol*) NULL){ + VMS_DBG_record(spnt,vsp->Psect_Index,vsp->Psect_Offset,str); + *pnt1=':'; /* and restore the string */ + return 1;}; +/* the symbol was not in the symbol list, but it may be an "entry point" + if it was a constant */ + for(sp1 = symbol_rootP; sp1; sp1 = symbol_next(sp1)) { + /* + * Dispatch on STAB type + */ + if(sp1->sy_type != (N_TEXT | N_EXT) && sp1->sy_type!=N_TEXT) + continue; + pnt = sp1->sy_nlist.n_un.n_name; + if(*pnt == '_') pnt++; + if(strcmp(pnt,str) == 0){ + if(!gave_compiler_message && expected_type=='G'){ +printf("***Warning - the assembly code generated by the compiler has placed\n"); +printf("global constant(s) in the text psect. These will not be available to\n"); +printf("other modules, since this is not the correct way to handle this. You\n"); +printf("have two options: 1) get a patched compiler that does not put global\n"); +printf("constants in the text psect, or 2) remove the 'const' keyword from\n"); +printf("definitions of global variables in your source module(s). Don't say\n"); +printf("I didn't warn you!"); +gave_compiler_message = 1;}; + VMS_DBG_record(spnt, + Text_Psect, + sp1->sy_nlist.n_value, + str); + *pnt1=':'; + *(sp1->sy_nlist.n_un.n_name) = 'L'; + /* fool assembler to not output this + * as a routine in the TBT */ + return 1;}; + }; + }; + *pnt1=':'; /* and restore the string */ + return 0; +} + + +VMS_GSYM_Parse(symbolS * sp,int Text_Psect){ /* Global variables */ + VMS_stab_parse(sp,'G',(N_UNDF | N_EXT),(N_DATA | N_EXT),Text_Psect); +} + + +VMS_LCSYM_Parse(symbolS * sp,int Text_Psect){/* Static symbols - uninitialized */ + VMS_stab_parse(sp,'S',N_BSS,-1,Text_Psect); +} + +VMS_STSYM_Parse(symbolS * sp,int Text_Psect){ /*Static symbols - initialized */ + VMS_stab_parse(sp,'S',N_DATA,-1,Text_Psect); +} + + +/* for register symbols, we must figure out what range of addresses within the + * psect are valid. We will use the brackets in the stab directives to give us + * guidance as to the PC range that this variable is in scope. I am still not + * completely comfortable with this but as I learn more, I seem to get a better + * handle on what is going on. + * Caveat Emptor. + */ +VMS_RSYM_Parse(symbolS * sp,symbolS * Current_Routine,int Text_Psect){ + char* pnt; + char* pnt1; + char* str; + int dbx_type; + struct VMS_DBG_Symbol* spnt; + int j; + int maxlen; + int i=0; + int bcnt=0; + int Min_Offset=-1; /* min PC of validity */ + int Max_Offset=0; /* max PC of validity */ + symbolS * symbolP; + for(symbolP = sp; symbolP; symbolP = symbol_next(symbolP)) { + /* + * Dispatch on STAB type + */ + switch((unsigned char)symbolP->sy_type) { + case N_LBRAC: + if(bcnt++==0) Min_Offset = symbolP->sy_nlist.n_value; + break; + case N_RBRAC: + if(--bcnt==0) Max_Offset = + symbolP->sy_nlist.n_value-1; + break; + } + if((Min_Offset != -1) && (bcnt == 0)) break; + if((unsigned char)symbolP->sy_type == N_FUN) break; + } +/* check to see that the addresses were defined. If not, then there were no + * brackets in the function, and we must try to search for the next function + * Since functions can be in any order, we should search all of the symbol list + * to find the correct ending address. */ + if(Min_Offset == -1){ + int Max_Source_Offset; + int This_Offset; + Min_Offset = sp->sy_nlist.n_value; + for(symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + /* + * Dispatch on STAB type + */ + This_Offset = symbolP->sy_nlist.n_value; + switch(symbolP->sy_type) { + case N_TEXT | N_EXT: + if((This_Offset > Min_Offset) && (This_Offset < Max_Offset)) + Max_Offset = This_Offset; + break; + case N_SLINE: + if(This_Offset > Max_Source_Offset) + Max_Source_Offset=This_Offset; + } + } +/* if this is the last routine, then we use the PC of the last source line + * as a marker of the max PC for which this reg is valid */ + if(Max_Offset == 0x7fffffff) Max_Offset = Max_Source_Offset; + }; + dbx_type=0; + str=sp->sy_nlist.n_un.n_name; + pnt=(char*) strchr(str,':'); + if(pnt==(char*) NULL) return; /* no colon present */ + pnt1=pnt; /* save this for later*/ + pnt++; + if(*pnt!='r') return 0; + pnt = cvt_integer( pnt+1, &dbx_type); + spnt = find_symbol(dbx_type); + if(spnt==(struct VMS_DBG_Symbol*) NULL) return 0;/*Dunno what this is yet*/ + *pnt1='\0'; + maxlen=25+strlen(sp->sy_nlist.n_un.n_name); + Local[i++]=maxlen; + Local[i++]=spnt->VMS_type; + Local[i++]=0xfb; + Local[i++]=strlen(sp->sy_nlist.n_un.n_name)+1; + Local[i++]=0x00; + Local[i++]=0x00; + Local[i++]=0x00; + Local[i++]=strlen(sp->sy_nlist.n_un.n_name); + pnt=sp->sy_nlist.n_un.n_name; + fix_name(pnt); /* if there are bad characters in name, convert them */ + while(*pnt!='\0') Local[i++]=*pnt++; + Local[i++]=0xfd; + Local[i++]=0x0f; + Local[i++]=0x00; + Local[i++]=0x03; + Local[i++]=0x01; + VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; + VMS_Set_Data(Text_Psect,Min_Offset,OBJ$C_DBG,1); + VMS_Set_Data(Text_Psect,Max_Offset,OBJ$C_DBG,1); + Local[i++]=0x03; + Local[i++]=sp->sy_nlist.n_value; + Local[i++]=0x00; + Local[i++]=0x00; + Local[i++]=0x00; + VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); + *pnt1=':'; + if(spnt->VMS_type == DBG$C_ADVANCED_TYPE) generate_suffix(spnt,0); +} + +/* this function examines a structure definition, checking all of the elements + * to make sure that all of them are fully defined. The only thing that we + * kick out are arrays of undefined structs, since we do not know how big + * they are. All others we can handle with a normal forward reference. + */ +static int forward_reference(char* pnt){ + int i; + struct VMS_DBG_Symbol * spnt; + struct VMS_DBG_Symbol * spnt1; + pnt = cvt_integer(pnt+1,&i); + if(*pnt == ';') return 0; /* no forward references */ + do{ + pnt=(char*) strchr(pnt,':'); + pnt = cvt_integer(pnt+1,&i); + spnt = find_symbol(i); + if(spnt == (struct VMS_DBG_Symbol*) NULL) return 0; + while((spnt->advanced == POINTER) || (spnt->advanced == ARRAY)){ + i=spnt->type2; + spnt1 = find_symbol(spnt->type2); + if((spnt->advanced == ARRAY) && + (spnt1 == (struct VMS_DBG_Symbol*) NULL))return 1; + if(spnt1 == (struct VMS_DBG_Symbol*) NULL) break; + spnt=spnt1; + }; + pnt = cvt_integer(pnt+1,&i); + pnt = cvt_integer(pnt+1,&i); + }while(*++pnt != ';'); + return 0; /* no forward refences found */ +} + +/* This routine parses the stabs directives to find any definitions of dbx type + * numbers. It makes a note of all of them, creating a structure element + * of VMS_DBG_Symbol that describes it. This also generates the info for the + * debugger that describes the struct/union/enum, so that further references + * to these data types will be by number + * We have to process pointers right away, since there can be references + * to them later in the same stabs directive. We cannot have forward + * references to pointers, (but we can have a forward reference to a pointer to + * a structure/enum/union) and this is why we process them immediately. + * After we process the pointer, then we search for defs that are nested even + * deeper. + */ +static int VMS_typedef_parse(char* str){ + char* pnt; + char* pnt1; + char* pnt2; + int i; + int dtype; + struct forward_ref * fpnt; + int i1,i2,i3; + int convert_integer; + struct VMS_DBG_Symbol* spnt; + struct VMS_DBG_Symbol* spnt1; +/* check for any nested def's */ + pnt=(char*)strchr(str+1,'='); + if((pnt != (char*) NULL) && (*(str+1) != '*')) + if(VMS_typedef_parse(pnt) == 1 ) return 1; +/* now find dbx_type of entry */ + pnt=str-1; + if(*pnt == 'c'){ /* check for static constants */ + *str = '\0'; /* for now we ignore them */ + return 0;}; + while((*pnt <= '9')&& (*pnt >= '0')) pnt--; + pnt++; /* and get back to the number */ + cvt_integer(pnt,&i1); + spnt = find_symbol(i1); +/* first we see if this has been defined already, due to a forward reference*/ + if(spnt == (struct VMS_DBG_Symbol*) NULL) { + if(VMS_Symbol_type_list==(struct VMS_DBG_Symbol*) NULL) + {spnt=(struct VMS_DBG_Symbol*) malloc(sizeof(struct VMS_DBG_Symbol)); + spnt->next = (struct VMS_DBG_Symbol*) NULL; + VMS_Symbol_type_list=spnt;} + else + {spnt=(struct VMS_DBG_Symbol*) malloc(sizeof(struct VMS_DBG_Symbol)); + spnt->next=VMS_Symbol_type_list; + VMS_Symbol_type_list = spnt;}; + spnt->dbx_type = i1; /* and save the type */ + }; +/* for structs and unions, do a partial parse, otherwise we sometimes get + * circular definitions that are impossible to resolve. We read enough info + * so that any reference to this type has enough info to be resolved + */ + pnt=str + 1; /* point to character past equal sign */ + if((*pnt == 'u') || (*pnt == 's')){ + }; + if((*pnt <= '9') && (*pnt >= '0')){ + if(type_check("void")){ /* this is the void symbol */ + *str='\0'; + spnt->advanced = VOID; + return 0;}; + printf("gcc-as warning(debugger output):"); + printf(" %d is an unknown untyped variable.\n",spnt->dbx_type); + return 1; /* do not know what this is */ + }; +/* now define this module*/ + pnt=str + 1; /* point to character past equal sign */ + switch (*pnt){ + case 'r': + spnt->advanced= BASIC; + if(type_check("int")) { + spnt->VMS_type=DBG$C_SLINT; spnt->data_size=4;} + else if(type_check("long int")) { + spnt->VMS_type=DBG$C_SLINT; spnt->data_size=4;} + else if(type_check("unsigned int")) { + spnt->VMS_type=DBG$C_ULINT; spnt->data_size = 4;} + else if(type_check("long unsigned int")) { + spnt->VMS_type=DBG$C_ULINT; spnt->data_size = 4;} + else if(type_check("short int")) { + spnt->VMS_type=DBG$C_SSINT; spnt->data_size = 2;} + else if(type_check("short unsigned int")) { + spnt->VMS_type=DBG$C_USINT; spnt->data_size = 2;} + else if(type_check("char")) { + spnt->VMS_type=DBG$C_SCHAR; spnt->data_size = 1;} + else if(type_check("signed char")) { + spnt->VMS_type=DBG$C_SCHAR; spnt->data_size = 1;} + else if(type_check("unsigned char")) { + spnt->VMS_type=DBG$C_UCHAR; spnt->data_size = 1;} + else if(type_check("float")) { + spnt->VMS_type=DBG$C_REAL4; spnt->data_size = 4;} + else if(type_check("double")) { + spnt->VMS_type=DBG$C_REAL8; spnt->data_size = 8;} + pnt1=(char*) strchr(str,';')+1; + break; + case 's': + case 'u': + if(*pnt == 's') spnt->advanced= STRUCT; + else spnt->advanced= UNION; + spnt->VMS_type = DBG$C_ADVANCED_TYPE; + pnt1 = cvt_integer(pnt+1,&spnt->data_size); + if(forward_reference(pnt)) { + spnt->struc_numb = -1; + return 1; + } + spnt->struc_numb = ++structure_count; + pnt1--; + pnt=get_struct_name(str); + VMS_Def_Struct(spnt->struc_numb); + fpnt = f_ref_root; + while(fpnt != (struct forward_ref*) NULL){ + if(fpnt->dbx_type == spnt->dbx_type) { + fpnt->resolved = 'Y'; + VMS_Set_Struct(fpnt->struc_numb); + VMS_Store_Struct(spnt->struc_numb);}; + fpnt = fpnt->next;}; + VMS_Set_Struct(spnt->struc_numb); + i=0; + Local[i++] = 11+strlen(pnt); + Local[i++] = DBG$C_STRUCT_START; + Local[i++] = 0x80; + for(i1=0;i1<4;i1++) Local[i++] = 0x00; + Local[i++] = strlen(pnt); + pnt2=pnt; + while(*pnt2 != '\0') Local[i++] = *pnt2++; + i2=spnt->data_size * 8; /* number of bits */ + pnt2=(char*) &i2; + for(i1=0;i1<4;i1++) Local[i++] = *pnt2++; + VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; + if(pnt != symbol_name) { + pnt += strlen(pnt); + *pnt=':';}; /* replace colon for later */ + while(*++pnt1 != ';'){ + pnt=(char*) strchr(pnt1,':'); + *pnt='\0'; + pnt2=pnt1; + pnt1 = cvt_integer(pnt+1,&dtype); + pnt1 = cvt_integer(pnt1+1,&i2); + pnt1 = cvt_integer(pnt1+1,&i3); + if((dtype == 1) && (i3 != 32)) { /* bitfield */ + Apoint = 0; + push(19+strlen(pnt2),1); + push(0xfa22,2); + push(1+strlen(pnt2),4); + push(strlen(pnt2),1); + while(*pnt2 != '\0') push(*pnt2++,1); + push(i3,2); /* size of bitfield */ + push(0x0d22,2); + push(0x00,4); + push(i2,4); /* start position */ + VMS_Store_Immediate_Data(Asuffix,Apoint,OBJ$C_DBG); + Apoint=0; + }else{ + Local[i++] = 7+strlen(pnt2); + spnt1 = find_symbol(dtype); + /* check if this is a forward reference */ + if(spnt1 != (struct VMS_DBG_Symbol*) NULL) + Local[i++] = spnt1->VMS_type; + else + Local[i++] = DBG$C_ADVANCED_TYPE; + Local[i++] = DBG$C_STRUCT_ITEM; + pnt=(char*) &i2; + for(i1=0;i1<4;i1++) Local[i++] = *pnt++; + Local[i++] = strlen(pnt2); + while(*pnt2 != '\0') Local[i++] = *pnt2++; + VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; + if(spnt1 == (struct VMS_DBG_Symbol*) NULL) + generate_suffix(spnt1,dtype); + else if(spnt1->VMS_type == DBG$C_ADVANCED_TYPE) + generate_suffix(spnt1,0); + }; + }; + pnt1++; + Local[i++] = 0x01; /* length byte */ + Local[i++] = DBG$C_STRUCT_END; + VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; + break; + case 'e': + spnt->advanced= ENUM; + spnt->VMS_type = DBG$C_ADVANCED_TYPE; + spnt->struc_numb = ++structure_count; + spnt->data_size=4; + VMS_Def_Struct(spnt->struc_numb); + fpnt = f_ref_root; + while(fpnt != (struct forward_ref*) NULL){ + if(fpnt->dbx_type == spnt->dbx_type) { + fpnt->resolved = 'Y'; + VMS_Set_Struct(fpnt->struc_numb); + VMS_Store_Struct(spnt->struc_numb);}; + fpnt = fpnt->next;}; + VMS_Set_Struct(spnt->struc_numb); + i=0; + Local[i++] = 3+strlen(symbol_name); + Local[i++] = DBG$C_ENUM_START; + Local[i++] = 0x20; + Local[i++] = strlen(symbol_name); + pnt2=symbol_name; + while(*pnt2 != '\0') Local[i++] = *pnt2++; + VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; + while(*++pnt != ';') { + pnt1=(char*) strchr(pnt,':'); + *pnt1++='\0'; + pnt1 = cvt_integer(pnt1,&i1); + Local[i++] = 7+strlen(pnt); + Local[i++] = DBG$C_ENUM_ITEM; + Local[i++] = 0x00; + pnt2=(char*) &i1; + for(i2=0;i2<4;i2++) Local[i++] = *pnt2++; + Local[i++] = strlen(pnt); + pnt2=pnt; + while(*pnt != '\0') Local[i++] = *pnt++; + VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; + pnt= pnt1; /* Skip final semicolon */ + }; + Local[i++] = 0x01; /* len byte */ + Local[i++] = DBG$C_ENUM_END; + VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; + pnt1=pnt + 1; + break; + case 'a': + spnt->advanced= ARRAY; + spnt->VMS_type = DBG$C_ADVANCED_TYPE; + pnt=(char*)strchr(pnt,';'); if (pnt == (char*) NULL) return 1; + pnt1 = cvt_integer(pnt+1,&spnt->index_min); + pnt1 = cvt_integer(pnt1+1,&spnt->index_max); + pnt1 = cvt_integer(pnt1+1,&spnt->type2); + break; + case 'f': + spnt->advanced= FUNCTION; + spnt->VMS_type = DBG$C_FUNCTION_ADDR; + /* this masquerades as a basic type*/ + spnt->data_size=4; + pnt1 = cvt_integer(pnt+1,&spnt->type2); + break; + case '*': + spnt->advanced= POINTER; + spnt->VMS_type = DBG$C_ADVANCED_TYPE; + spnt->data_size=4; + pnt1 = cvt_integer(pnt+1,&spnt->type2); + pnt=(char*)strchr(str+1,'='); + if((pnt != (char*) NULL)) + if(VMS_typedef_parse(pnt) == 1 ) return 1; + break; + default: + spnt->advanced= UNKNOWN; + spnt->VMS_type = 0; + printf("gcc-as warning(debugger output):"); + printf(" %d is an unknown type of variable.\n",spnt->dbx_type); + return 1; /* unable to decipher */ + }; +/* this removes the evidence of the definition so that the outer levels of +parsing do not have to worry about it */ + pnt=str; + while (*pnt1 != '\0') *pnt++ = *pnt1++; + *pnt = '\0'; + return 0; +} + + +/* + * This is the root routine that parses the stabs entries for definitions. + * it calls VMS_typedef_parse, which can in turn call itself. + * We need to be careful, since sometimes there are forward references to + * other symbol types, and these cannot be resolved until we have completed + * the parse. + */ +int VMS_LSYM_Parse(){ + char *pnt; + char *pnt1; + char *pnt2; + char *str; + char fixit[10]; + int incomplete,i,pass,incom1; + struct VMS_DBG_Symbol* spnt; + struct VMS_Symbol * vsp; + struct forward_ref * fpnt; + symbolS * sp; + pass=0; + incomplete = 0; + do{ + incom1=incomplete; + incomplete = 0; + for(sp = symbol_rootP; sp; sp = symbol_next(sp)) { + /* + * Deal with STAB symbols + */ + if ((sp->sy_nlist.n_type & N_STAB) != 0) { + /* + * Dispatch on STAB type + */ + switch((unsigned char)sp->sy_nlist.n_type) { + case N_GSYM: + case N_LCSYM: + case N_STSYM: + case N_PSYM: + case N_RSYM: + case N_LSYM: + case N_FUN: /*sometimes these contain typedefs*/ + str=sp->sy_nlist.n_un.n_name; + symbol_name = str; + pnt=(char*)strchr(str,':'); + if(pnt== (char*) NULL) break; + *pnt='\0'; + pnt1=pnt+1; + pnt2=(char*)strchr(pnt1,'='); + if(pnt2 == (char*) NULL){ + *pnt=':'; /* replace colon */ + break;}; /* no symbol here */ + incomplete += VMS_typedef_parse(pnt2); + *pnt=':'; /* put back colon so variable def code finds dbx_type*/ + break; + } /*switch*/ + } /* if */ + } /*for*/ + pass++; + } while((incomplete != 0) && (incomplete != incom1 )); + /* repeat until all refs resolved if possible */ +/* if(pass > 1) printf(" Required %d passes\n",pass);*/ + if(incomplete != 0){ + printf("gcc-as warning(debugger output):"); + printf("Unable to resolve %d circular references.\n",incomplete); + }; + fpnt = f_ref_root; + symbol_name="\0"; + while(fpnt != (struct forward_ref*) NULL){ + if(fpnt->resolved != 'Y') { + if( find_symbol(fpnt->dbx_type) != + (struct VMS_DBG_Symbol*) NULL){ + printf("gcc-as warning(debugger output):"); + printf("Forward reference error, dbx type %d\n", + fpnt->dbx_type); + break;}; + fixit[0]=0; + sprintf(&fixit[1],"%d=s4;",fpnt->dbx_type); + pnt2=(char*)strchr(&fixit[1],'='); + VMS_typedef_parse(pnt2); + }; + fpnt = fpnt->next;}; +} + +static symbolS* Current_Routine; +static int Text_Psect; + +static Define_Local_Symbols(symbolS* s1,symbolS* s2){ + symbolS * symbolP1; + for(symbolP1 = symbol_next(s1); symbolP1 != s2; symbolP1 = symbol_next(symbolP1)) { + if (symbolP1 == (symbolS *)NULL) return; + if (symbolP1->sy_nlist.n_type == N_FUN) return; + /* + * Deal with STAB symbols + */ + if ((symbolP1->sy_nlist.n_type & N_STAB) != 0) { + /* + * Dispatch on STAB type + */ + switch((unsigned char)symbolP1->sy_nlist.n_type) { + case N_LSYM: + case N_PSYM: + VMS_local_stab_Parse(symbolP1); + break; + case N_RSYM: + VMS_RSYM_Parse(symbolP1,Current_Routine,Text_Psect); + break; + } /*switch*/ + } /* if */ + } /* for */ +} + +static symbolS* Define_Routine(symbolS* symbolP,int Level){ + symbolS * sstart; + symbolS * symbolP1; + char str[10]; + char * pnt; + int rcount = 0; + int Offset; + sstart = symbolP; + for(symbolP1 = symbol_next(symbolP); symbolP1; symbolP1 = symbol_next(symbolP1)) { + if (symbolP1->sy_nlist.n_type == N_FUN) break; + /* + * Deal with STAB symbols + */ + if ((symbolP1->sy_nlist.n_type & N_STAB) != 0) { + /* + * Dispatch on STAB type + */ + if((unsigned char)symbolP1->sy_nlist.n_type == N_FUN) break; + switch((unsigned char)symbolP1->sy_nlist.n_type) { + case N_LBRAC: + if(Level != 0) { + pnt = str +sprintf(str,"$%d",rcount++); + *pnt = '\0'; + VMS_TBT_Block_Begin(symbolP1,Text_Psect,str); + }; + Offset = symbolP1->sy_nlist.n_value; + Define_Local_Symbols(sstart,symbolP1); + symbolP1 = + Define_Routine(symbolP1,Level+1); + if(Level != 0) + VMS_TBT_Block_End(symbolP1->sy_nlist.n_value - + Offset); + sstart=symbolP1; + break; + case N_RBRAC: + return symbolP1; + } /*switch*/ + } /* if */ + } /* for */ + /* we end up here if there were no brackets in this function. Define +everything */ + Define_Local_Symbols(sstart,(symbolS *) 0); +} + +VMS_DBG_Define_Routine(symbolS* symbolP,symbolS* Curr_Routine,int Txt_Psect){ + Current_Routine = Curr_Routine; + Text_Psect = Txt_Psect; + Define_Routine(symbolP,0); +} diff --git a/gas/config/vms/vms.c b/gas/config/vms/vms.c new file mode 100644 index 0000000..cd3bb59 --- /dev/null +++ b/gas/config/vms/vms.c @@ -0,0 +1,3741 @@ +/* vms.c -- Write out a VAX/VMS object file + Copyright (C) 1987, 1988 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can 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. */ + +/* Written by David L. Kashtan */ +#include <ctype.h> +#include <stdio.h> + +#include "as.h" +#include "subsegs.h" +#include "obstack.h" +#include "struc-symbol.h" +#include "write.h" +#include "symbols.h" + +#ifdef VMS /* THIS MODULE IS FOR VMS ONLY */ + +#include <stab.h> +#include "objrecdef.h" /* Define VMS Object record lang. */ +#include <vms/fabdef.h> /* Define File Access Block */ +#include <vms/namdef.h> /* Define NAM Block */ +#include <vms/xabdef.h> /* Define XAB */ +#include <vms/xabdatdef.h> /* Define Date XAB */ +#include <vms/xabfhcdef.h> /* Define File Header XAB */ + +const pseudo_typeS obj_pseudo_table[] = { + { "const", s_const, 0 }, + +}; /* obj_pseudo_table */ + +/* + * Version string of the compiler that produced the code we are + * assembling. (And this assembler, if we do not have compiler info.) + */ +extern char version_string[]; +char *compiler_version_string; + +extern char *myname; +static symbolS *Entry_Point_Symbol = 0; /* Pointer to "_main" */ + +/* + * We augment the "gas" symbol structure with this + */ +struct VMS_Symbol { + struct VMS_Symbol *Next; + struct symbol *Symbol; + int Size; + int Psect_Index; + int Psect_Offset; + }; +struct VMS_Symbol *VMS_Symbols = 0; + +/* we need this to keep track of the various input files, so that we can + * give the debugger the correct source line + */ + +struct input_file{ + struct input_file* next; + struct input_file* same_file_fpnt; + int file_number; + int max_line; + int min_line; + int offset; + char flag; + char * name; + symbolS * spnt; + }; + +static struct input_file * file_root = (struct input_file*)NULL; + +struct input_file * find_file(symbolS *); + + +/* + * If the procedure "main()" exists we have to add the instruction + * "jsb c$main_args" at the beginning to be compatible with VAX-11 "C". + */ +VMS_Check_For_Main() +{ + register symbolS *symbolP; +#ifdef HACK_DEC_C_STARTUP /* JF */ + register struct frchain *frchainP; + register fragS *fragP; + register fragS **prev_fragPP; + register struct fix *fixP; + register fragS *New_Frag; + int i; +#endif HACK_DEC_C_STARTUP + + symbolP = (struct symbol *)symbol_find("_main"); + if (symbolP && (symbolP->sy_nlist.n_type == (N_TEXT | N_EXT))) { +#ifdef HACK_DEC_C_STARTUP + if( !flagseen['+']) { +#endif + /* + * Remember the entry point symbol + */ + Entry_Point_Symbol = symbolP; +#ifdef HACK_DEC_C_STARTUP + } else { + /* + * Scan all the fragment chains for the one with "_main" + * (Actually we know the fragment from the symbol, but we need + * the previous fragment so we can change its pointer) + */ + frchainP = frchain_root; + while(frchainP) { + /* + * Scan all the fragments in this chain, remembering + * the "previous fragment" + */ + prev_fragPP = &frchainP->frch_root; + fragP = frchainP->frch_root; + while(fragP && (fragP != frchainP->frch_last)) { + /* + * Is this the fragment? + */ + if (fragP == symbolP->sy_frag) { + /* + * Yes: Modify the fragment by replacing + * it with a new fragment. + */ + New_Frag = (fragS *) + xmalloc(sizeof(*New_Frag) + + fragP->fr_fix + + fragP->fr_var + + 5); + /* + * The fragments are the same except + * that the "fixed" area is larger + */ + *New_Frag = *fragP; + New_Frag->fr_fix += 6; + /* + * Copy the literal data opening a hole + * 2 bytes after "_main" (i.e. just after + * the entry mask). Into which we place + * the JSB instruction. + */ + New_Frag->fr_literal[0] = fragP->fr_literal[0]; + New_Frag->fr_literal[1] = fragP->fr_literal[1]; + New_Frag->fr_literal[2] = 0x16; /* Jsb */ + New_Frag->fr_literal[3] = 0xef; + New_Frag->fr_literal[4] = 0; + New_Frag->fr_literal[5] = 0; + New_Frag->fr_literal[6] = 0; + New_Frag->fr_literal[7] = 0; + for(i = 2; i < fragP->fr_fix + fragP->fr_var; i++) + New_Frag->fr_literal[i+6] = + fragP->fr_literal[i]; + /* + * Now replace the old fragment with the + * newly generated one. + */ + *prev_fragPP = New_Frag; + /* + * Remember the entry point symbol + */ + Entry_Point_Symbol = symbolP; + /* + * Scan the text area fixup structures + * as offsets in the fragment may have + * changed + */ + for(fixP = text_fix_root; fixP; fixP = fixP->fx_next) { + /* + * Look for references to this + * fragment. + */ + if (fixP->fx_frag == fragP) { + /* + * Change the fragment + * pointer + */ + fixP->fx_frag = New_Frag; + /* + * If the offset is after + * the entry mask we need + * to account for the JSB + * instruction we just + * inserted. + */ + if (fixP->fx_where >= 2) + fixP->fx_where += 6; + } + } + /* + * Scan the symbols as offsets in the + * fragment may have changed + */ + for(symbolP = symbol_rootP; + symbolP; + symbolP = symbol_next(symbolP)) { + /* + * Look for references to this + * fragment. + */ + if (symbolP->sy_frag == fragP) { + /* + * Change the fragment + * pointer + */ + symbolP->sy_frag = New_Frag; + /* + * If the offset is after + * the entry mask we need + * to account for the JSB + * instruction we just + * inserted. + */ + if (symbolP->sy_nlist.n_value >= 2) + symbolP->sy_nlist.n_value += 6; + } + } + /* + * Make a symbol reference to + * "_c$main_args" so we can get + * its address inserted into the + * JSB instruction. + */ + symbolP = (symbolS *)xmalloc(sizeof(*symbolP)); + symbolP->sy_nlist.n_un.n_name = "_c$main_args"; + symbolP->sy_nlist.n_type = N_UNDF; + symbolP->sy_nlist.n_other = 0; + symbolP->sy_nlist.n_desc = 0; + symbolP->sy_nlist.n_value = 0; + symbolP->sy_name_offset = 0; + symbolP->sy_number = 0; + symbolP->sy_frag = New_Frag; + symbolP->sy_forward = 0; + /* this actually inserts at the beginning of the list */ + symbol_append(symbol_rootP, symbolP, &symbol_rootP, &symbol_lastP); + + symbol_rootP = symbolP; + /* + * Generate a text fixup structure + * to get "_c$main_args" stored into the + * JSB instruction. + */ + fixP = (struct fix *)xmalloc(sizeof(*fixP)); + fixP->fx_frag = New_Frag; + fixP->fx_where = 4; + fixP->fx_addsy = symbolP; + fixP->fx_subsy = 0; + fixP->fx_offset = 0; + fixP->fx_size = sizeof(long); + fixP->fx_pcrel = 1; + fixP->fx_next = text_fix_root; + text_fix_root = fixP; + /* + * Now make sure we exit from the loop + */ + frchainP = 0; + break; + } + /* + * Try the next fragment + */ + prev_fragPP = &fragP->fr_next; + fragP = fragP->fr_next; + } + /* + * Try the next fragment chain + */ + if (frchainP) frchainP=frchainP->frch_next; + } + } +#endif /* HACK_DEC_C_STARTUP */ + } +} + +/* + * Write a VAX/VMS object file (everything else has been done!) + */ +VMS_write_object_file(text_siz, data_siz, text_frag_root, data_frag_root) +unsigned text_siz; +unsigned data_siz; +struct frag *text_frag_root; +struct frag *data_frag_root; +{ + register fragS * fragP; + register symbolS * symbolP; + register symbolS * sp; + register struct fix * fixP; + register struct VMS_Symbol * vsp; + int Local_Initialized_Data_Size = 0; + int Psect_Number = 0; /* Psect Index Number */ + int Text_Psect = -1; /* Text Psect Index */ + int Data_Psect = -2; /* Data Psect Index JF: Was -1 */ + int Bss_Psect = -3; /* Bss Psect Index JF: Was -1 */ + + /* + * Create the VMS object file + */ + Create_VMS_Object_File(); + /* + * Write the module header records + */ + Write_VMS_MHD_Records(); + + /* + * Generate the VMS object file records + * 1st GSD then TIR records + */ + + /******* Global Symbol Dictionary *******/ + /* + * Define the Text Psect + */ + if (text_siz > 0) { + Text_Psect = Psect_Number++; + VMS_Psect_Spec("$code",text_siz,"TEXT"); + } + /* + * Define the BSS Psect + */ + if (local_bss_counter > 0) { + Bss_Psect = Psect_Number++; + VMS_Psect_Spec("$uninitialized_data",local_bss_counter,"DATA"); + } + /* + * Now scan the symbols and emit the appropriate GSD records + */ + for (sp = symbol_rootP; sp; sp = symbol_next(sp)) { + /* + * Dispatch on symbol type + */ + switch(sp->sy_type) { + /* + * Global uninitialized data + */ + case N_UNDF | N_EXT: + /* + * Make a VMS data symbol entry + */ + vsp = (struct VMS_Symbol *) + xmalloc(sizeof(*vsp)); + vsp->Symbol = sp; + vsp->Size = sp->sy_nlist.n_value; + vsp->Psect_Index = Psect_Number++; + vsp->Psect_Offset = 0; + vsp->Next = VMS_Symbols; + VMS_Symbols = vsp; + sp->sy_number = (int)vsp; + /* + * Make the psect for this data + */ + if(sp->sy_nlist.n_other) + VMS_Psect_Spec(sp->sy_nlist.n_un.n_name, + vsp->Size, + "CONST"); + else + VMS_Psect_Spec(sp->sy_nlist.n_un.n_name, + vsp->Size, + "COMMON"); +#ifdef NOT_VAX_11_C_COMPATIBLE + /* + * Place a global symbol at the + * beginning of the Psect + */ + VMS_Global_Symbol_Spec(sp->sy_nlist.n_un.n_name, + vsp->Psect_Index, + 0, + 1); +#endif NOT_VAX_11_C_COMPATIBLE + break; + /* + * Local uninitialized data + */ + case N_BSS: + /* + * Make a VMS data symbol entry + */ + vsp = (struct VMS_Symbol *) + xmalloc(sizeof(*vsp)); + vsp->Symbol = sp; + vsp->Size = 0; + vsp->Psect_Index = Bss_Psect; + vsp->Psect_Offset = + sp->sy_nlist.n_value - + bss_address_frag . fr_address; + vsp->Next = VMS_Symbols; + VMS_Symbols = vsp; + sp->sy_number = (int)vsp; + break; + /* + * Global initialized data + */ + case N_DATA | N_EXT: + /* + * Make a VMS data symbol entry + */ + vsp = (struct VMS_Symbol *) + xmalloc(sizeof(*vsp)); + vsp->Symbol = sp; + vsp->Size = VMS_Initialized_Data_Size(sp, + text_siz + data_siz); + vsp->Psect_Index = Psect_Number++; + vsp->Psect_Offset = 0; + vsp->Next = VMS_Symbols; + VMS_Symbols = vsp; + sp->sy_number = (int)vsp; + /* + * Make its psect + */ + if(sp->sy_nlist.n_other) + VMS_Psect_Spec(sp->sy_nlist.n_un.n_name, + vsp->Size, + "CONST"); + else + VMS_Psect_Spec(sp->sy_nlist.n_un.n_name, + vsp->Size, + "COMMON"); +#ifdef NOT_VAX_11_C_COMPATIBLE + /* + * Place a global symbol at the + * beginning of the Psect + */ + VMS_Global_Symbol_Spec(sp->sy_nlist.n_un.n_name, + vsp->Psect_Index, + 0, + 1); +#endif NOT_VAX_11_C_COMPATIBLE + break; + /* + * Local initialized data + */ + case N_DATA: + /* + * Make a VMS data symbol entry + */ + vsp = (struct VMS_Symbol *) + xmalloc(sizeof(*vsp)); + vsp->Symbol = sp; + vsp->Size = + VMS_Initialized_Data_Size(sp, + text_siz + data_siz); + vsp->Psect_Index = Data_Psect; + vsp->Psect_Offset = + Local_Initialized_Data_Size; + Local_Initialized_Data_Size += vsp->Size; + vsp->Next = VMS_Symbols; + VMS_Symbols = vsp; + sp->sy_number = (int)vsp; + break; + /* + * Global Text definition + */ + case N_TEXT | N_EXT: { + unsigned short Entry_Mask; + + /* + * Get the entry mask + */ + fragP = sp->sy_frag; + Entry_Mask = (fragP->fr_literal[0] & 0xff) + + ((fragP->fr_literal[1] & 0xff) + << 8); + /* + * Define the Procedure entry pt. + */ + VMS_Procedure_Entry_Pt(sp->sy_nlist.n_un.n_name, + Text_Psect, + sp->sy_nlist.n_value, + Entry_Mask); + break; + } + /* + * Local Text definition + */ + case N_TEXT: + /* + * Make a VMS data symbol entry + */ + if(Text_Psect != -1) { + vsp = (struct VMS_Symbol *) + xmalloc(sizeof(*vsp)); + vsp->Symbol = sp; + vsp->Size = 0; + vsp->Psect_Index = Text_Psect; + vsp->Psect_Offset = sp->sy_nlist.n_value; + vsp->Next = VMS_Symbols; + VMS_Symbols = vsp; + sp->sy_number = (int)vsp; + } + break; + /* + * Global Reference + */ + case N_UNDF: + /* + * Make a GSD global symbol reference + * record. + */ + VMS_Global_Symbol_Spec(sp->sy_nlist.n_un.n_name, + 0, + 0, + 0); + break; + /* + * Anything else + */ + default: + /* + * Ignore STAB symbols + * Including .stabs emitted by g++ + */ + if ((sp->sy_type & N_STAB) != 0 || sp->sy_nlist.n_type==22) + break; + /* + * Error + */ + if(sp->sy_nlist.n_type !=22) + printf(" ERROR, unknown type (%d)\n", + sp->sy_nlist.n_type); + break; + } + } + /* + * Define the Data Psect + */ + if ((data_siz > 0) && (Local_Initialized_Data_Size > 0)) { + /* + * Do it + */ + Data_Psect = Psect_Number++; + VMS_Psect_Spec("$data", + Local_Initialized_Data_Size, + "DATA"); + /* + * Scan the VMS symbols and fill in the data psect + */ + for (vsp = VMS_Symbols; vsp; vsp = vsp->Next) { + /* + * Only look for undefined psects + */ + if (vsp->Psect_Index < 0) { + /* + * And only initialized data + */ + if (vsp->Symbol->sy_nlist.n_type == N_DATA) + vsp->Psect_Index = Data_Psect; + } + } + } + + /******* Text Information and Relocation Records *******/ + /* + * Write the text segment data + */ + if (text_siz > 0) { + /* + * Scan the text fragments + */ + for(fragP = text_frag_root; fragP; fragP = fragP->fr_next) { + /* + * Stop if we get to the data fragments + */ + if (fragP == data_frag_root) break; + /* + * Ignore fragments with no data + */ + if ((fragP->fr_fix == 0) && (fragP->fr_var == 0)) + continue; + /* + * Go the the appropriate offset in the + * Text Psect. + */ + VMS_Set_Psect(Text_Psect,fragP->fr_address,OBJ$C_TIR); + /* + * Store the "fixed" part + */ + if (fragP->fr_fix) + VMS_Store_Immediate_Data(fragP->fr_literal, + fragP->fr_fix, + OBJ$C_TIR); + /* + * Store the "variable" part + */ + if (fragP->fr_var && fragP->fr_offset) + VMS_Store_Repeated_Data(fragP->fr_offset, + fragP->fr_literal+ + fragP->fr_fix, + fragP->fr_var, + OBJ$C_TIR); + } + /* + * Now we go through the text segment fixups and + * generate TIR records to fix up addresses within + * the Text Psect + */ + for(fixP = text_fix_root; fixP; fixP = fixP->fx_next) { + /* + * We DO handle the case of "Symbol - Symbol" as + * long as it is in the same segment. + */ + if (fixP->fx_subsy && fixP->fx_addsy) { + int i; + + /* + * They need to be in the same segment + */ + if (fixP->fx_subsy->sy_type != + fixP->fx_addsy->sy_type) + error("Fixup data addsy and subsy didn't have the same type"); + /* + * And they need to be in one that we + * can check the psect on + */ + if (((fixP->fx_addsy->sy_type & ~N_EXT) != N_DATA) && + ((fixP->fx_addsy->sy_type & ~N_EXT) != N_TEXT)) + error("Fixup data addsy and subsy didn't have an appropriate type"); + /* + * This had better not be PC relative! + */ + if (fixP->fx_pcrel) + error("Fixup data was erroneously \"pcrel\""); + /* + * Subtract their values to get the + * difference. + */ + i = fixP->fx_addsy->sy_value - + fixP->fx_subsy->sy_value; + /* + * Now generate the fixup object records + * Set the psect and store the data + */ + VMS_Set_Psect(Text_Psect, + fixP->fx_where + + fixP->fx_frag->fr_address, + OBJ$C_TIR); + VMS_Store_Immediate_Data(&i, + fixP->fx_size, + OBJ$C_TIR); + /* + * Done + */ + continue; + } + /* + * Size will HAVE to be "long" + */ + if (fixP->fx_size != sizeof(long)) + error("Fixup datum was not a longword"); + /* + * Symbol must be "added" (if it is ever + * subtracted we can + * fix this assumption) + */ + if (fixP->fx_addsy == 0) + error("Fixup datum was not \"fixP->fx_addsy\""); + /* + * Store the symbol value in a PIC fashion + */ + VMS_Store_PIC_Symbol_Reference(fixP->fx_addsy, + fixP->fx_offset, + fixP->fx_pcrel, + Text_Psect, + fixP->fx_where + + fixP->fx_frag->fr_address, + OBJ$C_TIR); + /* + * Check for indirect address reference, + * which has to be fixed up (as the linker + * will screw it up with TIR$C_STO_PICR). + */ + if (fixP->fx_pcrel) + VMS_Fix_Indirect_Reference(Text_Psect, + fixP->fx_where + + fixP->fx_frag->fr_address, + fixP->fx_frag, + text_frag_root); + } + } + /* + * Store the Data segment: + * + * Since this is REALLY hard to do any other way, + * we actually manufacture the data segment and + * the store the appropriate values out of it. + */ + if (data_siz > 0) { + char *Data_Segment; + + /* + * Allocate the data segment + */ + Data_Segment = (char *)xmalloc(data_siz); + /* + * Run through the data fragments, filling in the segment + */ + for(fragP = data_frag_root; fragP; fragP = fragP->fr_next) { + register long int count; + register char * fill_literal; + register long int fill_size; + int i; + + i = fragP->fr_address - text_siz; + if (fragP->fr_fix) + bcopy(fragP->fr_literal, + Data_Segment + i, + fragP->fr_fix); + i += fragP->fr_fix; + + fill_literal= fragP -> fr_literal + fragP -> fr_fix; + fill_size = fragP -> fr_var; + for (count = fragP -> fr_offset; count; count --) { + if (fill_size) + bcopy(fill_literal, + Data_Segment + i, + fill_size); + i += fill_size; + } + } + /* + * Now we can run through all the data symbols + * and store the data + */ + for(vsp = VMS_Symbols; vsp; vsp = vsp->Next) { + /* + * Ignore anything other than data symbols + */ + if ((vsp->Symbol->sy_nlist.n_type & ~N_EXT) != N_DATA) + continue; + /* + * Set the Psect + Offset + */ + VMS_Set_Psect(vsp->Psect_Index, + vsp->Psect_Offset, + OBJ$C_TIR); + /* + * Store the data + */ + VMS_Store_Immediate_Data(Data_Segment + + vsp->Symbol->sy_nlist.n_value - + text_siz, + vsp->Size, + OBJ$C_TIR); + } + /* + * Now we go through the data segment fixups and + * generate TIR records to fix up addresses within + * the Data Psects + */ + for(fixP = data_fix_root; fixP; fixP = fixP->fx_next) { + /* + * Find the symbol for the containing datum + */ + for(vsp = VMS_Symbols; vsp; vsp = vsp->Next) { + /* + * Only bother with Data symbols + */ + sp = vsp->Symbol; + if ((sp->sy_nlist.n_type & ~N_EXT) != N_DATA) + continue; + /* + * Ignore symbol if After fixup + */ + if (sp->sy_nlist.n_value > + (fixP->fx_where + + fixP->fx_frag->fr_address)) + continue; + /* + * See if the datum is here + */ + if ((sp->sy_nlist.n_value + vsp->Size) <= + (fixP->fx_where + + fixP->fx_frag->fr_address)) + continue; + /* + * We DO handle the case of "Symbol - Symbol" as + * long as it is in the same segment. + */ + if (fixP->fx_subsy && fixP->fx_addsy) { + int i; + + /* + * They need to be in the same segment + */ + if (fixP->fx_subsy->sy_type != + fixP->fx_addsy->sy_type) + error("Fixup data addsy and subsy didn't have the same type"); + /* + * And they need to be in one that we + * can check the psect on + */ + if (((fixP->fx_addsy->sy_type & ~N_EXT) != N_DATA) && + ((fixP->fx_addsy->sy_type & ~N_EXT) != N_TEXT)) + error("Fixup data addsy and subsy didn't have an appropriate type"); + /* + * This had better not be PC relative! + */ + if (fixP->fx_pcrel) + error("Fixup data was erroneously \"pcrel\""); + /* + * Subtract their values to get the + * difference. + */ + i = fixP->fx_addsy->sy_value - + fixP->fx_subsy->sy_value; + /* + * Now generate the fixup object records + * Set the psect and store the data + */ + VMS_Set_Psect(vsp->Psect_Index, + fixP->fx_frag->fr_address + + fixP->fx_where - + vsp->Symbol->sy_value + + vsp->Psect_Offset, + OBJ$C_TIR); + VMS_Store_Immediate_Data(&i, + fixP->fx_size, + OBJ$C_TIR); + /* + * Done + */ + break; + } + /* + * Size will HAVE to be "long" + */ + if (fixP->fx_size != sizeof(long)) + error("Fixup datum was not a longword"); + /* + * Symbol must be "added" (if it is ever + * subtracted we can + * fix this assumption) + */ + if (fixP->fx_addsy == 0) + error("Fixup datum was not \"fixP->fx_addsy\""); + /* + * Store the symbol value in a PIC fashion + */ + VMS_Store_PIC_Symbol_Reference( + fixP->fx_addsy, + fixP->fx_offset, + fixP->fx_pcrel, + vsp->Psect_Index, + fixP->fx_frag->fr_address + + fixP->fx_where - + vsp->Symbol->sy_value + + vsp->Psect_Offset, + OBJ$C_TIR); + /* + * Done + */ + break; + } + + } + } + + /* + * Write the Traceback Begin Module record + */ + VMS_TBT_Module_Begin(); + /* + * Scan the symbols and write out the routines + * (this makes the assumption that symbols are in + * order of ascending text segment offset) + */ + { + struct symbol *Current_Routine = 0; + int Current_Line_Number = 0; + int Current_Offset = -1; + struct input_file * Current_File; + +/* Output debugging info for global variables and static variables that are not + * specific to one routine. We also need to examine all stabs directives, to + * find the definitions to all of the advanced data types, and this is done by + * VMS_LSYM_Parse. This needs to be done before any definitions are output to + * the object file, since there can be forward references in the stabs + * directives. When through with parsing, the text of the stabs directive + * is altered, with the definitions removed, so that later passes will see + * directives as they would be written if the type were already defined. + * + * We also look for files and include files, and make a list of them. We + * examine the source file numbers to establish the actual lines that code was + * generated from, and then generate offsets. + */ + VMS_LSYM_Parse(); + for(symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + /* + * Deal with STAB symbols + */ + if ((symbolP->sy_nlist.n_type & N_STAB) != 0) { + /* + * Dispatch on STAB type + */ + switch((unsigned char)symbolP->sy_nlist.n_type) { + case N_SLINE: + if(symbolP->sy_nlist.n_desc > Current_File->max_line) + Current_File->max_line = symbolP->sy_nlist.n_desc; + if(symbolP->sy_nlist.n_desc < Current_File->min_line) + Current_File->min_line = symbolP->sy_nlist.n_desc; + break; + case N_SO: + Current_File =find_file(symbolP); + Current_File->flag = 1; + Current_File->min_line = 1; + break; + case N_SOL: + Current_File = find_file(symbolP); + break; + case N_GSYM: + VMS_GSYM_Parse(symbolP,Text_Psect); + break; + case N_LCSYM: + VMS_LCSYM_Parse(symbolP,Text_Psect); + break; + case N_FUN: /* For static constant symbols */ + case N_STSYM: + VMS_STSYM_Parse(symbolP,Text_Psect); + break; + } + } + } + + /* now we take a quick sweep through the files and assign offsets + to each one. This will essentially be the starting line number to the + debugger for each file. Output the info for the debugger to specify the + files, and then tell it how many lines to use */ + { + int File_Number = 0; + int Debugger_Offset = 0; + int file_available; + Current_File = file_root; + for(Current_File = file_root; Current_File; Current_File = Current_File->next){ + if(Current_File == (struct input_file*) NULL) break; + if(Current_File->max_line == 0) continue; + if((strncmp(Current_File->name,"GNU_GXX_INCLUDE:",16) == 0) && + !flagseen['D']) continue; + if((strncmp(Current_File->name,"GNU_CC_INCLUDE:",15) == 0) && + !flagseen['D']) continue; +/* show a few extra lines at the start of the region selected */ + if(Current_File->min_line > 2) Current_File->min_line -= 2; + Current_File->offset = Debugger_Offset - Current_File->min_line + 1; + Debugger_Offset += Current_File->max_line - Current_File->min_line + 1; + if(Current_File->same_file_fpnt != (struct input_file *) NULL) + Current_File->file_number =Current_File->same_file_fpnt->file_number; + else { + Current_File->file_number = ++File_Number; + file_available = VMS_TBT_Source_File(Current_File->name, + Current_File->file_number); + if(!file_available) {Current_File->file_number = 0; + File_Number--; + continue;}; + }; + VMS_TBT_Source_Lines(Current_File->file_number, + Current_File->min_line, + Current_File->max_line-Current_File->min_line+1); + }; /* for */ + }; /* scope */ + Current_File = (struct input_file*) NULL; + + for(symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + /* + * Deal with text symbols + */ + if ((symbolP->sy_nlist.n_type & ~N_EXT) == N_TEXT) { + /* + * Ignore symbols starting with "L", + * as they are local symbols + */ + if (symbolP->sy_nlist.n_un.n_name[0] == 'L') continue; + /* + * If there is a routine start defined, + * terminate it. + */ + if (Current_Routine) { + /* + * End the routine + */ + VMS_TBT_Routine_End(text_siz,Current_Routine); + } + /* + * Store the routine begin traceback info + */ + if(Text_Psect != -1) { + VMS_TBT_Routine_Begin(symbolP,Text_Psect); + Current_Routine = symbolP; + } +/* Output local symbols, i.e. all symbols that are associated with a specific + * routine. We output them now so the debugger recognizes them as local to + * this routine. + */ + { symbolS * symbolP1; + char* pnt; + char* pnt1; + for(symbolP1 = Current_Routine; symbolP1; symbolP1 = symbol_next(symbolP1)) { + if ((symbolP1->sy_nlist.n_type & N_STAB) == 0) continue; + if (symbolP1->sy_nlist.n_type != N_FUN) continue; + pnt=symbolP->sy_nlist.n_un.n_name; + pnt1=symbolP1->sy_nlist.n_un.n_name; + if(*pnt++ != '_') continue; + while(*pnt++ == *pnt1++) {}; + if((*(--pnt) == '\0') && (*(--pnt1) == ':')) break; + }; + if(symbolP1 != (symbolS *) NULL) + VMS_DBG_Define_Routine(symbolP1,Current_Routine,Text_Psect); + } /* local symbol block */ + /* + * Done + */ + continue; + } + /* + * Deal with STAB symbols + */ + if ((symbolP->sy_nlist.n_type & N_STAB) != 0) { + /* + * Dispatch on STAB type + */ + switch((unsigned char)symbolP->sy_nlist.n_type) { + /* + * Line number + */ + case N_SLINE: + /* Offset the line into the correct portion + * of the file */ + if(Current_File->file_number == 0) break; + /* Sometimes the same offset gets several source + * lines assigned to it. + * We should be selective about which lines + * we allow, we should prefer lines that are + * in the main source file when debugging + * inline functions. */ + if((Current_File->file_number != 1) && + symbolP->sy_nlist.n_value == + Current_Offset) break; + /* calculate actual debugger source line */ + symbolP->sy_nlist.n_desc + += Current_File->offset; + /* + * If this is the 1st N_SLINE, setup + * PC/Line correlation. Otherwise + * do the delta PC/Line. If the offset + * for the line number is not +ve we need + * to do another PC/Line correlation + * setup + */ + if (Current_Offset == -1) { + VMS_TBT_Line_PC_Correlation( + symbolP->sy_nlist.n_desc, + symbolP->sy_nlist.n_value, + Text_Psect, + 0); + } else { + if ((symbolP->sy_nlist.n_desc - + Current_Line_Number) <= 0) { + /* + * Line delta is not +ve, we + * need to close the line and + * start a new PC/Line + * correlation. + */ + VMS_TBT_Line_PC_Correlation(0, + symbolP->sy_nlist.n_value - + Current_Offset, + 0, + -1); + VMS_TBT_Line_PC_Correlation( + symbolP->sy_nlist.n_desc, + symbolP->sy_nlist.n_value, + Text_Psect, + 0); + } else { + /* + * Line delta is +ve, all is well + */ + VMS_TBT_Line_PC_Correlation( + symbolP->sy_nlist.n_desc - + Current_Line_Number, + symbolP->sy_nlist.n_value - + Current_Offset, + 0, + 1); + } + } + /* + * Update the current line/PC + */ + Current_Line_Number = symbolP->sy_nlist.n_desc; + Current_Offset = symbolP->sy_nlist.n_value; + /* + * Done + */ + break; + /* + * Source file + */ + case N_SO: + /* + * Remember that we had a source file + * and emit the source file debugger + * record + */ + Current_File = + find_file(symbolP); + break; +/* We need to make sure that we are really in the actual source file when + * we compute the maximum line number. Otherwise the debugger gets really + * confused */ + case N_SOL: + Current_File = + find_file(symbolP); + break; + } + } + } + /* + * If there is a routine start defined, + * terminate it (and the line numbers) + */ + if (Current_Routine) { + /* + * Terminate the line numbers + */ + VMS_TBT_Line_PC_Correlation(0, + text_siz - Current_Routine->sy_nlist.n_value, + 0, + -1); + /* + * Terminate the routine + */ + VMS_TBT_Routine_End(text_siz,Current_Routine); + } + } + /* + * Write the Traceback End Module TBT record + */ + VMS_TBT_Module_End(); + + /* + * Write the End Of Module record + */ + if (Entry_Point_Symbol == 0) + Write_VMS_EOM_Record(-1,0); + else + Write_VMS_EOM_Record(Text_Psect, + Entry_Point_Symbol->sy_nlist.n_value); + + /* + * All done, close the object file + */ + Close_VMS_Object_File(); +} + + + /****** VMS OBJECT FILE HACKING ROUTINES *******/ + + +/* + * Global data (Object records limited to 512 bytes by VAX-11 "C" runtime) + */ +static int VMS_Object_File_FD; /* File Descriptor for object file */ +static char Object_Record_Buffer[512]; /* Buffer for object file records */ +static int Object_Record_Offset; /* Offset to end of data */ +static int Current_Object_Record_Type; /* Type of record in above */ + +/* + * Macros for placing data into the object record buffer + */ +#define PUT_LONG(val) *((long *)(Object_Record_Buffer + \ + Object_Record_Offset)) = val; \ + Object_Record_Offset += sizeof(long) + +#define PUT_SHORT(val) *((short *)(Object_Record_Buffer + \ + Object_Record_Offset)) = val; \ + Object_Record_Offset += sizeof(short) + +#define PUT_CHAR(val) Object_Record_Buffer[Object_Record_Offset++] = val + +#define PUT_COUNTED_STRING(cp) {\ + register char *p = cp; \ + PUT_CHAR(strlen(p)); \ + while(*p) PUT_CHAR(*p++);} + +/* + * Macro for determining if a Name has psect attributes attached + * to it. + */ +#define PSECT_ATTRIBUTES_STRING "$$PsectAttributes_" +#define PSECT_ATTRIBUTES_STRING_LENGTH 18 + +#define HAS_PSECT_ATTRIBUTES(Name) \ + (strncmp((Name[0] == '_' ? Name + 1 : Name), \ + PSECT_ATTRIBUTES_STRING, \ + PSECT_ATTRIBUTES_STRING_LENGTH) == 0) + + +/* + * Create the VMS object file + */ +Create_VMS_Object_File() +{ +#ifdef eunice + VMS_Object_File_FD = creat(out_file_name, 0777, "var"); +#else eunice + VMS_Object_File_FD = creat(out_file_name, 0, "rfm=var"); +#endif eunice + /* + * Deal with errors + */ + if (VMS_Object_File_FD < 0) { + char Error_Line[256]; + + sprintf(Error_Line,"Couldn't create VMS object file \"%s\"", + out_file_name); + error(Error_Line); + } + /* + * Initialize object file hacking variables + */ + Object_Record_Offset = 0; + Current_Object_Record_Type = -1; +} + + +/* + * Declare a particular type of object file record + */ +Set_VMS_Object_File_Record(Type) +int Type; +{ + /* + * If the type matches, we are done + */ + if (Type == Current_Object_Record_Type) return; + /* + * Otherwise: flush the buffer + */ + Flush_VMS_Object_Record_Buffer(); + /* + * Set the new type + */ + Current_Object_Record_Type = Type; +} + + +/* + * Flush the object record buffer to the object file + */ +Flush_VMS_Object_Record_Buffer() +{ + int i; + + /* + * If the buffer is empty, we are done + */ + if (Object_Record_Offset == 0) return; + /* + * Write the data to the file + */ + i= write(VMS_Object_File_FD, + Object_Record_Buffer, + Object_Record_Offset); + if (i != Object_Record_Offset) + error("I/O error writing VMS object file"); + /* + * The buffer is now empty + */ + Object_Record_Offset = 0; +} + + +/* + * Close the VMS Object file + */ +Close_VMS_Object_File() +{ + close(VMS_Object_File_FD); +} + + +/* + * Write the MHD (Module Header) records + */ +Write_VMS_MHD_Records() +{ + register char *cp,*cp1; + register int i; + struct {int Size; char *Ptr;} Descriptor; + char Module_Name[256]; + char Now[17]; + + /* + * We are writing a module header record + */ + Set_VMS_Object_File_Record(OBJ$C_HDR); + /* + * *************************** + * *MAIN MODULE HEADER RECORD* + * *************************** + * + * Store record type and header type + */ + PUT_CHAR(OBJ$C_HDR); + PUT_CHAR(MHD$C_MHD); + /* + * Structure level is 0 + */ + PUT_CHAR(OBJ$C_STRLVL); + /* + * Maximum record size is size of the object record buffer + */ + PUT_SHORT(sizeof(Object_Record_Buffer)); + /* + * Get module name (the FILENAME part of the object file) + */ + cp = out_file_name; + cp1 = Module_Name; + while(*cp) { + if ((*cp == ']') || (*cp == '>') || + (*cp == ':') || (*cp == '/')) { + cp1 = Module_Name; + cp++; + continue; + } + *cp1++ = islower(*cp) ? toupper(*cp++) : *cp++; + } + *cp1 = 0; + /* + * Limit it to 31 characters and store in the object record + */ + while(--cp1 >= Module_Name) + if (*cp1 == '.') *cp1 = 0; + if (strlen(Module_Name) > 31) { + if(flagseen['+']) + printf("%s: Module name truncated: %s\n", myname, Module_Name); + Module_Name[31] = 0; + } + PUT_COUNTED_STRING(Module_Name); + /* + * Module Version is "V1.0" + */ + PUT_COUNTED_STRING("V1.0"); + /* + * Creation time is "now" (17 chars of time string) + */ + Descriptor.Size = 17; + Descriptor.Ptr = Now; + sys$asctim(0,&Descriptor,0,0); + for(i = 0; i < 17; i++) PUT_CHAR(Now[i]); + /* + * Patch time is "never" (17 zeros) + */ + for(i = 0; i < 17; i++) PUT_CHAR(0); + /* + * Flush the record + */ + Flush_VMS_Object_Record_Buffer(); + /* + * ************************* + * *LANGUAGE PROCESSOR NAME* + * ************************* + * + * Store record type and header type + */ + PUT_CHAR(OBJ$C_HDR); + PUT_CHAR(MHD$C_LNM); + /* + * Store language processor name and version + * (not a counted string!) + */ + cp = compiler_version_string; + if (cp == 0) { + cp ="GNU AS V"; + while(*cp) PUT_CHAR(*cp++); + cp = strchr(&version_string,'.'); + while(*cp != ' ') cp--; cp++; + }; + while(*cp >= 32) PUT_CHAR(*cp++); + /* + * Flush the record + */ + Flush_VMS_Object_Record_Buffer(); +} + + +/* + * Write the EOM (End Of Module) record + */ +Write_VMS_EOM_Record(Psect, Offset) +int Psect; +int Offset; +{ + /* + * We are writing an end-of-module record + */ + Set_VMS_Object_File_Record(OBJ$C_EOM); + /* + * Store record Type + */ + PUT_CHAR(OBJ$C_EOM); + /* + * Store the error severity (0) + */ + PUT_CHAR(0); + /* + * Store the entry point, if it exists + */ + if (Psect >= 0) { + /* + * Store the entry point Psect + */ + PUT_CHAR(Psect); + /* + * Store the entry point Psect offset + */ + PUT_LONG(Offset); + } + /* + * Flush the record + */ + Flush_VMS_Object_Record_Buffer(); +} + + +/* this hash routine borrowed from GNU-EMACS, and strengthened slightly ERY*/ + +static int +hash_string (ptr) + unsigned char *ptr; +{ + register unsigned char *p = ptr; + register unsigned char *end = p + strlen(ptr); + register unsigned char c; + register int hash = 0; + + while (p != end) + { + c = *p++; + hash = ((hash<<3) + (hash<<15) + (hash>>28) + c); + } + return hash; +} + +/* + * Generate a Case-Hacked VMS symbol name (limited to 31 chars) + */ +VMS_Case_Hack_Symbol(In,Out) +register char *In; +register char *Out; +{ + long int init = 0; + long int result; + char *pnt; + char *new_name; + char *old_name; + register int i; + int destructor = 0; /*hack to allow for case sens in a destructor*/ + int truncate = 0; + int Case_Hack_Bits = 0; + int Saw_Dollar = 0; + static char Hex_Table[16] = + {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + + /* + * Kill any leading "_" + */ + if (*In == '_') In++; + + new_name=Out; /* save this for later*/ + + if((In[0]=='_')&&(In[1]=='$')&&(In[2]=='_')) + destructor=1; + + /* We may need to truncate the symbol, save the hash for later*/ + if(strlen(In)>23) result = hash_string(In); + /* + * Is there a Psect Attribute to skip?? + */ + if (HAS_PSECT_ATTRIBUTES(In)) { + /* + * Yes: Skip it + */ + In += PSECT_ATTRIBUTES_STRING_LENGTH; + while(*In) { + if ((In[0] == '$') && (In[1] == '$')) { + In += 2; + break; + } + In++; + } + } + + old_name=In; +/* if(strlen(In) > 31 && flagseen['+']) + printf("%s: Symbol name truncated: %s\n",myname,In);*/ + /* + * Do the case conversion + */ + i = 23; /* Maximum of 23 chars */ + while(*In && (--i >= 0)) { + Case_Hack_Bits <<= 1; + if (*In == '$') Saw_Dollar = 1; + if ((destructor==1)&&(i==21)) Saw_Dollar = 0; + if (isupper(*In)) { + *Out++ = *In++; + Case_Hack_Bits |= 1; + } else { + *Out++ = islower(*In) ? toupper(*In++) : *In++; + } + } + /* + * If we saw a dollar sign, we don't do case hacking + */ + if(flagseen['h'] || Saw_Dollar) + Case_Hack_Bits = 0; + + /* + * If we have more than 23 characters and everything is lowercase + * we can insert the full 31 characters + */ + if (*In) { + /* + * We have more than 23 characters + * If we must add the case hack, then we have truncated the str + */ + pnt=Out; + truncate=1; + if (Case_Hack_Bits == 0) { + /* + * And so far they are all lower case: + * Check up to 8 more characters + * and ensure that they are lowercase + */ + if(flagseen['h']) + i=8; + else + for(i = 0; (In[i] != 0) && (i < 8); i++) + if (isupper(In[i]) && !Saw_Dollar) + break; + if(In[i]==0) + truncate=0; + + if ((i >= 8) || (In[i] == 0)) { + /* + * They are: Copy up to 31 characters + * to the output string + */ + i = 8; + while((--i >= 0) && (*In)) + *Out++ = islower(*In) ? + toupper(*In++) : + *In++; + } + } + } + /* + * If there were any uppercase characters in the name we + * take on the case hacking string + */ + + /* Old behavior for regular GNU-C compiler */ + if (!flagseen['+']) + truncate=0; + if ((Case_Hack_Bits != 0)||(truncate==1)) { + if(truncate==0) { + *Out++ = '_'; + for(i = 0; i < 6; i++) { + *Out++ = Hex_Table[Case_Hack_Bits & 0xf]; + Case_Hack_Bits >>= 4; + } + *Out++ = 'X'; + } else { + Out=pnt; /*Cut back to 23 characters maximum */ + *Out++ = '_'; + for( i=0; i < 7; i++) { + init = result & 0x01f; + if (init < 10) + *Out++='0'+init; + else + *Out++ = 'A'+init-10; + result = result >> 5; + } + } + } /*Case Hack */ + /* + * Done + */ + *Out = 0; + if( truncate==1 && flagseen['+'] && flagseen['H']) + printf("%s: Symbol %s replaced by %s\n",myname,old_name,new_name); +} + + +/* + * Scan a symbol name for a psect attribute specification + */ +VMS_Modify_Psect_Attributes(Name, Attribute_Pointer) +char *Name; +int *Attribute_Pointer; +{ + register int i; + register char *cp; + int Negate; + static struct { + char *Name; + int Value; + } Attributes[] = { + {"PIC", GPS$M_PIC}, + {"LIB", GPS$M_LIB}, + {"OVR", GPS$M_OVR}, + {"REL", GPS$M_REL}, + {"GBL", GPS$M_GBL}, + {"SHR", GPS$M_SHR}, + {"EXE", GPS$M_EXE}, + {"RD", GPS$M_RD}, + {"WRT", GPS$M_WRT}, + {"VEC", GPS$M_VEC}, + {0, 0}}; + + /* + * Kill leading "_" + */ + if (*Name == '_') Name++; + /* + * Check for a PSECT attribute list + */ + if (!HAS_PSECT_ATTRIBUTES(Name)) return; /* If not, return */ + /* + * Skip the attribute list indicator + */ + Name += PSECT_ATTRIBUTES_STRING_LENGTH; + /* + * Process the attributes ("_" separated, "$" terminated) + */ + while(*Name != '$') { + /* + * Assume not negating + */ + Negate = 0; + /* + * Check for "NO" + */ + if ((Name[0] == 'N') && (Name[1] == 'O')) { + /* + * We are negating (and skip the NO) + */ + Negate = 1; + Name += 2; + } + /* + * Find the token delimiter + */ + cp = Name; + while(*cp && (*cp != '_') && (*cp != '$')) cp++; + /* + * Look for the token in the attribute list + */ + for(i = 0; Attributes[i].Name; i++) { + /* + * If the strings match, set/clear the attr. + */ + if (strncmp(Name, Attributes[i].Name, cp - Name) == 0) { + /* + * Set or clear + */ + if (Negate) + *Attribute_Pointer &= + ~Attributes[i].Value; + else + *Attribute_Pointer |= + Attributes[i].Value; + /* + * Done + */ + break; + } + } + /* + * Now skip the attribute + */ + Name = cp; + if (*Name == '_') Name++; + } + /* + * Done + */ + return; +} + + +/* + * Define a psect + */ +VMS_Psect_Spec(Name, Size, Type) +char *Name; +int Size; +char *Type; +{ + char Local[32]; + int Psect_Attributes; + + /* + * We are writing a GSD record + */ + Set_VMS_Object_File_Record(OBJ$C_GSD); + /* + * If the buffer is empty we must insert the GSD record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD); + /* + * We are writing a PSECT definition subrecord + */ + PUT_CHAR(GSD$C_PSC); + /* + * Psects are always LONGWORD aligned + */ + PUT_CHAR(2); + /* + * Generate the appropriate PSECT flags given the PSECT type + */ + if (strcmp(Type,"COMMON") == 0) { + /* + * Common block psects are: PIC,OVR,REL,GBL,SHR,RD,WRT + */ + Psect_Attributes = (GPS$M_PIC|GPS$M_OVR|GPS$M_REL|GPS$M_GBL| + GPS$M_SHR|GPS$M_RD|GPS$M_WRT); + } else if (strcmp(Type,"CONST") == 0) { + /* + * Common block psects are: PIC,OVR,REL,GBL,SHR,RD + */ + Psect_Attributes = (GPS$M_PIC|GPS$M_OVR|GPS$M_REL|GPS$M_GBL| + GPS$M_SHR|GPS$M_RD); + } else if (strcmp(Type,"DATA") == 0) { + /* + * The Data psects are PIC,REL,RD,WRT + */ + Psect_Attributes = + (GPS$M_PIC|GPS$M_REL|GPS$M_RD|GPS$M_WRT); + } else if (strcmp(Type,"TEXT") == 0) { + /* + * The Text psects are PIC,REL,SHR,EXE,RD + */ + Psect_Attributes = + (GPS$M_PIC|GPS$M_REL|GPS$M_SHR| + GPS$M_EXE|GPS$M_RD); + } else { + /* + * Error: Unknown psect type + */ + error("Unknown VMS psect type"); + } + /* + * Modify the psect attributes according to any attribute string + */ + if (HAS_PSECT_ATTRIBUTES(Name)) + VMS_Modify_Psect_Attributes(Name,&Psect_Attributes); + /* + * Specify the psect attributes + */ + PUT_SHORT(Psect_Attributes); + /* + * Specify the allocation + */ + PUT_LONG(Size); + /* + * Finally, the psect name + */ + VMS_Case_Hack_Symbol(Name,Local); + PUT_COUNTED_STRING(Local); + /* + * Flush the buffer if it is more than 75% full + */ + if (Object_Record_Offset > + (sizeof(Object_Record_Buffer)*3/4)) + Flush_VMS_Object_Record_Buffer(); +} + + +/* + * Define a global symbol + */ +VMS_Global_Symbol_Spec(Name, Psect_Number, Psect_Offset, Defined) +char *Name; +int Psect_Number; +int Psect_Offset; +{ + char Local[32]; + + /* + * We are writing a GSD record + */ + Set_VMS_Object_File_Record(OBJ$C_GSD); + /* + * If the buffer is empty we must insert the GSD record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD); + /* + * We are writing a Global symbol definition subrecord + */ + if (Psect_Number <= 255) { + PUT_CHAR(GSD$C_SYM); + } else { + PUT_CHAR(GSD$C_SYMW); + } + /* + * Data type is undefined + */ + PUT_CHAR(0); + /* + * Switch on Definition/Reference + */ + if (Defined) { + /* + * Definition: + * Flags = "RELOCATABLE" and "DEFINED" + */ + PUT_SHORT(GSY$M_DEF|GSY$M_REL); + /* + * Psect Number + */ + if (Psect_Number <= 255) { + PUT_CHAR(Psect_Number); + } else { + PUT_SHORT(Psect_Number); + } + /* + * Offset + */ + PUT_LONG(Psect_Offset); + } else { + /* + * Reference: + * Flags = "RELOCATABLE" + */ + PUT_SHORT(GSY$M_REL); + } + /* + * Finally, the global symbol name + */ + VMS_Case_Hack_Symbol(Name,Local); + PUT_COUNTED_STRING(Local); + /* + * Flush the buffer if it is more than 75% full + */ + if (Object_Record_Offset > + (sizeof(Object_Record_Buffer)*3/4)) + Flush_VMS_Object_Record_Buffer(); +} + + +/* + * Define a procedure entry pt/mask + */ +VMS_Procedure_Entry_Pt(Name, Psect_Number, Psect_Offset, Entry_Mask) +char *Name; +int Psect_Number; +int Psect_Offset; +int Entry_Mask; +{ + char Local[32]; + + /* + * We are writing a GSD record + */ + Set_VMS_Object_File_Record(OBJ$C_GSD); + /* + * If the buffer is empty we must insert the GSD record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD); + /* + * We are writing a Procedure Entry Pt/Mask subrecord + */ + if (Psect_Number <= 255) { + PUT_CHAR(GSD$C_EPM); + } else { + PUT_CHAR(GSD$C_EPMW); + } + /* + * Data type is undefined + */ + PUT_CHAR(0); + /* + * Flags = "RELOCATABLE" and "DEFINED" + */ + PUT_SHORT(GSY$M_DEF|GSY$M_REL); + /* + * Psect Number + */ + if (Psect_Number <= 255) { + PUT_CHAR(Psect_Number); + } else { + PUT_SHORT(Psect_Number); + } + /* + * Offset + */ + PUT_LONG(Psect_Offset); + /* + * Entry mask + */ + PUT_SHORT(Entry_Mask); + /* + * Finally, the global symbol name + */ + VMS_Case_Hack_Symbol(Name,Local); + PUT_COUNTED_STRING(Local); + /* + * Flush the buffer if it is more than 75% full + */ + if (Object_Record_Offset > + (sizeof(Object_Record_Buffer)*3/4)) + Flush_VMS_Object_Record_Buffer(); +} + + +/* + * Set the current location counter to a particular Psect and Offset + */ +VMS_Set_Psect(Psect_Index, Offset, Record_Type) +int Psect_Index; +int Offset; +int Record_Type; +{ + /* + * We are writing a "Record_Type" record + */ + Set_VMS_Object_File_Record(Record_Type); + /* + * If the buffer is empty we must insert the record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(Record_Type); + /* + * Stack the Psect base + Longword Offset + */ + if (Psect_Index < 255) { + PUT_CHAR(TIR$C_STA_PL); + PUT_CHAR(Psect_Index); + } else { + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(Psect_Index); + } + PUT_LONG(Offset); + /* + * Set relocation base + */ + PUT_CHAR(TIR$C_CTL_SETRB); + /* + * Flush the buffer if it is more than 75% full + */ + if (Object_Record_Offset > + (sizeof(Object_Record_Buffer)*3/4)) + Flush_VMS_Object_Record_Buffer(); +} + +/* + * Make a data reference + */ +VMS_Set_Data(Psect_Index, Offset, Record_Type,Force) +int Psect_Index; +int Offset; +int Record_Type; +int Force; +{ + /* + * We are writing a "Record_Type" record + */ + Set_VMS_Object_File_Record(Record_Type); + /* + * If the buffer is empty we must insert the record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(Record_Type); + /* + * Stack the Psect base + Longword Offset + */ + if(Force==1){ + if(Psect_Index>127){ + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(Psect_Index); + PUT_LONG(Offset);} + else { + PUT_CHAR(TIR$C_STA_PL); + PUT_CHAR(Psect_Index); + PUT_LONG(Offset);} + } else {if(Offset>32767){ + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(Psect_Index); + PUT_LONG(Offset);} + else if(Offset>127){ + PUT_CHAR(TIR$C_STA_WPW); + PUT_SHORT(Psect_Index); + PUT_SHORT(Offset);} + else{ + PUT_CHAR(TIR$C_STA_WPB); + PUT_SHORT(Psect_Index); + PUT_CHAR(Offset);};}; + /* + * Set relocation base + */ + PUT_CHAR(TIR$C_STO_PIDR); + /* + * Flush the buffer if it is more than 75% full + */ + if (Object_Record_Offset > + (sizeof(Object_Record_Buffer)*3/4)) + Flush_VMS_Object_Record_Buffer(); +} + +/* + * Make a debugger reference to a struct, union or enum. + */ +VMS_Store_Struct(int Struct_Index) +{ + /* + * We are writing a "OBJ$C_DBG" record + */ + Set_VMS_Object_File_Record(OBJ$C_DBG); + /* + * If the buffer is empty we must insert the record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG); + PUT_CHAR(TIR$C_STA_UW); + PUT_SHORT(Struct_Index); + PUT_CHAR(TIR$C_CTL_STKDL); + PUT_CHAR(TIR$C_STO_L); + /* + * Flush the buffer if it is more than 75% full + */ + if (Object_Record_Offset > + (sizeof(Object_Record_Buffer)*3/4)) + Flush_VMS_Object_Record_Buffer(); +} + +/* + * Make a debugger reference to partially define a struct, union or enum. + */ +VMS_Def_Struct(int Struct_Index) +{ + /* + * We are writing a "OBJ$C_DBG" record + */ + Set_VMS_Object_File_Record(OBJ$C_DBG); + /* + * If the buffer is empty we must insert the record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG); + PUT_CHAR(TIR$C_STA_UW); + PUT_SHORT(Struct_Index); + PUT_CHAR(TIR$C_CTL_DFLOC); + /* + * Flush the buffer if it is more than 75% full + */ + if (Object_Record_Offset > + (sizeof(Object_Record_Buffer)*3/4)) + Flush_VMS_Object_Record_Buffer(); +} + +VMS_Set_Struct(int Struct_Index) +{/* see previous functions for comments */ + Set_VMS_Object_File_Record(OBJ$C_DBG); + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG); + PUT_CHAR(TIR$C_STA_UW); + PUT_SHORT(Struct_Index); + PUT_CHAR(TIR$C_CTL_STLOC); + if (Object_Record_Offset > + (sizeof(Object_Record_Buffer)*3/4)) + Flush_VMS_Object_Record_Buffer(); +} + +/* + * Store immediate data in current Psect + */ +VMS_Store_Immediate_Data(Pointer, Size, Record_Type) +register char *Pointer; +int Size; +int Record_Type; +{ + register int i; + + /* + * We are writing a "Record_Type" record + */ + Set_VMS_Object_File_Record(Record_Type); + /* + * We can only store 128 bytes at a time + */ + while(Size > 0) { + /* + * Store a maximum of 128 bytes + */ + i = (Size > 128) ? 128 : Size; + Size -= i; + /* + * If we cannot accommodate this record, flush the + * buffer. + */ + if ((Object_Record_Offset + i + 1) >= + sizeof(Object_Record_Buffer)) + Flush_VMS_Object_Record_Buffer(); + /* + * If the buffer is empty we must insert record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(Record_Type); + /* + * Store the count + */ + PUT_CHAR(-i & 0xff); + /* + * Store the data + */ + while(--i >= 0) PUT_CHAR(*Pointer++); + /* + * Flush the buffer if it is more than 75% full + */ + if (Object_Record_Offset > + (sizeof(Object_Record_Buffer)*3/4)) + Flush_VMS_Object_Record_Buffer(); + } +} + + +/* + * Store repeated immediate data in current Psect + */ +VMS_Store_Repeated_Data(Repeat_Count,Pointer, Size, Record_Type) +int Repeat_Count; +register char *Pointer; +int Size; +int Record_Type; +{ + + /* + * Ignore zero bytes/words/longwords + */ + if ((Size == sizeof(char)) && (*Pointer == 0)) return; + if ((Size == sizeof(short)) && (*(short *)Pointer == 0)) return; + if ((Size == sizeof(long)) && (*(long *)Pointer == 0)) return; + /* + * If the data is too big for a TIR$C_STO_RIVB sub-record + * then we do it manually + */ + if (Size > 255) { + while(--Repeat_Count >= 0) + VMS_Store_Immediate_Data(Pointer,Size,Record_Type); + return; + } + /* + * We are writing a "Record_Type" record + */ + Set_VMS_Object_File_Record(Record_Type); + /* + * If the buffer is empty we must insert record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(Record_Type); + /* + * Stack the repeat count + */ + PUT_CHAR(TIR$C_STA_LW); + PUT_LONG(Repeat_Count); + /* + * And now the command and its data + */ + PUT_CHAR(TIR$C_STO_RIVB); + PUT_CHAR(Size); + while(--Size >= 0) PUT_CHAR(*Pointer++); + /* + * Flush the buffer if it is more than 75% full + */ + if (Object_Record_Offset > + (sizeof(Object_Record_Buffer)*3/4)) + Flush_VMS_Object_Record_Buffer(); +} + + +/* + * Store a Position Independent Reference + */ +VMS_Store_PIC_Symbol_Reference(Symbol, Offset, PC_Relative, + Psect, Psect_Offset, Record_Type) +struct symbol *Symbol; +int Offset; +int PC_Relative; +int Psect; +int Psect_Offset; +int Record_Type; +{ + register struct VMS_Symbol *vsp = + (struct VMS_Symbol *)(Symbol->sy_number); + char Local[32]; + + /* + * We are writing a "Record_Type" record + */ + Set_VMS_Object_File_Record(Record_Type); + /* + * If the buffer is empty we must insert record type + */ + if (Object_Record_Offset == 0) PUT_CHAR(Record_Type); + /* + * Set to the appropriate offset in the Psect + */ + if (PC_Relative) { + /* + * For a Code reference we need to fix the operand + * specifier as well (so back up 1 byte) + */ + VMS_Set_Psect(Psect, Psect_Offset - 1, Record_Type); + } else { + /* + * For a Data reference we just store HERE + */ + VMS_Set_Psect(Psect, Psect_Offset, Record_Type); + } + /* + * Make sure we are still generating a "Record Type" record + */ + if (Object_Record_Offset == 0) PUT_CHAR(Record_Type); + /* + * Dispatch on symbol type (so we can stack its value) + */ + switch(Symbol->sy_nlist.n_type) { + /* + * Global symbol + */ +#ifdef NOT_VAX_11_C_COMPATIBLE + case N_UNDF | N_EXT: + case N_DATA | N_EXT: +#endif NOT_VAX_11_C_COMPATIBLE + case N_UNDF: + case N_TEXT | N_EXT: + /* + * Get the symbol name (case hacked) + */ + VMS_Case_Hack_Symbol(Symbol->sy_nlist.n_un.n_name,Local); + /* + * Stack the global symbol value + */ + PUT_CHAR(TIR$C_STA_GBL); + PUT_COUNTED_STRING(Local); + if (Offset) { + /* + * Stack the longword offset + */ + PUT_CHAR(TIR$C_STA_LW); + PUT_LONG(Offset); + /* + * Add the two, leaving the result on the stack + */ + PUT_CHAR(TIR$C_OPR_ADD); + } + break; + /* + * Uninitialized local data + */ + case N_BSS: + /* + * Stack the Psect (+offset) + */ + if (vsp->Psect_Index < 255) { + PUT_CHAR(TIR$C_STA_PL); + PUT_CHAR(vsp->Psect_Index); + } else { + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(vsp->Psect_Index); + } + PUT_LONG(vsp->Psect_Offset + Offset); + break; + /* + * Local text + */ + case N_TEXT: + /* + * Stack the Psect (+offset) + */ + if (vsp->Psect_Index < 255) { + PUT_CHAR(TIR$C_STA_PL); + PUT_CHAR(vsp->Psect_Index); + } else { + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(vsp->Psect_Index); + } + PUT_LONG(Symbol->sy_nlist.n_value); + break; + /* + * Initialized local or global data + */ + case N_DATA: +#ifndef NOT_VAX_11_C_COMPATIBLE + case N_UNDF | N_EXT: + case N_DATA | N_EXT: +#endif NOT_VAX_11_C_COMPATIBLE + /* + * Stack the Psect (+offset) + */ + if (vsp->Psect_Index < 255) { + PUT_CHAR(TIR$C_STA_PL); + PUT_CHAR(vsp->Psect_Index); + } else { + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(vsp->Psect_Index); + } + PUT_LONG(vsp->Psect_Offset + Offset); + break; + } + /* + * Store either a code or data reference + */ + PUT_CHAR(PC_Relative ? TIR$C_STO_PICR : TIR$C_STO_PIDR); + /* + * Flush the buffer if it is more than 75% full + */ + if (Object_Record_Offset > + (sizeof(Object_Record_Buffer)*3/4)) + Flush_VMS_Object_Record_Buffer(); +} + + +/* + * Check in the text area for an indirect pc-relative reference + * and fix it up with addressing mode 0xff [PC indirect] + * + * THIS SHOULD BE REPLACED BY THE USE OF TIR$C_STO_PIRR IN THE + * PIC CODE GENERATING FIXUP ROUTINE. + */ +VMS_Fix_Indirect_Reference(Text_Psect, Offset, fragP, text_frag_root) +int Text_Psect; +int Offset; +register fragS *fragP; +struct frag *text_frag_root; +{ + /* + * The addressing mode byte is 1 byte before the address + */ + Offset--; + /* + * Is it in THIS frag?? + */ + if ((Offset < fragP->fr_address) || + (Offset >= (fragP->fr_address + fragP->fr_fix))) { + /* + * We need to search for the fragment containing this + * Offset + */ + for(fragP = text_frag_root; fragP; fragP = fragP->fr_next) { + if ((Offset >= fragP->fr_address) && + (Offset < (fragP->fr_address + fragP->fr_fix))) + break; + } + /* + * If we couldn't find the frag, things are BAD!! + */ + if (fragP == 0) + error("Couldn't find fixup fragment when checking for indirect reference"); + } + /* + * Check for indirect PC relative addressing mode + */ + if (fragP->fr_literal[Offset - fragP->fr_address] == (char)0xff) { + static char Address_Mode = 0xff; + + /* + * Yes: Store the indirect mode back into the image + * to fix up the damage done by STO_PICR + */ + VMS_Set_Psect(Text_Psect,Offset,OBJ$C_TIR); + VMS_Store_Immediate_Data(&Address_Mode,1,OBJ$C_TIR); + } +} + + +/* + * Write the Traceback Module Begin record + */ +VMS_TBT_Module_Begin() +{ + register char *cp,*cp1; + int Size; + char Module_Name[256]; + char Local[256]; + + /* + * Get module name (the FILENAME part of the object file) + */ + cp = out_file_name; + cp1 = Module_Name; + while(*cp) { + if ((*cp == ']') || (*cp == '>') || + (*cp == ':') || (*cp == '/')) { + cp1 = Module_Name; + cp++; + continue; + } + *cp1++ = islower(*cp) ? toupper(*cp++) : *cp++; + } + *cp1 = 0; + /* + * Limit it to 31 characters + */ + while(--cp1 >= Module_Name) + if (*cp1 == '.') *cp1 = 0; + if (strlen(Module_Name) > 31) { + if(flagseen['+']) + printf("%s: Module name truncated: %s\n",myname, Module_Name); + Module_Name[31] = 0; + } + /* + * Arrange to store the data locally (leave room for size byte) + */ + cp = Local+1; + /* + * Begin module + */ + *cp++ = DST$C_MODBEG; + /* + * Unused + */ + *cp++ = 0; + /* + * Language type == "C" + */ + *(long *)cp = DST$C_C; + cp += sizeof(long); + /* + * Store the module name + */ + *cp++ = strlen(Module_Name); + cp1 = Module_Name; + while(*cp1) *cp++ = *cp1++; + /* + * Now we can store the record size + */ + Size = (cp - Local); + Local[0] = Size-1; + /* + * Put it into the object record + */ + VMS_Store_Immediate_Data(Local, Size, OBJ$C_TBT); +} + + +/* + * Write the Traceback Module End record +*/ +VMS_TBT_Module_End() +{ + char Local[2]; + + /* + * End module + */ + Local[0] = 1; + Local[1] = DST$C_MODEND; + /* + * Put it into the object record + */ + VMS_Store_Immediate_Data(Local, 2, OBJ$C_TBT); +} + + +/* + * Write the Traceback Routine Begin record + */ +VMS_TBT_Routine_Begin(symbolP, Psect) +struct symbol *symbolP; +int Psect; +{ + register char *cp,*cp1; + char *Name; + int Offset; + int Size; + char Local[512]; + + /* + * Strip the leading "_" from the name + */ + Name = symbolP->sy_nlist.n_un.n_name; + if (*Name == '_') Name++; + /* + * Get the text psect offset + */ + Offset = symbolP->sy_nlist.n_value; + /* + * Calculate the record size + */ + Size = 1+1+4+1+strlen(Name); + /* + * Record Size + */ + Local[0] = Size; + /* + * Begin Routine + */ + Local[1] = DST$C_RTNBEG; + /* + * Uses CallS/CallG + */ + Local[2] = 0; + /* + * Store the data so far + */ + VMS_Store_Immediate_Data(Local, 3, OBJ$C_TBT); + /* + * Make sure we are still generating a OBJ$C_TBT record + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_TBT); + /* + * Now get the symbol address + */ + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(Psect); + PUT_LONG(Offset); + /* + * Store the data reference + */ + PUT_CHAR(TIR$C_STO_PIDR); + /* + * Store the counted string as data + */ + cp = Local; + cp1 = Name; + Size = strlen(cp1) + 1; + *cp++ = Size - 1; + while(*cp1) *cp++ = *cp1++; + VMS_Store_Immediate_Data(Local, Size, OBJ$C_TBT); +} + + +/* + * Write the Traceback Routine End record + * We *must* search the symbol table to find the next routine, since + * the assember has a way of reassembling the symbol table OUT OF ORDER + * Thus the next routine in the symbol list is not necessarily the + * next one in memory. For debugging to work correctly we must know the + * size of the routine. + */ +VMS_TBT_Routine_End(Max_Size,sp) +int Max_Size; +symbolS *sp; +{ + symbolS *symbolP; + int Size = 0x7fffffff; + char Local[16]; + + + for(symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + if ((symbolP->sy_nlist.n_type & ~N_EXT) == N_TEXT) { + if (symbolP->sy_nlist.n_un.n_name[0] == 'L') continue; + if((symbolP->sy_nlist.n_value > sp->sy_nlist.n_value) && + (symbolP->sy_nlist.n_value < Size )) + Size = symbolP->sy_nlist.n_value; + /* check if gcc_compiled. has size of zero */ + if((symbolP->sy_nlist.n_value == sp->sy_nlist.n_value) && + sp != symbolP && + !strcmp(sp->sy_nlist.n_un.n_name,"gcc_compiled.")) + Size = symbolP->sy_nlist.n_value; + + }; + }; + if(Size == 0x7fffffff) Size = Max_Size; + Size -= sp->sy_nlist.n_value; /* and get the size of the routine */ + /* + * Record Size + */ + Local[0] = 6; + /* + * End of Routine + */ + Local[1] = DST$C_RTNEND; + /* + * Unused + */ + Local[2] = 0; + /* + * Size of routine + */ + *((long *)(Local+3)) = Size; + /* + * Store the record + */ + VMS_Store_Immediate_Data(Local,7, OBJ$C_TBT); +} +/* + * Write the Traceback Block End record + */ +VMS_TBT_Block_Begin(symbolP, Psect, Name) +struct symbol *symbolP; +int Psect; +char* Name; +{ + register char *cp,*cp1; + int Offset; + int Size; + char Local[512]; + /* + * Begin block + */ + Size = 1+1+4+1+strlen(Name); + /* + * Record Size + */ + Local[0] = Size; + /* + * Begin Block - We simulate with a phony routine + */ + Local[1] = DST$C_BLKBEG; + /* + * Uses CallS/CallG + */ + Local[2] = 0; + /* + * Store the data so far + */ + VMS_Store_Immediate_Data(Local, 3, OBJ$C_DBG); + /* + * Make sure we are still generating a OBJ$C_DBG record + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG); + /* + * Now get the symbol address + */ + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(Psect); + /* + * Get the text psect offset + */ + Offset = symbolP->sy_nlist.n_value; + PUT_LONG(Offset); + /* + * Store the data reference + */ + PUT_CHAR(TIR$C_STO_PIDR); + /* + * Store the counted string as data + */ + cp = Local; + cp1 = Name; + Size = strlen(cp1) + 1; + *cp++ = Size - 1; + while(*cp1) *cp++ = *cp1++; + VMS_Store_Immediate_Data(Local, Size, OBJ$C_DBG); +} + + +/* + * Write the Traceback Block End record + */ +VMS_TBT_Block_End(int Size) +{ + char Local[16]; + + /* + * End block - simulate with a phony end routine + */ + Local[0] = 6; + Local[1] = DST$C_BLKEND; + *((long *)(Local+3)) = Size; + /* + * Unused + */ + Local[2] = 0; + VMS_Store_Immediate_Data(Local,7, OBJ$C_DBG); +} + + + +/* + * Write a Line number / PC correlation record + */ +VMS_TBT_Line_PC_Correlation(Line_Number, Offset, Psect, Do_Delta) +int Line_Number; +int Offset; +int Psect; +int Do_Delta; +{ + register char *cp; + char Local[64]; + + /* +* If not delta, set our PC/Line number correlation +*/ + if (Do_Delta == 0) { + /* + * Size + */ + Local[0] = 1+1+2+1+4; + /* + * Line Number/PC correlation + */ + Local[1] = DST$C_LINE_NUM; + /* + * Set Line number + */ + Local[2] = DST$C_SET_LINE_NUM; + *((unsigned short *)(Local+3)) = Line_Number-1; + /* + * Set PC + */ + Local[5] = DST$C_SET_ABS_PC; + VMS_Store_Immediate_Data(Local, 6, OBJ$C_TBT); + /* + * Make sure we are still generating a OBJ$C_TBT record + */ + if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_TBT); + if (Psect < 255) { + PUT_CHAR(TIR$C_STA_PL); + PUT_CHAR(Psect); + } else { + PUT_CHAR(TIR$C_STA_WPL); + PUT_SHORT(Psect); + } + PUT_LONG(Offset); + PUT_CHAR(TIR$C_STO_PIDR); + /* + * Do a PC offset of 0 to register the line number + */ + Local[0] = 2; + Local[1] = DST$C_LINE_NUM; + Local[2] = 0; /* Increment PC by 0 and register line # */ + VMS_Store_Immediate_Data(Local, 3, OBJ$C_TBT); + } else { + /* + * If Delta is negative, terminate the line numbers + */ + if (Do_Delta < 0) { + Local[0] = 1+1+4; + Local[1] = DST$C_LINE_NUM; + Local[2] = DST$C_TERM_L; + *((long *)(Local+3)) = Offset; + VMS_Store_Immediate_Data(Local, 7, OBJ$C_TBT); + /* + * Done + */ + return; + } + /* + * Do a PC/Line delta + */ + cp = Local+1; + *cp++ = DST$C_LINE_NUM; + if (Line_Number > 1) { + /* + * We need to increment the line number + */ + if (Line_Number-1 <= 255) { + *cp++ = DST$C_INCR_LINUM; + *cp++ = Line_Number-1; + } else { + *cp++ = DST$C_INCR_LINUM_W; + *(short *)cp = Line_Number-1; + cp += sizeof(short); + } + } + /* + * Increment the PC + */ + if (Offset <= 128) { + *cp++ = -Offset; + } else { + if (Offset < 0x10000) { + *cp++ = DST$C_DELTA_PC_W; + *(short *)cp = Offset; + cp += sizeof(short); + } else { + *cp++ = DST$C_DELTA_PC_L; + *(long *)cp = Offset; + cp += sizeof(long); + } + } + Local[0] = cp - (Local+1); + VMS_Store_Immediate_Data(Local,cp - Local, OBJ$C_TBT); + } +} + + +/* + * Describe a source file to the debugger + */ +VMS_TBT_Source_File(Filename, ID_Number) +char *Filename; +int ID_Number; +{ + register char *cp,*cp1; + int Status,i; + char Local[512]; + static struct FAB Fab; + static struct NAM Nam; + static struct XABDAT Date_Xab; + static struct XABFHC File_Header_Xab; + char Es_String[255],Rs_String[255]; + + /* + * Setup the Fab + */ + Fab.fab$b_bid = FAB$C_BID; + Fab.fab$b_bln = sizeof(Fab); + Fab.fab$l_nam = (&Nam); + Fab.fab$l_xab = (struct XAB *)&Date_Xab; + /* + * Setup the Nam block so we can find out the FULL name + * of the source file. + */ + Nam.nam$b_bid = NAM$C_BID; + Nam.nam$b_bln = sizeof(Nam); + Nam.nam$l_rsa = Rs_String; + Nam.nam$b_rss = sizeof(Rs_String); + Nam.nam$l_esa = Es_String; + Nam.nam$b_ess = sizeof(Es_String); + /* + * Setup the Date and File Header Xabs + */ + Date_Xab.xab$b_cod = XAB$C_DAT; + Date_Xab.xab$b_bln = sizeof(Date_Xab); + Date_Xab.xab$l_nxt = (char *)&File_Header_Xab; + File_Header_Xab.xab$b_cod = XAB$C_FHC; + File_Header_Xab.xab$b_bln = sizeof(File_Header_Xab); +/* ((struct XAB *)&Date_Xab)->xab$b_cod = XAB$C_DAT; */ +/* ((struct XAB *)&Date_Xab)->xab$b_bln = sizeof(Date_Xab); */ +/* ((struct XAB *)&Date_Xab)->xab$l_nxt = (struct XAB *)&File_Header_Xab; */ +/* ((struct XAB *)&File_Header_Xab)->xab$b_cod = XAB$C_FHC; */ +/* ((struct XAB *)&File_Header_Xab)->xab$b_bln = sizeof(File_Header_Xab); */ + /* + * Get the file information + */ + Fab.fab$l_fna = Filename; + Fab.fab$b_fns = strlen(Filename); + Status = sys$open(&Fab); + if (!(Status & 1)) { + printf("gas: Couldn't find source file \"%s\", Error = %%X%x\n", + Filename, Status); + return(0); + } + sys$close(&Fab); + /* + * Calculate the size of the resultant string + */ + i = Nam.nam$b_rsl; + /* + * Size of record + */ + Local[0] = 1+1+1+1+1+2+8+4+2+1+1+i+1; + /* + * Source declaration + */ + Local[1] = DST$C_SOURCE; + /* + * Make formfeeds count as source records + */ + Local[2] = DST$C_SRC_FORMFEED; + /* + * Declare source file + */ + Local[3] = DST$C_SRC_DECLFILE; + Local[4] = 1+2+8+4+2+1+1+i+1; + cp = Local+5; + /* + * Flags + */ + *cp++ = 0; + /* + * File ID + */ + *(short *)cp = ID_Number; + cp += sizeof(short); + /* + * Creation Date + */ + *(long *)cp = ((long *) &Date_Xab.xab$q_cdt)[0]; + cp += sizeof(long); + *(long *)cp = ((long *) &Date_Xab.xab$q_cdt)[1]; + cp += sizeof(long); + /* + * End of file block + */ + *(long *)cp = File_Header_Xab.xab$l_ebk; + cp += sizeof(long); + /* + * First free byte + */ + *(short *)cp = File_Header_Xab.xab$w_ffb; + cp += sizeof(short); + /* + * Record format + */ + *cp++ = File_Header_Xab.xab$b_rfo; + /* + * Filename + */ + *cp++ = i; + cp1 = Rs_String; + while(--i >= 0) *cp++ = *cp1++; + /* + * Library module name (none) + */ + *cp++ = 0; + /* + * Done + */ + VMS_Store_Immediate_Data(Local,cp - Local, OBJ$C_TBT); +} + + +/* + * Give the number of source lines to the debugger + */ +VMS_TBT_Source_Lines(ID_Number,Starting_Line_Number,Number_Of_Lines) +int ID_Number; +int Starting_Line_Number; +int Number_Of_Lines; +{ + char *cp,*cp1; + char Local[16]; + + /* + * Size of record + */ + Local[0] = 1+1+2+1+4+1+2; + /* + * Source declaration + */ + Local[1] = DST$C_SOURCE; + /* + * Set Source File + */ + cp = Local+2; + *cp++ = DST$C_SRC_SETFILE; + /* + * File ID Number + */ + *(short *)cp = ID_Number; + cp += sizeof(short); + /* + * Set record number + */ + *cp++ = DST$C_SRC_SETREC_L; + *(long *)cp = Starting_Line_Number; + cp += sizeof(long); + /* + * Define lines + */ + *cp++ = DST$C_SRC_DEFLINES_W; + *(short *)cp = Number_Of_Lines; + cp += sizeof(short); + /* + * Done + */ + VMS_Store_Immediate_Data(Local, cp-Local, OBJ$C_TBT); +} + + +/* + * Given the pointer to a symbol we calculate how big the data at the + * symbol is. We do this by looking for the next symbol (local or + * global) which will indicate the start of another datum. + */ +int VMS_Initialized_Data_Size(sp, End_Of_Data) +register struct symbol *sp; +int End_Of_Data; +{ + register struct symbol *sp1,*Next_Symbol; + + /* + * Find the next symbol + * it delimits this datum + */ + Next_Symbol = 0; + for (sp1 = symbol_rootP; sp1; sp1 = symbol_next(sp1)) { + /* + * The data type must match + */ + if ((sp1->sy_nlist.n_type & ~N_EXT) != N_DATA) continue; + /* + * The symbol must be AFTER this symbol + */ + if (sp1->sy_nlist.n_value <= sp->sy_nlist.n_value) continue; + /* + * We ignore THIS symbol + */ + if (sp1 == sp) continue; + /* + * If there is already a candidate selected for the + * next symbol, see if we are a better candidate + */ + if (Next_Symbol) { + /* + * We are a better candidate if we are "closer" + * to the symbol + */ + if (sp1->sy_nlist.n_value > + Next_Symbol->sy_nlist.n_value) + continue; + /* + * Win: Make this the candidate + */ + Next_Symbol = sp1; + } else { + /* + * This is the 1st candidate + */ + Next_Symbol = sp1; + } + } + /* + * Calculate its size + */ + return(Next_Symbol ? + (Next_Symbol->sy_nlist.n_value - + sp->sy_nlist.n_value) : + (End_Of_Data - sp->sy_nlist.n_value)); +} + + + +/* this routine locates a file in the list of files. If an entry does not + * exist, one is created. For include files, a new entry is always created + * such that inline functions can be properly debugged */ +struct input_file * +find_file(sp) +symbolS * sp; +{ + struct input_file * same_file; + struct input_file * fpnt; + same_file = (struct input_file*) NULL; + for(fpnt = file_root; fpnt; fpnt = fpnt->next){ + if(fpnt == (struct input_file*) NULL) break; + if(fpnt->spnt == sp) return fpnt; + }; + for(fpnt = file_root; fpnt; fpnt = fpnt->next){ + if(fpnt == (struct input_file*) NULL) break; + if (strcmp(sp->sy_nlist.n_un.n_name,fpnt->name) == 0){ + if(fpnt->flag == 1)return fpnt; + same_file = fpnt; + break; + }; + }; + fpnt = (struct input_file*) malloc(sizeof(struct input_file)); + if(file_root == (struct input_file*) NULL) file_root = fpnt; + else { + struct input_file * fpnt1; + for(fpnt1 = file_root; fpnt1->next; fpnt1 = fpnt1->next); + fpnt1->next = fpnt; + }; + fpnt->next = (struct input_file*) NULL; + fpnt->name = sp->sy_nlist.n_un.n_name; + fpnt->min_line = 0x7fffffff; + fpnt->max_line = 0; + fpnt->offset = 0; + fpnt->flag = 0; + fpnt->file_number = 0; + fpnt->spnt = sp; + fpnt->same_file_fpnt = same_file; + return fpnt; +} + + +/* + * This is a hacked _doprnt() for VAX-11 "C". It understands that + * it is ONLY called by as_fatal(Format, Args) with a pointer to the + * "Args" argument. From this we can make it all work right! + */ +#ifndef eunice +_doprnt(Format, a, f) +char *Format; +FILE *f; +char **a; +{ + int Nargs = ((int *)a)[-2]; /* This understands as_fatal() */ + + switch(Nargs) { + default: fprintf(f,"_doprnt error on \"%s\"!!",Format); break; + case 1: fprintf(f,Format); break; + case 2: fprintf(f,Format,a[0]); break; + case 3: fprintf(f,Format,a[0],a[1]); break; + case 4: fprintf(f,Format,a[0],a[1],a[2]); break; + case 5: fprintf(f,Format,a[0],a[1],a[2],a[3]); break; + case 6: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4]); break; + case 7: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5]); break; + case 8: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5],a[6]); break; + case 9: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]); break; + case 10: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]); break; + } +} + +#endif /* eunice */ + +#endif /* VMS */ + +char const_flag = 0; +void s_const(); + +void +s_const() +{ + register int temp; + + temp = get_absolute_expression (); + subseg_new (SEG_DATA, (subsegT)temp); + const_flag = 1; + demand_empty_rest_of_line(); +} + +obj_crawl_symbol_chain() { + /* JF deal with forward references first. . . */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + if (symbolP->sy_forward) { + symbolP->sy_value += symbolP->sy_forward->sy_value + symbolP->sy_forward->sy_frag->fr_address; +#ifdef OBJ_COFF + if(SF_GET_GET_SEGMENT(symbolP) && + S_GET_SEGMENT(symbolP) == SEG_UNKNOWN) + S_SET_SEGMENT(symbolP, S_GET_SEGMENT(symbolP->sy_forward)); +#endif /* OBJ_COFF */ + symbolP->sy_forward=0; + } /* if it has a forward reference */ + } /* walk the symbol chain */ + + { /* crawl symbol table */ + register int symbol_number = 0; + +#if defined(OBJ_COFF) + { /* OBJ_COFF version */ + lineno* lineP; + symbolS* symbol_externP = (symbolS*)0; + symbolS* symbol_extern_lastP = (symbolS*)0; + + /* The symbol list should be ordered according to the following sequence + * order : + * . .file symbol + * . debug entries for functions + * . fake symbols for .text .data and .bss + * . defined symbols + * . undefined symbols + * But this is not mandatory. The only important point is to put the + * undefined symbols at the end of the list. + */ + + if (symbol_rootP == NULL + || S_GET_STORAGE_CLASS(symbol_rootP) != C_FILE) { + c_dot_file_symbol("fake"); + } /* Is there a .file symbol ? If not insert one at the beginning. */ + + /* + * Build up static symbols for .text, .data and .bss + */ + dot_text_symbol = (symbolS*) + c_section_symbol(".text", + 0, + H_GET_TEXT_SIZE(&headers), + 0/*text_relocation_number*/, + 0/*text_lineno_number*/); + + dot_data_symbol = (symbolS*) + c_section_symbol(".data", + H_GET_TEXT_SIZE(&headers), + H_GET_DATA_SIZE(&headers), + 0/*data_relocation_number*/, + 0); /* There are no data lineno + entries */ + + dot_bss_symbol = (symbolS*) + c_section_symbol(".bss", + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers), + H_GET_BSS_SIZE(&headers), + 0, /* No relocation for a bss section. */ + 0); /* There are no bss lineno entries */ + + /* FIXME late night before delivery, I don't know why the chain is + broken, but I can guess. So! Let's force them to be knit properly + at this point. */ + +/* as john pointed out, this wasn't right. Instead, we'll check here to + make sure that the list is doubly linked. */ + +#if defined(DEBUG) && defined(SYMBOLS_NEED_BACKPOINTERS) + for (symbolP = symbol_rootP; symbol_next(symbolP); symbolP = symbol_next(symbolP)) { + know(symbolP->sy_next->sy_previous == symbolP); + } /* walk the symbol chain */ +#endif /* DEBUG and SYMBOLS_NEED_BACKPOINTERS */ + symbolP = symbol_rootP; + + if (symbolP) { + while(symbolP) { + /* If the symbol has a tagndx entry, resolve it */ + if(SF_GET_TAGGED(symbolP)) { + SA_SET_SYM_TAGNDX(symbolP, + ((symbolS*)SA_GET_SYM_TAGNDX(symbolP))->sy_number); + } + /* Debug symbol do not need all this rubbish */ + if(!SF_GET_DEBUG(symbolP)) { + symbolS* real_symbolP; + /* L* and C_EFCN symbols never merge. */ + if(!SF_GET_LOCAL(symbolP) && + (real_symbolP = + symbol_find_base(S_GET_NAME(symbolP), DO_NOT_STRIP)) && + real_symbolP != symbolP) { + /* FIXME where do dups come from? xoxorich. */ + /* Move the debug data from the debug symbol to the + real symbol. Do NOT do the oposite (i.e. move from + real symbol to symbol and remove real symbol from the + list.) Because some pointers refer to the real symbol + whereas no pointers refer to the symbol. */ + c_symbol_merge(symbolP, real_symbolP); + /* Replace the current symbol by the real one */ + /* The symbols will never be the last or the first + because : 1st symbol is .file and 3 last symbols are + .text, .data, .bss */ + symbol_remove(real_symbolP, &symbol_rootP, &symbol_lastP); + symbol_insert(real_symbolP, symbolP, &symbol_rootP, &symbol_lastP); + symbol_remove(symbolP, &symbol_rootP, &symbol_lastP); + symbolP = real_symbolP; + } + if(flagseen['R'] && S_IS_DATA(symbolP)) + S_SET_TEXT(symbolP); + + symbolP->sy_value += symbolP->sy_frag->fr_address; + + if(!S_IS_DEFINED(symbolP)) + S_SET_EXTERNAL(symbolP); + else if(S_GET_STORAGE_CLASS(symbolP) == C_NULL) + S_SET_STORAGE_CLASS(symbolP, C_STAT); + + /* Mainly to speed up if not -g */ + if(SF_GET_PROCESS(symbolP)) { + /* Handle the nested blocks auxiliary info. */ + if(S_GET_STORAGE_CLASS(symbolP) == C_BLOCK) { + if(!strcmp(S_GET_NAME(symbolP), ".bb")) + stack_push(block_stack, (char *) &symbolP); + else { /* .eb */ + register symbolS* begin_symbolP; + begin_symbolP = *(symbolS**)stack_pop(block_stack); + if(begin_symbolP == (symbolS*)0) + as_warn("mismatched .eb"); + else + SA_SET_SYM_ENDNDX(begin_symbolP, symbol_number); + } + } + /* If we are able to identify the type of a function, and we + are out of a function (last_functionP == 0) then, the + function symbol will be associated with an auxiliary + entry. */ + if(last_functionP == (symbolS*)0 && + SF_GET_FUNCTION(symbolP)) { + last_functionP = symbolP; + S_SET_NUMBER_AUXILIARY(symbolP, 1); + /* Clobber possible stale .dim information. */ + memset(&symbolP->sy_auxent[0], '\0', sizeof(union auxent)); + } + /* The C_FCN doesn't need any additional information. + I don't even know if this is needed for sdb. But the + standard assembler generates it, so... + */ + if(S_GET_STORAGE_CLASS(symbolP) == C_EFCN) { + if(last_functionP == (symbolS*)0) + as_fatal("C_EFCN symbol out of scope"); + SA_SET_SYM_FSIZE(last_functionP, + (long)(symbolP->sy_value - + last_functionP->sy_value)); + SA_SET_SYM_ENDNDX(last_functionP, symbol_number); + last_functionP = (symbolS*)0; + } + } + } else { + /* First descriptor of a structure must point to the next + slot outside the structure description. */ + if(SF_GET_TAG(symbolP)) + last_tagP = symbolP; + else if(S_GET_STORAGE_CLASS(symbolP) == C_EOS) + /* +2 take in account the current symbol */ + SA_SET_SYM_ENDNDX(last_tagP, symbol_number+2); + } + + /* We must put the external symbols apart. The loader + does not bomb if we do not. But the references in + the endndx field for a .bb symbol are not corrected + if an external symbol is removed between .bb and .be. + I.e in the following case : + [20] .bb endndx = 22 + [21] foo external + [22] .be + ld will move the symbol 21 to the end of the list but + endndx will still be 22 instead of 21. */ + { + register symbolS* thisP = symbolP; + + symbolP = symbol_next(thisP); + /* remove C_EFCN and LOCAL (L...) symbols */ + if (SF_GET_LOCAL(thisP)) { + symbol_remove(thisP, &symbol_rootP, &symbol_lastP); + } else { + if(S_GET_STORAGE_CLASS(thisP) == C_EXT && + !SF_GET_FUNCTION(thisP)) { + /* Remove from the list */ + symbol_remove(thisP, &symbol_rootP, &symbol_lastP); + symbol_clear_list_pointers(thisP); + /* Move at the end of the list */ + if (symbol_extern_lastP == (symbolS*)0) + symbol_externP = thisP; + else + symbol_append(thisP, symbol_extern_lastP); + symbol_extern_lastP = thisP; + } else { + if(SF_GET_STRING(thisP)) { + thisP->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(thisP)) + 1; + } else + thisP->sy_name_offset = 0; + thisP->sy_number = symbol_number; + symbol_number += 1 + S_GET_NUMBER_AUXILIARY(thisP); + } + } + } + } + + /* this actually appends the entire extern chain */ + symbol_append(symbol_externP, symbol_lastP); + symbolP = symbol_externP; + while(symbolP) { + if(SF_GET_STRING(symbolP)) { + symbolP->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(symbolP)) + 1; + } else + symbolP->sy_name_offset = 0; + symbolP->sy_number = symbol_number; + symbol_number += 1 + S_GET_NUMBER_AUXILIARY(symbolP); + symbolP = symbol_next(symbolP); + } + } + + /* FIXME I'm counting line no's here so we know what to put in the section + headers, and I'm resolving the addresses since I'm not sure how to + do it later. I am NOT resolving the linno's representing functions. + Their symbols need a fileptr pointing to this linno when emitted. + Thus, I resolve them on emit. xoxorich. */ + + for (lineP = lineno_rootP; lineP; lineP = lineP->next) { + if (lineP->line.l_lnno) { + lineP->line.l_addr.l_paddr += ((fragS*)lineP->frag)->fr_address; + } else { + ; + } + text_lineno_number++; + } /* for each line number */ + } /* OBJ_COFF version */ +#elif defined(OBJ_AOUT) | defined(OBJ_BOUT) + { /* OBJ_AOUT version */ + symbolPP = & symbol_rootP; /* -> last symbol chain link. */ + while ((symbolP = *symbolPP) != NULL) + { + if (flagseen['R'] && S_IS_DATA(symbolP)) { + S_SET_TEXT(symbolP); + } /* if pusing data into text */ + + symbolP -> sy_value += 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) +#ifndef VMS /* Under VMS we need to keep local symbols */ + && ( !S_GET_NAME(symbolP) + || S_IS_DEBUG(symbolP) +#ifdef TC_I960 + /* FIXME 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)))) +#endif /* not VMS */ + ) + { +#ifndef VMS + 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. */ +#endif /* not VMS */ + 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", name); + } /* oops. */ + +#ifndef VMS + /* Unhook it from the chain */ + *symbolPP = symbol_next(symbolP); +#endif /* VMS */ + } /* if this symbol should be in the output */ + } /* for each symbol */ + } /* OBJ_AOUT version */ +#else + cant_crawl_symbol_table(); +#endif + H_SET_STRING_SIZE(&headers,string_byte_count); + H_SET_SYMBOL_TABLE_SIZE(&headers, symbol_number); + } /* crawl symbol table */ + + /* JF deal with forward references first. . . */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { + if (symbolP->sy_forward) { + symbolP->sy_value += symbolP->sy_forward->sy_value + symbolP->sy_forward->sy_frag->fr_address; +#ifdef OBJ_COFF + if(SF_GET_GET_SEGMENT(symbolP) && + S_GET_SEGMENT(symbolP) == SEG_UNKNOWN) + S_SET_SEGMENT(symbolP, S_GET_SEGMENT(symbolP->sy_forward)); +#endif /* OBJ_COFF */ + symbolP->sy_forward=0; + } /* if it has a forward reference */ + } /* walk the symbol chain */ + + { /* crawl symbol table */ + register int symbol_number = 0; + +#if defined(OBJ_COFF) + { /* OBJ_COFF version */ + lineno* lineP; + symbolS* symbol_externP = (symbolS*)0; + symbolS* symbol_extern_lastP = (symbolS*)0; + + /* The symbol list should be ordered according to the following sequence + * order : + * . .file symbol + * . debug entries for functions + * . fake symbols for .text .data and .bss + * . defined symbols + * . undefined symbols + * But this is not mandatory. The only important point is to put the + * undefined symbols at the end of the list. + */ + + if (symbol_rootP == NULL + || S_GET_STORAGE_CLASS(symbol_rootP) != C_FILE) { + c_dot_file_symbol("fake"); + } /* Is there a .file symbol ? If not insert one at the beginning. */ + + /* + * Build up static symbols for .text, .data and .bss + */ + dot_text_symbol = (symbolS*) + c_section_symbol(".text", + 0, + H_GET_TEXT_SIZE(&headers), + 0/*text_relocation_number*/, + 0/*text_lineno_number*/); + + dot_data_symbol = (symbolS*) + c_section_symbol(".data", + H_GET_TEXT_SIZE(&headers), + H_GET_DATA_SIZE(&headers), + 0/*data_relocation_number*/, + 0); /* There are no data lineno + entries */ + + dot_bss_symbol = (symbolS*) + c_section_symbol(".bss", + H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers), + H_GET_BSS_SIZE(&headers), + 0, /* No relocation for a bss section. */ + 0); /* There are no bss lineno entries */ + + /* FIXME late night before delivery, I don't know why the chain is + broken, but I can guess. So! Let's force them to be knit properly + at this point. */ + +/* as john pointed out, this wasn't right. Instead, we'll check here to + make sure that the list is doubly linked. */ + +#if defined(DEBUG) && defined(SYMBOLS_NEED_BACKPOINTERS) + for (symbolP = symbol_rootP; symbol_next(symbolP); symbolP = symbol_next(symbolP)) { + know(symbolP->sy_next->sy_previous == symbolP); + } /* walk the symbol chain */ +#endif /* DEBUG and SYMBOLS_NEED_BACKPOINTERS */ + symbolP = symbol_rootP; + + if (symbolP) { + while(symbolP) { + /* If the symbol has a tagndx entry, resolve it */ + if(SF_GET_TAGGED(symbolP)) { + SA_SET_SYM_TAGNDX(symbolP, + ((symbolS*)SA_GET_SYM_TAGNDX(symbolP))->sy_number); + } + /* Debug symbol do not need all this rubbish */ + if(!SF_GET_DEBUG(symbolP)) { + symbolS* real_symbolP; + /* L* and C_EFCN symbols never merge. */ + if(!SF_GET_LOCAL(symbolP) && + (real_symbolP = + symbol_find_base(S_GET_NAME(symbolP), DO_NOT_STRIP)) && + real_symbolP != symbolP) { + /* FIXME where do dups come from? xoxorich. */ + /* Move the debug data from the debug symbol to the + real symbol. Do NOT do the oposite (i.e. move from + real symbol to symbol and remove real symbol from the + list.) Because some pointers refer to the real symbol + whereas no pointers refer to the symbol. */ + c_symbol_merge(symbolP, real_symbolP); + /* Replace the current symbol by the real one */ + /* The symbols will never be the last or the first + because : 1st symbol is .file and 3 last symbols are + .text, .data, .bss */ + symbol_remove(real_symbolP, &symbol_rootP, &symbol_lastP); + symbol_insert(real_symbolP, symbolP, &symbol_rootP, &symbol_lastP); + symbol_remove(symbolP, &symbol_rootP, &symbol_lastP); + symbolP = real_symbolP; + } + if(flagseen['R'] && S_IS_DATA(symbolP)) + S_SET_TEXT(symbolP); + + symbolP->sy_value += symbolP->sy_frag->fr_address; + + if(!S_IS_DEFINED(symbolP)) + S_SET_EXTERNAL(symbolP); + else if(S_GET_STORAGE_CLASS(symbolP) == C_NULL) + S_SET_STORAGE_CLASS(symbolP, C_STAT); + + /* Mainly to speed up if not -g */ + if(SF_GET_PROCESS(symbolP)) { + /* Handle the nested blocks auxiliary info. */ + if(S_GET_STORAGE_CLASS(symbolP) == C_BLOCK) { + if(!strcmp(S_GET_NAME(symbolP), ".bb")) + stack_push(block_stack, (char *) &symbolP); + else { /* .eb */ + register symbolS* begin_symbolP; + begin_symbolP = *(symbolS**)stack_pop(block_stack); + if(begin_symbolP == (symbolS*)0) + as_warn("mismatched .eb"); + else + SA_SET_SYM_ENDNDX(begin_symbolP, symbol_number); + } + } + /* If we are able to identify the type of a function, and we + are out of a function (last_functionP == 0) then, the + function symbol will be associated with an auxiliary + entry. */ + if(last_functionP == (symbolS*)0 && + SF_GET_FUNCTION(symbolP)) { + last_functionP = symbolP; + S_SET_NUMBER_AUXILIARY(symbolP, 1); + /* Clobber possible stale .dim information. */ + memset(&symbolP->sy_auxent[0], '\0', sizeof(union auxent)); + } + /* The C_FCN doesn't need any additional information. + I don't even know if this is needed for sdb. But the + standard assembler generates it, so... + */ + if(S_GET_STORAGE_CLASS(symbolP) == C_EFCN) { + if(last_functionP == (symbolS*)0) + as_fatal("C_EFCN symbol out of scope"); + SA_SET_SYM_FSIZE(last_functionP, + (long)(symbolP->sy_value - + last_functionP->sy_value)); + SA_SET_SYM_ENDNDX(last_functionP, symbol_number); + last_functionP = (symbolS*)0; + } + } + } else { + /* First descriptor of a structure must point to the next + slot outside the structure description. */ + if(SF_GET_TAG(symbolP)) + last_tagP = symbolP; + else if(S_GET_STORAGE_CLASS(symbolP) == C_EOS) + /* +2 take in account the current symbol */ + SA_SET_SYM_ENDNDX(last_tagP, symbol_number+2); + } + + /* We must put the external symbols apart. The loader + does not bomb if we do not. But the references in + the endndx field for a .bb symbol are not corrected + if an external symbol is removed between .bb and .be. + I.e in the following case : + [20] .bb endndx = 22 + [21] foo external + [22] .be + ld will move the symbol 21 to the end of the list but + endndx will still be 22 instead of 21. */ + { + register symbolS* thisP = symbolP; + + symbolP = symbol_next(thisP); + /* remove C_EFCN and LOCAL (L...) symbols */ + if (SF_GET_LOCAL(thisP)) { + symbol_remove(thisP, &symbol_rootP, &symbol_lastP); + } else { + if(S_GET_STORAGE_CLASS(thisP) == C_EXT && + !SF_GET_FUNCTION(thisP)) { + /* Remove from the list */ + symbol_remove(thisP, &symbol_rootP, &symbol_lastP); + symbol_clear_list_pointers(thisP); + /* Move at the end of the list */ + if (symbol_extern_lastP == (symbolS*)0) + symbol_externP = thisP; + else + symbol_append(thisP, symbol_extern_lastP); + symbol_extern_lastP = thisP; + } else { + if(SF_GET_STRING(thisP)) { + thisP->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(thisP)) + 1; + } else + thisP->sy_name_offset = 0; + thisP->sy_number = symbol_number; + symbol_number += 1 + S_GET_NUMBER_AUXILIARY(thisP); + } + } + } + } + + /* this actually appends the entire extern chain */ + symbol_append(symbol_externP, symbol_lastP); + symbolP = symbol_externP; + while(symbolP) { + if(SF_GET_STRING(symbolP)) { + symbolP->sy_name_offset = string_byte_count; + string_byte_count += strlen(S_GET_NAME(symbolP)) + 1; + } else + symbolP->sy_name_offset = 0; + symbolP->sy_number = symbol_number; + symbol_number += 1 + S_GET_NUMBER_AUXILIARY(symbolP); + symbolP = symbol_next(symbolP); + } + } + + /* FIXME I'm counting line no's here so we know what to put in the section + headers, and I'm resolving the addresses since I'm not sure how to + do it later. I am NOT resolving the linno's representing functions. + Their symbols need a fileptr pointing to this linno when emitted. + Thus, I resolve them on emit. xoxorich. */ + + for (lineP = lineno_rootP; lineP; lineP = lineP->next) { + if (lineP->line.l_lnno) { + lineP->line.l_addr.l_paddr += ((fragS*)lineP->frag)->fr_address; + } else { + ; + } + text_lineno_number++; + } /* for each line number */ + } /* OBJ_COFF version */ +#elif defined(OBJ_AOUT) | defined(OBJ_BOUT) + { /* OBJ_AOUT version */ + symbolPP = & symbol_rootP; /* -> last symbol chain link. */ + while ((symbolP = *symbolPP) != NULL) + { + if (flagseen['R'] && S_IS_DATA(symbolP)) { + S_SET_TEXT(symbolP); + } /* if pusing data into text */ + + symbolP -> sy_value += 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) +#ifndef VMS /* Under VMS we need to keep local symbols */ + && ( !S_GET_NAME(symbolP) + || S_IS_DEBUG(symbolP) +#ifdef TC_I960 + /* FIXME 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)))) +#endif /* not VMS */ + ) + { +#ifndef VMS + 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. */ +#endif /* not VMS */ + 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", name); + } /* oops. */ + +#ifndef VMS + /* Unhook it from the chain */ + *symbolPP = symbol_next(symbolP); +#endif /* VMS */ + } /* if this symbol should be in the output */ + } /* for each symbol */ + } /* OBJ_AOUT version */ +#else + cant_crawl_symbol_table(); +#endif + H_SET_STRING_SIZE(&headers,string_byte_count); + H_SET_SYMBOL_TABLE_SIZE(&headers, symbol_number); + } /* crawl symbol table */ + +} /* obj_crawl_symbol_chain() */ + +/* end of obj-vms.c */ diff --git a/gas/make-gas.com b/gas/make-gas.com new file mode 100644 index 0000000..96922c4 --- /dev/null +++ b/gas/make-gas.com @@ -0,0 +1,56 @@ +$! Set the def dir to proper place for use in batch. Works for interactive to. +$flnm = f$enviroment("PROCEDURE") ! get current procedure name +$set default 'f$parse(flnm,,,"DEVICE")''f$parse(flnm,,,"DIRECTORY")' +$! +$! Command file to build a GNU assembler on VMS +$! +$! If you are using a version of GCC that supports global constants +$! you should remove the define="const=" from the gcc lines. +$ if "''p1'" .eqs. "LINK" then goto Link +$ gcc/debug/define=("VMS","const=") as.c +$ gcc/debug/define=("VMS", "error=as_fatal","const=") xrealloc.c +$ gcc/debug/define=("VMS", "error=as_fatal","const=") xmalloc.c +$ gcc/debug/define=("VMS", "error=as_fatal","const=") hash.c +$ gcc/debug/define=("VMS","const=") obstack.c +$ gcc/debug/define=("VMS","const=") hex-value.c +$ gcc/debug/define=("VMS","const=") atof-generic.c +$ gcc/debug/define=("VMS","const=") append.c +$ gcc/debug/define=("VMS","const=") messages.c +$ gcc/debug/define=("VMS","const=") expr.c +$ gcc/debug/define=("VMS","const=") app.c +$ gcc/debug/define=("VMS","const=") frags.c +$ gcc/debug/define=("VMS","const=") input-file.c +$ gcc/debug/define=("VMS","const=") input-scrub.c +$ gcc/debug/define=("VMS","const=") output-file.c +$ gcc/debug/define=("VMS","const=") read.c +$ gcc/debug/define=("VMS","const=") subsegs.c +$ gcc/debug/define=("VMS","const=") symbols.c +$ gcc/debug/define=("VMS","const=") write.c +$ gcc/debug/define=("VMS","const=") version.c +$ gcc/debug/define=("VMS","const=") flonum-const.c +$ gcc/debug/define=("VMS","const=") flonum-copy.c +$ gcc/debug/define=("VMS","const=") flonum-mult.c +$ gcc/debug/define=("VMS","const=") strstr.c +$ gcc/debug/define=("VMS","const=") bignum-copy.c +$ gcc/debug/define=("VMS", "error=as_fatal","const=") vax.c +$ gcc/debug/define=("VMS","const=") atof-vax.c +$ write sys$output " If you are building gas to work with the G++ compiler" +$ write sys$output " based upon gcc version 1.37.n or earlier, you should" +$ write sys$output " edit make-gas.com and make the changes indicated in the" +$ write sys$output "comments." +$! For older versions of G++, we need the jsb hack, the HACK_DEC_C_STARTUP +$! enables this. Just use the compilation for vms.c that defines this instead +$! of the other one. +$ gcc/debug/define=("VMS", "error=as_fatal","const=") vms.c +$! gcc/debug/define=("VMS", "error=as_fatal","HACK_DEC_C_STARTUP","const=") vms.c +$ gcc/debug/define=("VMS","const=") vms-dbg.c +$ Link: +$ link/exec=gcc-as sys$input:/opt +! +! Linker options file for GNU assembler +! +as,xrealloc,xmalloc,hash,hex-value,atof-generic,append,messages,expr,app,- +frags,input-file,input-scrub,output-file,read,subsegs,symbols,write,- +version,flonum-const,flonum-copy,flonum-mult,strstr,bignum-copy,- +obstack,vax,atof-vax,vms,vms-dbg,- +gnu_cc:[000000]gcclib/lib,sys$share:vaxcrtl/lib diff --git a/gas/obsolete/gdb-blocks.c b/gas/obsolete/gdb-blocks.c new file mode 100644 index 0000000..15cd347 --- /dev/null +++ b/gas/obsolete/gdb-blocks.c @@ -0,0 +1,289 @@ +/* gdb_block.c - Deal with GDB blocks + 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. */ + +/* + * Implements .gdbblk, .gdbbeg, .gdbend concepts. + * No other modules need to know the details of these concepts. + * + * During assembly, note the addresses of block beginnings and ends. + * Each block has a begin-address, an end-address, a number, and + * a place in the GDB symbol file to place the 2 addresses. + * Block numbers are 0, 1, ... with no gaps. + * + * During assembly, we don't actually know the addresses, so they are + * expressed as {frag-address + offset-in-frag}. + * + * gdb_block_begin () + * Call once before using this package. + * + * gdb_block_beg (number, frag, offset) + * Note a block beginning. + * + * gdb_block_end (number, frag, offset) + * Note a block end. + * + * gdb_block_position (block_number, pos) + * Remember, after assembly, to copy a structure containing + * the beginning and ending addresses of block number + * block_number into the gdb file, starting at position pos. + * + * gdb_block_emit (block_number, where_in_gdb_symbol_file) + * Emit a block begin/end locations to a place in the GDB symbol + * file. + * + * uses: + * xmalloc() + * gdb_alter() + */ + + +#include "as.h" + +/* + * malloc() calls are considered expensive. So ... + * + * We remember blocks by making a tree, and each block number has a leaf. + * The tree is 3 levels, and we don't allocate interior nodes until they + * are needed. Both leaves and interior nodes are allocated in lumps, + * which should save on malloc() calls. Due to the way we break up a + * block number to navigate through the tree, we insist that lumps of + * memory contain a power of 2 items each. Powers of 2 may differ + * for different levels of tree. + */ + +/* + * A block number: + * + * +---------------+---------------+---------------+ + * | | | | + * | Z2-part bits | Z1-part bits | Z0-part bits | + * | | | | + * +---------------+---------------+---------------+ + * + * High order Low order + * + * "Z" is short for "siZe". + */ + +#define LOG_2_Z0 (8) /* How many bits are in Z0 part? */ +#define LOG_2_Z1 (8) /* How many bits are in Z1 part? */ +#define LOG_2_Z2 (8) /* How many bits are in Z2 part? */ + +#define BLOCK_NUMBER_LIMIT (1 << (LOG_2_Z0 + LOG_2_Z1 + LOG_2_Z2)) + /* What is the first block number that is */ + /* "too big"? */ + +struct gdb_block +{ + fragS * begin_frag; + fragS * end_frag; + long int begin_where_in_frag; + long int end_where_in_frag; + long int position; /* In GDB symbols file. */ +}; + +typedef struct gdb_block node_0_T [1 << LOG_2_Z0]; + +typedef node_0_T * node_1_T [1 << LOG_2_Z1]; + +typedef node_1_T * node_2_T [1 << LOG_2_Z2]; + + +static long int highest_block_number_seen; +static node_2_T * root; /* 3 level tree of block locations. */ + +static node_2_T * new_2 (); + + +char * xmalloc(); +void gdb_alter(); + +void +gdb_block_begin () +{ + root = new_2 (); + highest_block_number_seen = -1; +} + +static node_0_T * +new_0 () +{ + register node_0_T * place; + + place = (node_0_T *) xmalloc ((long)sizeof(node_0_T)); + bzero ((char *)place, sizeof(node_0_T)); + return (place); +} + +static node_1_T * +new_1 () +{ + register node_1_T * place; + + place = (node_1_T *) xmalloc ((long)sizeof(node_1_T)); + bzero ((char *)place, sizeof(node_1_T)); + return (place); +} + +static node_2_T * +new_2 () +{ + register node_2_T * place; + + place = (node_2_T *) xmalloc ((long)sizeof(node_2_T)); + bzero ((char *)place, sizeof(node_2_T)); + return (place); +} + +static struct gdb_block * +find (block_number) + register long int block_number; +{ + register node_1_T ** pp_1; + register node_0_T ** pp_0; + register struct gdb_block * b; + register int index0; + register int index1; + register int index2; + +#ifdef SUSPECT + if (block_number >= BLOCK_NUMBER_LIMIT) + { + as_fatal ("gdb_block: Block number = %ld.", block_number); + } +#endif + + index2 = block_number >> (LOG_2_Z0 + LOG_2_Z1); + index1 = block_number >> (LOG_2_Z0) & ((1 << LOG_2_Z1) - 1); + index0 = block_number & ((1 << LOG_2_Z0) - 1); + pp_1 = * root + index2; + if (* pp_1 == 0) + { + * pp_1 = new_1 (); + } + pp_0 = ** pp_1 + index1; + if (* pp_0 == 0) + { + * pp_0 = new_0 (); + } + b = ** pp_0 + index0; + return (b); +} + + +static struct gdb_block * +find_create (block_number) + long int block_number; +{ + if (highest_block_number_seen < block_number) + { + highest_block_number_seen = block_number; + } + return (find (block_number)); +} + +void +gdb_block_beg (block_number, frag, offset) + long int block_number; + fragS * frag; + long int offset; +{ + struct gdb_block * pointer; + + pointer = find_create (block_number); +#ifdef SUSPECT + if (pointer -> begin_frag != 0) + { + as_warn( "Overwriting begin_frag for block # %ld.", block_number ); + } + if (pointer -> begin_where_in_frag != 0) + { + as_warn( "Overwriting begin_where_in_frag for block # %ld.", block_number ); + } +#endif + pointer -> begin_frag = frag; + pointer -> begin_where_in_frag = offset; +} + +void +gdb_block_end (block_number, frag, offset) + long int block_number; + fragS * frag; + long int offset; +{ + struct gdb_block * pointer; + + pointer = find_create (block_number); +#ifdef SUSPECT + if (pointer -> end_frag != 0) + { + as_warn( "Overwriting end_frag for block # %ld.", block_number ); + } + if (pointer -> end_where_in_frag != 0) + { + as_warn( "Overwriting end_where_in_frag for block # %ld.", block_number ); + } +#endif + pointer -> end_frag = frag; + pointer -> end_where_in_frag = offset; +} + +void +gdb_block_position (block_number, pos) + long int block_number; + long int pos; +{ + struct gdb_block * pointer; + + pointer = find_create (block_number); + if (pointer -> position != 0) + { + as_warn( "Overwriting old position %ld. in block #%ld.", + pointer -> position, block_number); + } + pointer -> position = pos; +} + +void +gdb_block_emit () +{ + long int block_number; + struct gdb_block * b; + + for (block_number = 0; + block_number <= highest_block_number_seen; + block_number ++) + { + b = find (block_number); + if (b -> begin_frag) + { + gdb_alter (b -> position, + (long int) + (b -> begin_frag -> fr_address + b -> begin_where_in_frag)); + } + if (b -> end_frag) + { + gdb_alter (b -> position + sizeof( long int ), + (long int) + (b -> end_frag -> fr_address + b -> end_where_in_frag)); + } + } +} + +/* end: gdb_block.c */ diff --git a/gas/obsolete/gdb-file.c b/gas/obsolete/gdb-file.c new file mode 100644 index 0000000..42938ad --- /dev/null +++ b/gas/obsolete/gdb-file.c @@ -0,0 +1,80 @@ +/* gdb_file.c -o/s specific- + Copyright (C) 1987 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +static long file_len; +static FILE *file; +extern long get_len(); + + +void +gdb_file_begin () +{ +} + +void +gdb_file_end() +{ +} + +long int /* Open file, return size. 0: failed. */ +gdb_file_size (filename) +char *filename; +{ + struct stat stat_buf; + void as_perror(); + + file= fopen (filename, "r"); + if (file == (FILE *)NULL) + { + as_perror ("Can't read GDB symbolic information file", filename); + file_len=0; + } else { + (void)fstat (fileno(file), &stat_buf); + file_len=stat_buf . st_size; + } + return ((long int)file_len ); +} + +void /* Read the file, don't return if failed. */ +gdb_file_read (buffer, filename) + char * buffer; + char * filename; +{ + register off_t size_wanted; + void as_perror(); + + size_wanted = file_len; + if (fread (buffer, size_wanted, 1, file) != 1) + { + as_perror ("Can't read GDB symbolic info file", filename); + as_fatal ("Failed to read %ld. chars of GDB symbolic information", + size_wanted); + } + if (fclose(file)==EOF) + { + as_perror ("Can't close GDB symbolic info file", filename); + as_fatal ("I quit in disgust"); + } +} + +/* end: gdb_file.c */ diff --git a/gas/obsolete/gdb-lines.c b/gas/obsolete/gdb-lines.c new file mode 100644 index 0000000..6af0c42 --- /dev/null +++ b/gas/obsolete/gdb-lines.c @@ -0,0 +1,241 @@ +/* gdb-lines.c -- Deal with source lines for GDB format + 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. */ + +#include "as.h" +#include "obstack.h" +#include "frags.h" + +/* This is a souce file that we're storing .gdbline information about */ +/* .gdbline refers to files by numbers. We keep a linked list of them + We store a list of vectors for each file. Each element of the vector + contains a line-number, a frag, and an offset within the frag. */ +struct g_line_file { + int gdb_line_file_file_number; /* fnum */ + int gdb_line_file_number_of_vectors; /* nv */ + long gdb_line_table_offset; /* taboff */ + struct g_line_vector *gdb_line_file_vectors; /* vec */ + struct g_line_file *gdb_line_file_next_file; /* nfile */ +}; + +/* In order to save on space (We expect there to be LOTS of lines), we + store line-number/address pairs in bunches of MAX_LINES_PER_VECTOR + (originally fifty). Each vector descriptor contains + + gdb_line_number_of_lines the number of line-number/address pairs + actually in this vector. + gdb_line_lines The actual vector. + + gdb_line_next_vector The next vector descriptor in the linked list. + */ +struct g_line_vector { + int gdb_line_number_of_lines; /* nlines */ + struct g_line *gdb_line_lines; /* lines */ + struct g_line_vector *gdb_line_next_vector; /* nvec */ +}; + + +/* A .gdbline wants to store a line-number/address pair. Unfortunatly, we + don't know addresses yet, so we store frag/offset which we can use to + generate the address at write-out time. */ +struct g_line { + int gdb_line_line_number; /* lno */ + fragS *gdb_line_frag; /* lfrag */ + int gdb_line_offset; /* loff */ +}; + + +/* The following is stolen from (gdb's? (or is it gcc's?) symseg.h file. + These structures describe the format for the line# symbolic info in + the gdb symbolic info file. This info is not particularly useful, + except to show what we're writing into. . . */ + +/* Source-file information. + This describes the relation between source files and line numbers + and addresses in the program text. */ + +struct sourcevector +{ + int length; /* Number of source files described */ + struct source *source[1]; /* Descriptions of the files */ +}; + +/* Line number and address of one line. */ + +struct line +{ + int linenum; + int address; +}; + +/* All the information on one source file. */ + +struct source +{ + char *name; /* Name of file */ + int nlines; /* Number of lines that follow */ + struct line lines[1]; /* Information on each line */ +}; + +/* End of text from symseg.h */ + +struct g_line_file *first_file; + +struct g_line_file *add_file(); +struct g_line_vector *add_vector(); + +#define MAX_LINES_PER_VECTOR 50 /* lpv */ + +/* We've been told that the current address corresponds to line LINENO in + file FILE_NUMBER */ +void +gdb_line(file_number,lineno) +int file_number; +int lineno; +{ + struct g_line_file *f; + struct g_line_vector *v; + struct g_line *line; + + for(f=first_file;f;f=f->gdb_line_file_next_file) + if(f->gdb_line_file_file_number==file_number) + break; + if(!f) f=add_file(file_number); + v=f->gdb_line_file_vectors; + if(!v || v->gdb_line_number_of_lines==MAX_LINES_PER_VECTOR) + v=add_vector(f); + line= &(v->gdb_line_lines)[v->gdb_line_number_of_lines]; + v->gdb_line_number_of_lines++; + line->gdb_line_line_number=lineno; + line->gdb_line_frag= frag_now; + line->gdb_line_offset=obstack_next_free(&frags)-frag_now->fr_literal; +} + +/* We've been told where to store the .line table for file FILE_NUMBER */ +void +gdb_line_tab(file_number,offset) +int file_number; +int offset; +{ + struct g_line_file *f; + + for(f=first_file;f;f=f->gdb_line_file_next_file) + if(f->gdb_line_file_file_number==file_number) + break; + if(!f) f=add_file(file_number); + if(f->gdb_line_table_offset) + as_warn("Ignoring duplicate .linetab for file %d",file_number); + else + f->gdb_line_table_offset=offset; +} + +/* We've got a file (FILE_NUMBER) that we haven't heard about before. Create + an entry for it, etc. . . */ +struct g_line_file * +add_file(file_number) +{ + struct g_line_file *f; + + f=(struct g_line_file *)xmalloc(sizeof(struct g_line_file)); + f->gdb_line_file_file_number=file_number; + f->gdb_line_table_offset = 0; + f->gdb_line_file_number_of_vectors=0; + f->gdb_line_file_vectors=(struct g_line_vector *)0; + f->gdb_line_file_next_file=first_file; + first_file=f; + return f; +} + +/* The last vector for file F is full. Allocate a new one. */ +struct g_line_vector * +add_vector(f) +struct g_line_file *f; +{ + struct g_line_vector *tmp_vec; + + f->gdb_line_file_number_of_vectors++; + tmp_vec=(struct g_line_vector *)xmalloc(sizeof(struct g_line_vector)); + tmp_vec->gdb_line_number_of_lines=0; + tmp_vec->gdb_line_lines=(struct g_line *)xmalloc(MAX_LINES_PER_VECTOR*sizeof(struct g_line)); + tmp_vec->gdb_line_next_vector=f->gdb_line_file_vectors; + f->gdb_line_file_vectors=tmp_vec; + return tmp_vec; +} + +/* All done. Time to write the stuff out. This should be fun. */ +void +gdb_lines_emit() +{ + struct g_line_file *f; + struct g_line_vector *v,*old_v,*v_tmp; + struct g_line *current_line_pointer; /* lp */ + int n; + int previous_line_number; + long int current_gdb_segment_pos; + unsigned int number_of_things_in_table; + + for(f=first_file;f;f=f->gdb_line_file_next_file) { + if(!f->gdb_line_table_offset) { + as_warn("No .gdblinetab given for file %d. Ignoring .gdbline(s) for it."); + continue; + } + + /* Reverse the linked list of vectors. Since we built it + last entry first, this puts the first entry at the start + of the list. Thus we can manage to put out low line #s + at the start of the table. . .*/ + v_tmp=0; + old_v=0; + for(v=f->gdb_line_file_vectors;v;v=v_tmp) { + v_tmp=v->gdb_line_next_vector; + v->gdb_line_next_vector=old_v; + old_v=v; + } + f->gdb_line_file_vectors=old_v; + + /* Start putting stuff at the beginning of the table */ + current_gdb_segment_pos=f->gdb_line_table_offset+sizeof(long int); + previous_line_number = -2; + number_of_things_in_table = 0; + + /* For every vector in the table: */ + for(v=f->gdb_line_file_vectors;v;v=v->gdb_line_next_vector) { + current_line_pointer=v->gdb_line_lines; + + /* For every element of every vector */ + for(n=v->gdb_line_number_of_lines;n;n--) { + + if(current_line_pointer->gdb_line_line_number != previous_line_number + 1) { + /* Write out the line number */ + gdb_alter(current_gdb_segment_pos, -(current_line_pointer->gdb_line_line_number)); + current_gdb_segment_pos+=sizeof(long int); + number_of_things_in_table++; + } + previous_line_number = current_line_pointer->gdb_line_line_number; + + /* And write out the address */ + gdb_alter(current_gdb_segment_pos,current_line_pointer->gdb_line_frag->fr_address+current_line_pointer->gdb_line_offset); + current_gdb_segment_pos+=sizeof(long int); + number_of_things_in_table++; + + current_line_pointer++; + } + } + gdb_alter(f->gdb_line_table_offset,number_of_things_in_table); + } +} diff --git a/gas/obsolete/gdb-symbols.c b/gas/obsolete/gdb-symbols.c new file mode 100644 index 0000000..8bd8f7d --- /dev/null +++ b/gas/obsolete/gdb-symbols.c @@ -0,0 +1,129 @@ +/* gdb_symbols.c - Deal with symbols for GDB format + 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. */ + +/* + * During assembly, note requests to place symbol values in the GDB + * symbol file. When symbol values are known and the symbol file is + * in memory, place the symbol values in the memory image of the file. + * + * This has static data: it is not data_sharable. + * + * gdb_symbols_begin () + * Call once before using this package. + * + * gdb_symbols_fixup (symbolP, offset_in_file) + * Remember to put the value of a symbol into the GDB file. + * + * gdb_symbols_emit () + * Perform all the symbol fixups. + * + * uses: + * xmalloc() + * gdb_alter() + */ + +#include "as.h" +#include "struc-symbol.h" + +#define SYM_GROUP (100) /* We allocate storage in lumps this big. */ + + +struct gdb_symbol /* 1 fixup request. */ +{ + symbolS * gs_symbol; + long int gs_offset; /* Where in GDB symbol file. */ +}; +typedef struct gdb_symbol gdb_symbolS; + +struct symbol_fixup_group +{ + struct symbol_fixup_group * sfg_next; + gdb_symbolS sfg_item [SYM_GROUP]; +}; +typedef struct symbol_fixup_group symbol_fixup_groupS; + +static symbol_fixup_groupS * root; +static short int used; /* # of last slot used. */ + /* Counts down from SYM_GROUP. */ + +static symbol_fixup_groupS * /* Make storage for some more reminders. */ +new_sfg () +{ + symbol_fixup_groupS * newP; + char * xmalloc(); + + newP = (symbol_fixup_groupS *) xmalloc ((long)sizeof(symbol_fixup_groupS)); + newP -> sfg_next = root; + used = SYM_GROUP; + root = newP; + return (newP); +} + + +void +gdb_symbols_begin () +{ + root = 0; + (void)new_sfg (); +} + + +void /* Build a reminder to put a symbol value */ +gdb_symbols_fixup (sy, offset) /* into the GDB symbol file. */ + symbolS * sy; /* Which symbol. */ + long int offset; /* Where in GDB symbol file. */ +{ + register symbol_fixup_groupS * p; + register gdb_symbolS * q; + + p = root; + know( used >= 0 ); + if ( used == 0) + { + p = new_sfg (); + } + q = p -> sfg_item + -- used; + q -> gs_symbol = sy; + q -> gs_offset = offset; +} + +void +gdb_symbols_emit () /* Append GDB symbols to object file. */ +{ + symbol_fixup_groupS * sfgP; + void gdb_alter(); + + for (sfgP = root; sfgP; sfgP = sfgP -> sfg_next) + { + register gdb_symbolS * gsP; + register gdb_symbolS * limit; + + limit = sfgP -> sfg_item + + (sfgP -> sfg_next ? 0 : used); + for (gsP = sfgP -> sfg_item + SYM_GROUP - 1; + gsP >= limit; + gsP --) + { + gdb_alter (gsP -> gs_offset, + (long int) gsP -> gs_symbol -> sy_value); + } + } +} + +/* end: gdb_symbols.c */ diff --git a/gas/obsolete/gdb.c b/gas/obsolete/gdb.c new file mode 100644 index 0000000..4896e2e --- /dev/null +++ b/gas/obsolete/gdb.c @@ -0,0 +1,110 @@ +/* gdb.c -as supports gdb- + 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 code is independent of the underlying operating system. */ + +#include "as.h" + +static long int size; /* 0 or size of GDB symbol file. */ +static char * where; /* Where we put symbol file in memory. */ + +#define SUSPECT /* JF */ + +long int /* 0 means don't call gdb_... routines */ +gdb_begin (filename) /* because we failed to establish file */ + /* in memory. */ + char * filename; /* NULL: we have nothing to do. */ +{ + long int gdb_file_size(); + char * xmalloc(); + void gdb_file_begin(); + void gdb_file_read(); + void gdb_block_begin(); + void gdb_symbols_begin(); + + gdb_file_begin(); + size = 0; + if (filename && (size = gdb_file_size (filename))) + { + where = xmalloc( (long) size ); + gdb_file_read (where, filename); /* Read, then close file. */ + gdb_block_begin(); + gdb_symbols_begin(); + } + return (size); +} + +void +gdb_end() +{ + void gdb_file_end(); + + gdb_file_end(); +} + +void +gdb_emit (filename) /* Append GDB symbols to object file. */ +char * filename; +{ + void gdb_block_emit(); + void gdb_symbols_emit(); + void gdb_lines_emit(); + void output_file_append(); + + gdb_block_emit (); + gdb_symbols_emit (); + gdb_lines_emit(); + output_file_append (where, size, filename); +} + + + +/* + Notes: We overwrite what was there. + We assume all overwrites are 4-char numbers. +*/ + +void +gdb_alter (offset, value) /* put value into GDB file + offset. */ + long int offset; + long int value; +{ + void md_number_to_chars(); + +#ifdef SUSPECT + if (offset > size - sizeof(long int) || offset < 0) + { + as_warn( "gdb_alter: offset=%d. size=%ld.\n", offset, size ); + return; + } +#endif + +#ifdef B_OUT + /* Symbol info will be used on the host machine only (only executable + * code is actually downloaded to the i80960). Therefore, leave it + * in host byte order. + */ + + *(long int *)(where + offset) = value; +#else + md_number_to_chars (where + offset, value, 4); +#endif +} + +/* end: gdb.c */ diff --git a/gas/ver960.c b/gas/ver960.c new file mode 100644 index 0000000..fee9000 --- /dev/null +++ b/gas/ver960.c @@ -0,0 +1 @@ +char gas960_ver[]= "gas960 1.2, Fri Nov 30 03:01:56 PST 1990"; diff --git a/gas/version.c b/gas/version.c new file mode 100644 index 0000000..6a46f45 --- /dev/null +++ b/gas/version.c @@ -0,0 +1,23 @@ +#if defined(__STDC__) || defined(const) +const +#endif +char version_string[] = "GNU assembler version 1.38.1 (Cygnus Support pre-release)\n"; + +/* DO NOT PUT COMMENTS ABOUT CHANGES IN THIS FILE. + + This file exists only to define `version_string'. + + Log changes in ChangeLog. The easiest way to do this is with + the Emacs command `add-change-log-entry'. If you don't use Emacs, + add entries of the form: + +Thu Jan 1 00:00:00 1970 Dennis Ritchie (dmr at alice) + + * universe.c (temporal_reality): Began Time. +*/ + +#ifdef VMS +dummy3() +{ +} +#endif |