From: DALL@hfrd.dsto.GOV.AU
Subject: GAS 1.38.1 NS32K corrections
Organization: Association for the Prevention of Polar Bears and Kangaroos
Date: Thu, 19 Nov 1992 01:07:30 GMT

The patches at the end of this message fix the following problems
in GAS 1.38.1 for the ns32000 processors.

The changed files are:

Makefile:
--------

Add a rule to override the SunOs default rule. This is because SunOs
4.1.1 make adds arguments which gcc1 (which I use to build gas)
doesn't recognize. Not needed if you don't use a sun or you use a newer
gcc.

Add some stuff to install gas in my cross tools directory (you
probably don't want this).

Use VPATH and -I options to compile in a shadow directory. I like this
so it is easy to keep the FSF distribution clean.

a.out.gnu.h:
-----------

Make r_disp 2 bits big. This is *essential* (r_disp needs to take on 3
values) but for some reason the change never makes it into the
distribution no matter how often I report it.

write.c, frags.c, ns32k.c, as.h:
-------------------------------

In the 32k processors, pc relatative operands are relative to the
start of the instruction not the start of the operand which gas
normally assumes.  Gas attempted to fix this with a pcrel_adjust field
in the frags. The problem is, if there are two pc relative operands,
the first one can change in size during the relax phase and then the
pcrel_adjust for the second operand will be wrong. Gcc1 never generated
such code, but gcc2 does.

To fix this I introduced an adjustment to the adjustment --
pcrel_adjust_adjust. This starts out as zero, but gets changed if the
operand moves relative to the start of the instruction during the
relax phase. The relax phase needs to know when a new instruction
has been started and normally frags don't contain that information.
An extra field "first" has been added to the frag structure. First
is true whenever a frag contains an opcode. Possibly "first" is not
the best name.

This stuff is mind boggling (at least, it made my mind boggle), and I
agree it is not that clean but it is hard to see how else to support
the ns32k without an extensive re-think of gas.  It has been
extensively tested. Mach (MK and UX) and bash have been compiled and
tested using these changes.

ns32k.c:
-------

As well as the above changes for the pc relative stuff, a bug which
sometimes caused gas to core dump because it did "bzero(memP,8)"
instead of "bzero(memP,size)" has been fixed. Obviously this escaped
detection because it rarely actually damaged anything.

Also, in ns32k.c, the checks for valid size of displacements is wrong.
The maximum displacement is 30 bits signed twos complement or [-2**29,
+2**29 - 1]. For some reason people (including me in the past) get
this wrong.


*** ../dist/Makefile	Fri Oct 19 05:56:42 1990
--- Makefile	Wed Nov 18 23:19:14 1992
***************
*** 20,31 ****
  # This makefile may be used to make the VAX, 68020, 80386, 
  # SPARC, ns32k, or i860 assembler(s).
  
! BINDIR = /usr/local/bin
! #CC=gcc
  
  # If you are on a BSD system, un-comment the next two lines, and comment out
  # the lines for SystemV and HPUX below
! G0 = -g  -I. #-O -Wall
  LDFLAGS = $(CFLAGS)
  #
  # To compile gas on a System Five machine, comment out the two lines above
--- 20,37 ----
  # This makefile may be used to make the VAX, 68020, 80386, 
  # SPARC, ns32k, or i860 assembler(s).
  
! .c.o:
! 	$(CC) -c $(CFLAGS) $<
  
+ BINDIR = /usr/local/cross-tools/pc532-mach/bin
+ BINDIR1 = /usr/local/cross-tools/bin
+ VPATH = .:../dist
+ 
+ CC=gcc
+ 
  # If you are on a BSD system, un-comment the next two lines, and comment out
  # the lines for SystemV and HPUX below
! G0 = -g -I- -I. -I../dist -O #-Wall
  LDFLAGS = $(CFLAGS)
  #
  # To compile gas on a System Five machine, comment out the two lines above
***************
*** 113,120 ****
  O3 = # -Dm68851
  O4 = # -DEXEC_VERSION=1
  O5 = # -DSIGTY=void
! O6 = # -DNS32532
! O6 = # -DNS32381
  O7 = # -DDOT_LABEL_PREFIX
  O8 = # -DSEQUENT_COMPATABILITY
  O9 = # -DREGISTER_PREFIX=\'%\'
--- 119,125 ----
  O3 = # -Dm68851
  O4 = # -DEXEC_VERSION=1
  O5 = # -DSIGTY=void
! O6 =  -DNS32532 -DNS32381
  O7 = # -DDOT_LABEL_PREFIX
  O8 = # -DSEQUENT_COMPATABILITY
  O9 = # -DREGISTER_PREFIX=\'%\'
***************
*** 131,137 ****
  #
  # 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
--- 136,142 ----
  #
  # 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
***************
*** 143,149 ****
  #
  # 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
--- 148,154 ----
  #
  # 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
***************
*** 222,232 ****
  	$(CC) $(CFLAGS) $(OPTIONS) -c ns32k.c
  
  write-ns32k.o:	write.c
! 	$(CC) -c -DNS32K $(CFLAGS) write.c
  	mv write.o write-ns32k.o
  
! read-ns32k.o:
! 	$(CC) -c -DNS32K $(CFLAGS) read.c
  	mv read.o read-ns32k.o
  
  a32k: $a $w
--- 227,237 ----
  	$(CC) $(CFLAGS) $(OPTIONS) -c ns32k.c
  
  write-ns32k.o:	write.c
! 	$(CC) -c -DNS32K $(CFLAGS) $?
  	mv write.o write-ns32k.o
  
! read-ns32k.o:	read.c
! 	$(CC) -c -DNS32K $(CFLAGS) $?
  	mv read.o read-ns32k.o
  
  a32k: $a $w
***************
*** 319,325 ****
  	rm -f a avax a68 a386 a32k asparc $a $v $w $x $y $z a core gmon.out bugs a.out
  
  install:	a
! 	cp a $(BINDIR)/gas
  
  
  # General .o-->.h dependencies
--- 324,333 ----
  	rm -f a avax a68 a386 a32k asparc $a $v $w $x $y $z a core gmon.out bugs a.out
  
  install:	a
! 	cp a $(BINDIR)/as
! 	strip $(BINDIR)/as
! 	-rm  $(BINDIR1)/as532
! 	ln $(BINDIR)/as $(BINDIR1)/as532
  
  
  # General .o-->.h dependencies
*** ../dist/a.out.gnu.h	Tue Jul 17 06:30:50 1990
--- a.out.gnu.h	Tue Jun  9 00:51:20 1992
***************
*** 249,256 ****
       it is desirable to clear them.  */
  #ifdef NS32K
    unsigned r_bsr:1;
!   unsigned r_disp:1;
!   unsigned r_pad:2;
  #else
    unsigned int r_pad:4;
  #endif
--- 249,256 ----
       it is desirable to clear them.  */
  #ifdef NS32K
    unsigned r_bsr:1;
!   unsigned r_disp:2;
!   unsigned r_pad:1;
  #else
    unsigned int r_pad:4;
  #endif
*** ../dist/write.c	Fri Oct 12 01:56:15 1990
--- write.c	Mon Nov 16 22:41:32 1992
***************
*** 709,714 ****
--- 709,718 ----
    /* register relax_addressT	old_address; JF unused */
    /* register relax_addressT	new_address; JF unused */
  
+ #ifdef NS32K
+   int pcrel_adjust_adjust;
+ #endif
+ 
    know( segment_type == SEG_DATA || segment_type == SEG_TEXT );
  
    /* In case md_estimate_size_before_relax() wants to make fixSs. */
***************
*** 718,727 ****
--- 722,739 ----
     * For each frag in segment: count and store  (a 1st guess of) fr_address.
     */
    address = 0;
+ #ifdef NS32K
+   pcrel_adjust_adjust = 0;
+ #endif
+ 
    for ( fragP = segment_frag_root;   fragP;   fragP = fragP -> fr_next )
      {
        fragP -> fr_address = address;
        address += fragP -> fr_fix;
+ #ifdef NS32K
+       if (fragP->fr_first)
+ 	pcrel_adjust_adjust = 0;
+ #endif
        switch (fragP -> fr_type)
  	{
  	case rs_fill:
***************
*** 739,746 ****
  	  break;
  
  	case rs_machine_dependent:
! 	  address += md_estimate_size_before_relax
! 	    (fragP, seg_N_TYPE [(int) segment_type]);
  	  break;
  
  #ifndef WORKING_DOT_WORD
--- 751,765 ----
  	  break;
  
  	case rs_machine_dependent:
! 	  {
! 	    int delta = md_estimate_size_before_relax
! 	      (fragP, seg_N_TYPE [(int) segment_type]);
! 	    address += delta;
! #ifdef NS32K
! 	    fragP->fr_pcrel_adjust_adjust = pcrel_adjust_adjust;
! 	    pcrel_adjust_adjust += delta;
! #endif
! 	  }
  	  break;
  
  #ifndef WORKING_DOT_WORD
***************
*** 771,776 ****
--- 790,798 ----
  
      do
        {
+ #ifdef NS32K
+ 	int pcrel_stretch = 0;
+ #endif
  	stretch = stretched = 0;
  	for (fragP = segment_frag_root;  fragP;  fragP = fragP -> fr_next)
  	  {
***************
*** 787,792 ****
--- 809,820 ----
  	    address = fragP -> fr_address += stretch;
  	    symbolP = fragP -> fr_symbol;
  	    offset = fragP -> fr_offset;
+ #ifdef NS32K
+ 	    if (fragP->fr_first)
+ 	      pcrel_stretch = stretch;
+ 	    fragP->fr_pcrel_adjust_adjust += (stretch - pcrel_stretch);
+ #endif
+ 
  	    /* var = fragP -> fr_var; */
  	    switch (fragP -> fr_type)
  	      {
***************
*** 923,929 ****
  		   * else we'll put this inside #ifdef NS32K ... #endif
  		   */
  #ifdef NS32K
! 		  aim += fragP->fr_pcrel_adjust;
  #endif
  
  		  if (aim < 0)
--- 951,957 ----
  		   * else we'll put this inside #ifdef NS32K ... #endif
  		   */
  #ifdef NS32K
! 		  aim += fragP->fr_pcrel_adjust + fragP->fr_pcrel_adjust_adjust;
  #endif
  
  		  if (aim < 0)
***************
*** 1166,1174 ****
  #endif
  	  break;
  	case 1:
  	  md_number_to_disp (place,
! 			     fixP->fx_pcrel ? add_number+fixP->fx_pcrel_adjust:add_number,
  			     size);
  	  break;
  	case 2: /* fix requested for .long .word etc */
  	  md_number_to_chars (place, add_number, size);
--- 1194,1209 ----
  #endif
  	  break;
  	case 1:
+ #ifdef NS32K
  	  md_number_to_disp (place,
! 			     fixP->fx_pcrel ? add_number+fixP->fx_pcrel_adjust
! 			     + fragP->fr_pcrel_adjust_adjust:add_number,
  			     size);
+ #else
+ 	  md_number_to_disp (place,
+ 			     fixP->fx_pcrel ? add_number+fixP->fx_pcrel_adjust,
+ 			     size);
+ #endif
  	  break;
  	case 2: /* fix requested for .long .word etc */
  	  md_number_to_chars (place, add_number, size);
*** ../dist/frags.c	Fri Aug 18 05:23:21 1989
--- frags.c	Wed Oct  7 00:56:55 1992
***************
*** 36,42 ****
--- 36,44 ----
  	rs_fill,		/* fr_type */
  	0,			/* fr_subtype */
  	0,			/* fr_pcrel_adjust */
+         0,			/* fr_pcrel_adjust_adjust */
  	0,			/* fr_bsr */
+ 	0,			/* fr_first */
  	0			/* fr_literal [0] */
  };
  
***************
*** 52,58 ****
--- 54,62 ----
  	rs_fill,		/* fr_type */
  	0,			/* fr_subtype */
  	0,			/* fr_pcrel_adjust */
+         0,			/* fr_pcrel_adjust_adjust */
  	0,			/* fr_bsr */
+ 	0,			/* fr_first */
  	0			/* fr_literal [0] */
  };
  
***************
*** 213,219 ****
--- 217,225 ----
      frag_now->fr_opcode = opcode;
      /* default these to zero. */
      frag_now->fr_pcrel_adjust = 0;
+     frag_now->fr_pcrel_adjust = 0;
      frag_now->fr_bsr = 0;
+     frag_now->fr_first = 0;
      frag_new (max_chars);
      return (retval);
  }				/* frag_var() */
***************
*** 228,234 ****
   */
  
  char   *
! frag_variant (type, max_chars, var, subtype, symbol, offset, opcode, pcrel_adjust,bsr)
       relax_stateT	 type;
       int		 max_chars;
       int		 var;
--- 234,240 ----
   */
  
  char   *
! frag_variant (type, max_chars, var, subtype, symbol, offset, opcode, pcrel_adjust,bsr, first)
       relax_stateT	 type;
       int		 max_chars;
       int		 var;
***************
*** 238,243 ****
--- 244,250 ----
       char		*opcode;
       char		 pcrel_adjust;
       char		 bsr;
+      char		 first;
  {
      register char  *retval;
  
***************
*** 252,257 ****
--- 259,265 ----
      frag_now->fr_opcode = opcode;
      frag_now->fr_pcrel_adjust = pcrel_adjust;
      frag_now->fr_bsr = bsr;
+     frag_now->fr_first = first;
      frag_new (max_chars);
      return (retval);
  }				/* frag_variant() */
*** ../dist/ns32k.c	Sat Oct 27 05:44:08 1990
--- ns32k.c	Wed Nov 18 23:08:14 1992
***************
*** 1019,1024 ****
--- 1019,1027 ----
    register char type;
    register char size = 0;
    int	size_so_far=0; /* used to calculate pcrel_adjust */
+   char first = 1;		/* true until after the first frag of this
+ 				 * instruction has been done
+ 				 */
  
      rem_size=iif.instr_size;
      memP=frag_more(iif.instr_size); /* make sure we have enough bytes for instruction */
***************
*** 1033,1039 ****
  	    iif.iifP[i].bit_fixP->fx_bit_base=(long)inst_opcode;
  	  }
  	case 8: /* bignum or doublefloat */
! 	  bzero (memP,8);
  	case 1:case 2:case 3:case 4:/* the final size in objectmemory is known */
  	  j=(unsigned long)iif.iifP[i].bit_fixP;
  	  switch (type) {
--- 1036,1042 ----
  	    iif.iifP[i].bit_fixP->fx_bit_base=(long)inst_opcode;
  	  }
  	case 8: /* bignum or doublefloat */
! 	  bzero (memP,size);	/* size could be 0 if we fell through to here */
  	case 1:case 2:case 3:case 4:/* the final size in objectmemory is known */
  	  j=(unsigned long)iif.iifP[i].bit_fixP;
  	  switch (type) {
***************
*** 1180,1187 ****
  				   exprP.X_add_symbol,
  				   exprP.X_add_number,
  				   (char*)inst_opcode,
! 				   (char)size_so_far, /*iif.iifP[i].pcrel_adjust);*/
! 		                   iif.iifP[i].bsr); /* sequent linker hack */
  		rem_size-=4;
  		if (rem_size>0) {
  		  memP=frag_more(rem_size);
--- 1183,1198 ----
  				   exprP.X_add_symbol,
  				   exprP.X_add_number,
  				   (char*)inst_opcode,
! 				   (char) size_so_far, /*iif.iifP[i].pcrel_adjust);*/
! 		                   iif.iifP[i].bsr,  /* sequent linker hack */
! 				   first /* True for first frag in inst. */
! 				   );
! 		first = 0;
! 
! 		/* Size is used to update "size_so_far" which is needed to
! 		 * get the next operand right if it is PC relative. -- IWD
! 		 */ 
! 		size = 0;
  		rem_size-=4;
  		if (rem_size>0) {
  		  memP=frag_more(rem_size);
***************
*** 1196,1205 ****
  		if (-8192<=exprP.X_add_number && exprP.X_add_number<=8191) {
  		  size=2;
  		} else {
! 		  if (-0x1f000000<=exprP.X_add_number &&
  		      exprP.X_add_number<=0x1fffffff)
- 		  /* if (-0x40000000<=exprP.X_add_number &&
- 		      exprP.X_add_number<=0x3fffffff) */
  		  {
  		    size=4;
  		  } else {
--- 1207,1214 ----
  		if (-8192<=exprP.X_add_number && exprP.X_add_number<=8191) {
  		  size=2;
  		} else {
! 		  if (-0x20000000<=exprP.X_add_number &&
  		      exprP.X_add_number<=0x1fffffff)
  		  {
  		    size=4;
  		  } else {
***************
*** 1365,1372 ****
      *buf++=val;
      break;
    case 4:
!     if (val < -0x1f000000 || val >= 0x20000000)
!     /* if (val < -0x20000000 || val >= 0x20000000) */
        as_warn("Double word displacement out of range");
      val|=0xc0000000;
  #ifdef SHOW_NUM
--- 1374,1380 ----
      *buf++=val;
      break;
    case 4:
!     if (val < -0x20000000 || val >= 0x20000000)
        as_warn("Double word displacement out of range");
      val|=0xc0000000;
  #ifdef SHOW_NUM
***************
*** 1563,1569 ****
  register fragS *fragP;
  {
    long disp;
!   long ext;
  
    /* Address in gas core of the place to store the displacement.  */
    register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal;
--- 1571,1577 ----
  register fragS *fragP;
  {
    long disp;
!   long ext = 0;
  
    /* Address in gas core of the place to store the displacement.  */
    register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal;
***************
*** 1574,1580 ****
  
    /* The displacement of the address, from current location.  */
    disp = (fragP->fr_symbol->sy_value + fragP->fr_offset) - object_address;
!   disp+= fragP->fr_pcrel_adjust;
  
    switch(fragP->fr_subtype) {
    case IND(BRANCH,BYTE):
--- 1582,1588 ----
  
    /* The displacement of the address, from current location.  */
    disp = (fragP->fr_symbol->sy_value + fragP->fr_offset) - object_address;
!   disp+= fragP->fr_pcrel_adjust + fragP->fr_pcrel_adjust_adjust;
  
    switch(fragP->fr_subtype) {
    case IND(BRANCH,BYTE):
*** ../dist/xmalloc.c	Thu Mar  2 09:18:34 1989
--- xmalloc.c	Mon Jun 15 22:24:58 1992
***************
*** 50,56 ****
    char *	malloc();
    void	error();
  
!   if ( ! (retval = malloc ((unsigned)n)) )
      {
        error("virtual memory exceeded");
      }
--- 50,60 ----
    char *	malloc();
    void	error();
  
!   if ( ! (retval = malloc ((unsigned)n
! #if defined(sun) && defined(sparc)
! 			   + 1
! #endif
! 			   )) )
      {
        error("virtual memory exceeded");
      }
*** ../dist/as.h	Fri Oct 12 01:56:18 1990
--- as.h	Tue Oct  6 23:52:26 1992
***************
*** 250,256 ****
--- 250,258 ----
  	relax_substateT	fr_subtype;
  		/* These are needed only on the NS32K machines */
  	char	fr_pcrel_adjust;
+ 	char	fr_pcrel_adjust_adjust;
  	char	fr_bsr;
+ 	char	fr_first;
  	char	fr_literal [1];	/* Chars begin here. */
  				/* One day we will compile fr_literal[0]. */
  };