This is the mail archive of the gas2@sourceware.cygnus.com mailing list for the gas2 project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Inconsistent behaviour (in resolve_symbol_value?)


   Date: Mon, 05 Aug 1996 16:02:35 +0100
   From: Richard Earnshaw <rearnsha@armltd.co.uk>

   The problem seems to be the code in resolve_symbol_value that handles
   various binary operations.  I'm not sure what the code is trying to check
   for so I'm not sure what the fix should be.  Both 'if' clauses involve
   checks for undefined sections, but the cases are very specific.  Further,
   after the logical operation has been performed the type of the node is
   changed to O_constant, so it is no-longer possible to recover the
   operation in the back end.


That code doesn't really make any sense to me either, even though I
wrote it.

I think I'll apply this patch.  It requires that both operands of an
arithmetic operator be absolute, except in the special cases of adding
or subtracting a constant, or subtracting two symbols in the same
section.  Please let me know if this seems to have any problems.

Ian

Index: symbols.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gas/symbols.c,v
retrieving revision 1.86
diff -u -r1.86 symbols.c
--- symbols.c	1996/07/26 15:58:57	1.86
+++ symbols.c	1996/08/07 19:32:08
@@ -639,7 +639,35 @@
 
       symp->sy_resolving = 1;
 
-    reduce:
+      /* Simplify addition or subtraction of a constant by folding the
+         constant into X_add_number.  */
+      if (symp->sy_value.X_op == O_add
+	  || symp->sy_value.X_op == O_subtract)
+	{
+	  resolve_symbol_value (symp->sy_value.X_add_symbol);
+	  resolve_symbol_value (symp->sy_value.X_op_symbol);
+	  if (S_GET_SEGMENT (symp->sy_value.X_op_symbol) == absolute_section)
+	    {
+	      right = S_GET_VALUE (symp->sy_value.X_op_symbol);
+	      if (symp->sy_value.X_op == O_add)
+		symp->sy_value.X_add_number += right;
+	      else
+		symp->sy_value.X_add_number -= right;
+	      symp->sy_value.X_op = O_symbol;
+	      symp->sy_value.X_op_symbol = NULL;
+	    }
+	  else if ((S_GET_SEGMENT (symp->sy_value.X_add_symbol)
+		    == absolute_section)
+		   && symp->sy_value.X_op == O_add)
+	    {
+	      left = S_GET_VALUE (symp->sy_value.X_add_symbol);
+	      symp->sy_value.X_add_symbol = symp->sy_value.X_op_symbol;
+	      symp->sy_value.X_add_number += left;
+	      symp->sy_value.X_op = O_symbol;
+	      symp->sy_value.X_op_symbol = NULL;
+	    }
+	}
+
       switch (symp->sy_value.X_op)
 	{
 	case O_absent:
@@ -708,39 +736,6 @@
 	  resolved = symp->sy_value.X_add_symbol->sy_resolved;
 	  break;
 
-	case O_add:
-	  resolve_symbol_value (symp->sy_value.X_add_symbol);
-	  resolve_symbol_value (symp->sy_value.X_op_symbol);
-	  seg_left = S_GET_SEGMENT (symp->sy_value.X_add_symbol);
-	  seg_right = S_GET_SEGMENT (symp->sy_value.X_op_symbol);
-	  /* This case comes up with PIC support.  */
-	  {
-	    symbolS *s_left = symp->sy_value.X_add_symbol;
-	    symbolS *s_right = symp->sy_value.X_op_symbol;
-
-	    if (seg_left == absolute_section)
-	      {
-		symbolS *t;
-		segT ts;
-		t = s_left;
-		s_left = s_right;
-		s_right = t;
-		ts = seg_left;
-		seg_left = seg_right;
-		seg_right = ts;
-	      }
-	    if (seg_right == absolute_section
-		&& s_right->sy_resolved)
-	      {
-		symp->sy_value.X_add_number += S_GET_VALUE (s_right);
-		symp->sy_value.X_op_symbol = 0;
-		symp->sy_value.X_add_symbol = s_left;
-		symp->sy_value.X_op = O_symbol;
-		goto reduce;
-	      }
-	  }
-	  /* fall through */
-
 	case O_multiply:
 	case O_divide:
 	case O_modulus:
@@ -750,6 +745,7 @@
 	case O_bit_or_not:
 	case O_bit_exclusive_or:
 	case O_bit_and:
+	case O_add:
 	case O_subtract:
 	case O_eq:
 	case O_ne:
@@ -763,38 +759,30 @@
 	  resolve_symbol_value (symp->sy_value.X_op_symbol);
 	  seg_left = S_GET_SEGMENT (symp->sy_value.X_add_symbol);
 	  seg_right = S_GET_SEGMENT (symp->sy_value.X_op_symbol);
-	  if (seg_left != seg_right
-	      && seg_left != undefined_section
-	      && seg_right != undefined_section)
-	    {
-	      char *file;
-	      unsigned int line;
+	  left = S_GET_VALUE (symp->sy_value.X_add_symbol);
+	  right = S_GET_VALUE (symp->sy_value.X_op_symbol);
 
-	      if (expr_symbol_where (symp, &file, &line))
-		as_bad_where
-		  (file, line,
-		   "illegal operation on symbols in different sections");
-	      else
-		as_bad
-		  ("%s set to illegal operation on symbols in different sections",
-		   S_GET_NAME (symp));
-	    }
-	  if ((S_GET_SEGMENT (symp->sy_value.X_add_symbol)
-	       != absolute_section)
-	      && symp->sy_value.X_op != O_subtract)
+	  /* Subtraction is permitted if both operands are in the same
+	     section.  Otherwise, both operands must be absolute.  We
+	     already handled the case of addition or subtraction of a
+	     constant above.  This will probably need to be changed
+	     for an object file format which supports arbitrary
+	     expressions, such as IEEE-695.  */
+	  if ((seg_left != absolute_section
+	       || seg_right != absolute_section)
+	      && (symp->sy_value.X_op != O_subtract
+		  || seg_left != seg_right))
 	    {
 	      char *file;
 	      unsigned int line;
 
 	      if (expr_symbol_where (symp, &file, &line))
-		as_bad_where (file, line,
-			      "illegal operation on non-absolute symbols");
+		as_bad_where (file, line, "invalid section for operation");
 	      else
-		as_bad ("%s set to illegal operation on non-absolute symbols",
+		as_bad ("invalid section for operation setting %s",
 			S_GET_NAME (symp));
 	    }
-	  left = S_GET_VALUE (symp->sy_value.X_add_symbol);
-	  right = S_GET_VALUE (symp->sy_value.X_op_symbol);
+
 	  switch (symp->sy_value.X_op)
 	    {
 	    case O_multiply:		val = left * right; break;