This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch][gas/z80] Prevent using register names as ordinary symbols


Peter Hanzel has reported to me that z80-coff-as happily produces code 
for pseudo instructions like LD HL,(SP+0).
Register names, like `SP' were only recognised when they appeared 
alone in an argument or as part of standard indexed addressing 
constructs, like `(ix+d)'.
This patch creates symbol table entries for z80 registers, preventing 
their usage as ordinary symbols and bringing the parsing of them more 
in line with other ports.

Changelog:
2012-05-06  Arnold Metselaar <arnold_m@operamail.com>

	* config/tc-z80.h(md_register_arithmetic): Define as 0.
	* config/tc-z80.c(md_begin): Store register names in symbol table, 
prevents usage as ordinary symbol.
	* config/tc-z80.c(contains_register): New function.
	* config/tc-z80.c(parse_exp2): Removed.
	* config/tc-z80.c(parse_exp_not_indexed): New function.
	* config/tc-z80.c(parse_exp): Add code to recogize indexed 
addressing after parsing.
	* config/tc-z80.c(emit_byte, emit_word): Use contains_register.
	* config/tc-z80.c(emit_jp): Use parse_exp_not_indexed, simplify 
condition for jump to register.
	* config/tc-z80.c(emit_call, emit_jr, emit_ex, emit_rst): Use 
parse_exp_not_indexed.
Index: config/tc-z80.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-z80.c,v
retrieving revision 1.13
diff -u -p -r1.13 tc-z80.c
--- config/tc-z80.c	9 Dec 2010 20:02:07 -0000	1.13
+++ config/tc-z80.c	6 May 2012 09:28:51 -0000
@@ -1,5 +1,5 @@
 /* tc-z80.c -- Assemble code for the Zilog Z80 and ASCII R800
-   Copyright 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   Copyright 2005, 2006, 2007, 2008, 2009, 2012 Free Software Foundation, Inc.
    Contributed by Arnold Metselaar <arnold_m@operamail.com>
 
    This file is part of GAS, the GNU Assembler.
@@ -161,12 +161,93 @@ Default: -z80 -ignore-undocument-instruc
 
 static symbolS * zero;
 
+struct reg_entry
+{
+  char* name;
+  int number;
+};
+#define R_STACKABLE (0x80)
+#define R_ARITH     (0x40)
+#define R_IX        (0x20)
+#define R_IY        (0x10)
+#define R_INDEX     (R_IX | R_IY)
+
+#define REG_A (7)
+#define REG_B (0)
+#define REG_C (1)
+#define REG_D (2)
+#define REG_E (3)
+#define REG_H (4)
+#define REG_L (5)
+#define REG_F (6 | 8)
+#define REG_I (9)
+#define REG_R (10)
+
+#define REG_AF (3 | R_STACKABLE)
+#define REG_BC (0 | R_STACKABLE | R_ARITH)
+#define REG_DE (1 | R_STACKABLE | R_ARITH)
+#define REG_HL (2 | R_STACKABLE | R_ARITH)
+#define REG_IX (REG_HL | R_IX)
+#define REG_IY (REG_HL | R_IY)
+#define REG_SP (3 | R_ARITH)
+
+static const struct reg_entry regtable[] =
+{
+  {"a",  REG_A },
+  {"af", REG_AF },
+  {"b",  REG_B },
+  {"bc", REG_BC },
+  {"c",  REG_C },
+  {"d",  REG_D },
+  {"de", REG_DE },
+  {"e",  REG_E },
+  {"f",  REG_F },
+  {"h",  REG_H },
+  {"hl", REG_HL },
+  {"i",  REG_I },
+  {"ix", REG_IX },
+  {"ixh",REG_H | R_IX },
+  {"ixl",REG_L | R_IX },
+  {"iy", REG_IY },
+  {"iyh",REG_H | R_IY },
+  {"iyl",REG_L | R_IY },
+  {"l",  REG_L },
+  {"r",  REG_R },
+  {"sp", REG_SP },
+} ;
+
+#define BUFLEN 8 /* Large enough for any keyword.  */
+
 void
 md_begin (void)
 {
-  expressionS nul;
+  expressionS nul, reg;
   char * p;
+  unsigned int i, j, k;
+  char buf[BUFLEN];
 
+  reg.X_op = O_register;
+  reg.X_md = 0;
+  reg.X_add_symbol = reg.X_op_symbol = 0;
+  for ( i = 0 ; i < ARRAY_SIZE ( regtable ) ; ++i )
+    {
+      reg.X_add_number = regtable[i].number;
+      k = strlen ( regtable[i].name );
+      buf[k] = 0;
+      if ( k+1 < BUFLEN )
+        {
+          for ( j = ( 1<<k ) ; j ; --j )
+            {
+              for ( k = 0 ; regtable[i].name[k] ; ++k )
+                {
+                  buf[k] = ( j & ( 1<<k ) ) ? TOUPPER ( regtable[i].name[k] ) : regtable[i].name[k];
+                }
+              symbolS * psym = symbol_find_or_make(buf);
+	      S_SET_SEGMENT(psym, reg_section);
+	      symbol_set_value_expression(psym, &reg);
+            }
+        }
+    }
   p = input_line_pointer;
   input_line_pointer = "0";
   nul.X_md=0;
@@ -343,63 +424,9 @@ key_cmp (const void * a, const void * b)
   return strcmp (str_a, str_b);
 }
 
-#define BUFLEN 8 /* Large enough for any keyword.  */
-
 char buf[BUFLEN];
 const char *key = buf;
 
-#define R_STACKABLE (0x80)
-#define R_ARITH     (0x40)
-#define R_IX        (0x20)
-#define R_IY        (0x10)
-#define R_INDEX     (R_IX | R_IY)
-
-#define REG_A (7)
-#define REG_B (0)
-#define REG_C (1)
-#define REG_D (2)
-#define REG_E (3)
-#define REG_H (4)
-#define REG_L (5)
-#define REG_F (6 | 8)
-#define REG_I (9)
-#define REG_R (10)
-
-#define REG_AF (3 | R_STACKABLE)
-#define REG_BC (0 | R_STACKABLE | R_ARITH)
-#define REG_DE (1 | R_STACKABLE | R_ARITH)
-#define REG_HL (2 | R_STACKABLE | R_ARITH)
-#define REG_SP (3 | R_ARITH)
-
-static const struct reg_entry
-{
-  char* name;
-  int number;
-} regtable[] =
-{
-  {"a",  REG_A },
-  {"af", REG_AF },
-  {"b",  REG_B },
-  {"bc", REG_BC },
-  {"c",  REG_C },
-  {"d",  REG_D },
-  {"de", REG_DE },
-  {"e",  REG_E },
-  {"f",  REG_F },
-  {"h",  REG_H },
-  {"hl", REG_HL },
-  {"i",  REG_I },
-  {"ix", REG_HL | R_IX },
-  {"ixh",REG_H | R_IX },
-  {"ixl",REG_L | R_IX },
-  {"iy", REG_HL | R_IY },
-  {"iyh",REG_H | R_IY },
-  {"iyl",REG_L | R_IY },
-  {"l",  REG_L },
-  {"r",  REG_R },
-  {"sp", REG_SP },
-} ;
-
 /* Prevent an error on a line from also generating
    a "junk at end of line" error message.  */
 static char err_flag;
@@ -496,88 +523,90 @@ is_indir (const char *s)
   return indir;
 }
 
-/* Parse general expression.  */
+/* Check whether a symbol involves a register.  */
+static int 
+contains_register(symbolS *sym)
+{
+  if (sym)
+  {
+    expressionS * ex = symbol_get_value_expression(sym);
+    return (O_register == ex->X_op) 
+      || (ex->X_add_symbol && contains_register(ex->X_add_symbol)) 
+      || (ex->X_op_symbol && contains_register(ex->X_op_symbol));
+  }
+  else
+    return 0;
+}
+
+/* Parse general expression, not loooking for indexed adressing.  */
 static const char *
-parse_exp2 (const char *s, expressionS *op, segT *pseg)
+parse_exp_not_indexed (const char *s, expressionS *op)
 {
   const char *p;
   int indir;
-  int i;
-  const struct reg_entry * regp;
-  expressionS offset;
+  segT dummy;
 
   p = skip_space (s);
   op->X_md = indir = is_indir (p);
-  if (indir)
-    p = skip_space (p + 1);
-
-  for (i = 0; i < BUFLEN; ++i)
-    {
-      if (!ISALPHA (p[i])) /* Register names consist of letters only.  */
-	break;
-      buf[i] = TOLOWER (p[i]);
-    }
-
-  if ((i < BUFLEN) && ((p[i] == 0) || (strchr (")+-, \t", p[i]))))
+  input_line_pointer = (char*) s ;
+  dummy = expression (op);
+  switch (op->X_op)
     {
-      buf[i] = 0;
-      regp = bsearch (& key, regtable, ARRAY_SIZE (regtable),
-		      sizeof (regtable[0]), key_cmp);
-      if (regp)
-	{
-	  *pseg = reg_section;
-	  op->X_add_symbol = op->X_op_symbol = 0;
-	  op->X_add_number = regp->number;
-	  op->X_op = O_register;
-	  p += strlen (regp->name);
-	  p = skip_space (p);
-	  if (indir)
-	    {
-	      if (*p == ')')
-		++p;
-	      if ((regp->number & R_INDEX) && (regp->number & R_ARITH))
-		{
-		  op->X_op = O_md1;
-
-		  if  ((*p == '+') || (*p == '-'))
-		    {
-		      input_line_pointer = (char*) p;
-		      expression (& offset);
-		      p = skip_space (input_line_pointer);
-		      if (*p != ')')
-			error (_("bad offset expression syntax"));
-		      else
-			++ p;
-		      op->X_add_symbol = make_expr_symbol (& offset);
-		      return p;
-		    }
-
-		  /* We treat (i[xy]) as (i[xy]+0), which is how it will
-		     end up anyway, unless we're processing jp (i[xy]).  */
-		  op->X_add_symbol = zero;
-		}
-	    }
-	  p = skip_space (p);
-
-	  if ((*p == 0) || (*p == ','))
-	    return p;
-	}
+    case O_absent:
+      error (_("missing operand"));
+      break;
+    case O_illegal:
+      error (_("bad expression syntax"));
+      break;
     }
-  /* Not an argument involving a register; use the generic parser.  */
-  input_line_pointer = (char*) s ;
-  *pseg = expression (op);
-  if (op->X_op == O_absent)
-    error (_("missing operand"));
-  if (op->X_op == O_illegal)
-    error (_("bad expression syntax"));
   return input_line_pointer;
 }
 
+/* Parse expression, change operator to O_md1 for indexed addressing*/
 static const char *
 parse_exp (const char *s, expressionS *op)
 {
-  segT dummy;
-  return parse_exp2 (s, op, & dummy);
+  const char* res = parse_exp_not_indexed (s, op);
+  switch (op->X_op)
+    {
+    case O_add:
+    case O_subtract:
+      if (op->X_md && (O_register == symbol_get_value_expression(op->X_add_symbol)->X_op))
+        {
+	  int rnum = symbol_get_value_expression(op->X_add_symbol)->X_add_number;
+	  if ( ((REG_IX != rnum) && (REG_IY != rnum)) || contains_register(op->X_op_symbol) )
+	    {
+	      ill_op();
+	    }
+	  else
+	    {
+	      if (O_subtract == op->X_op)
+	        {
+		  expressionS minus;
+		  minus.X_op = O_uminus;
+		  minus.X_add_number = 0;
+		  minus.X_add_symbol = op->X_op_symbol;
+		  minus.X_op_symbol = 0;
+		  op->X_op_symbol = make_expr_symbol(&minus);
+		  op->X_op = O_add;
+	        }
+	      symbol_get_value_expression(op->X_op_symbol)->X_add_number += op->X_add_number;
+	      op->X_add_number = rnum;
+	      op->X_add_symbol = op->X_op_symbol;
+	      op->X_op_symbol = 0;
+	      op->X_op = O_md1;
+	    }
+	}
+      break;
+    case O_register:
+      if ( op->X_md && ((REG_IX == op->X_add_number)||(REG_IY == op->X_add_number)) )
+        {
+	  op->X_add_symbol = zero;
+	  op->X_op = O_md1;
+	}
+	break;
+    }
+  return res;
 }
 
 /* Condition codes, including some synonyms provided by HiTech zas.  */
@@ -680,7 +709,11 @@ emit_byte (expressionS * val, bfd_reloc_
 
   p = frag_more (1);
   *p = val->X_add_number;
-  if ((r_type == BFD_RELOC_8_PCREL) && (val->X_op == O_constant))
+  if ( contains_register(val->X_add_symbol) || contains_register(val->X_op_symbol) )
+    {
+      ill_op();
+    }
+  else if ((r_type == BFD_RELOC_8_PCREL) && (val->X_op == O_constant))
     {
       as_bad (_("cannot make a relative jump to an absolute location"));
     }
@@ -712,7 +745,9 @@ emit_word (expressionS * val)
 
   p = frag_more (2);
   if (   (val->X_op == O_register)
-      || (val->X_op == O_md1))
+      || (val->X_op == O_md1)
+      || contains_register(val->X_add_symbol)
+      || contains_register(val->X_op_symbol) )
     ill_op ();
   else
     {
@@ -888,7 +923,7 @@ emit_call (char prefix ATTRIBUTE_UNUSED,
   expressionS addr;
   const char *p;  char *q;
 
-  p = parse_exp (args, &addr);
+  p = parse_exp_not_indexed (args, &addr);
   if (addr.X_md)
     ill_op ();
   else
@@ -936,7 +971,7 @@ emit_jr (char prefix ATTRIBUTE_UNUSED, c
   const char *p;
   char *q;
 
-  p = parse_exp (args, &addr);
+  p = parse_exp_not_indexed (args, &addr);
   if (addr.X_md)
     ill_op ();
   else
@@ -956,14 +991,11 @@ emit_jp (char prefix, char opcode, const
   char *q;
   int rnum;
 
-  p = parse_exp (args, & addr);
+  p = parse_exp_not_indexed (args, & addr);
   if (addr.X_md)
     {
       rnum = addr.X_add_number;
-      if ((addr.X_op == O_register && (rnum & ~R_INDEX) == REG_HL)
-	 /* An operand (i[xy]) would have been rewritten to (i[xy]+0)
-            in parse_exp ().  */
-	  || (addr.X_op == O_md1 && addr.X_add_symbol == zero))
+      if ((O_register == addr.X_op) && (REG_HL == (rnum & ~R_INDEX)))
 	{
 	  q = frag_more ((rnum & R_INDEX) ? 2 : 1);
 	  if (rnum & R_INDEX)
@@ -1217,7 +1249,7 @@ emit_ex (char prefix_in ATTRIBUTE_UNUSED
   const char * p;
   char prefix, opcode;
 
-  p = parse_exp (args, &op);
+  p = parse_exp_not_indexed (args, &op);
   p = skip_space (p);
   if (*p++ != ',')
     {
@@ -1377,7 +1409,7 @@ emit_rst (char prefix ATTRIBUTE_UNUSED, 
   const char *p;
   char *q;
 
-  p = parse_exp (args, &addr);
+  p = parse_exp_not_indexed (args, &addr);
   if (addr.X_op != O_constant)
     {
       error ("rst needs constant address");
Index: config/tc-z80.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-z80.h,v
retrieving revision 1.6
diff -u -p -r1.6 tc-z80.h
--- config/tc-z80.h	2 Sep 2009 07:24:21 -0000	1.6
+++ config/tc-z80.h	6 May 2012 09:28:51 -0000
@@ -1,5 +1,5 @@
 /* this is tc-z80.h
-   Copyright 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright 2005, 2006, 2007, 2012 Free Software Foundation, Inc.
 
    Contributed by Arnold Metselaar <arnold_m@operamail.com>
 
@@ -102,4 +102,8 @@ extern void z80_cons_fix_new (fragS *, i
    P2VAR to the truncated power of two of sizes up to eight bytes.  */
 #define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) (P2VAR) = 0
 
+/* It does not make any sense to perform arithmetic on the numbers 
+   we use to identify registers.  */
+#define md_register_arithmetic 0
+
 #endif

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