This is the mail archive of the binutils@sources.redhat.com 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]

Re: [js@convergence.de: binutils-2.11.92.0.12.3 gas MIPS bug: nested parens in %hi]


> > ----- Forwarded message from Johannes Stezenbach <js@convergence.de> -----
[snip]
> > the assembler of binutils-2.11.92.0.12.3 for MIPS has a bug which
> > shows up when parsing percent-ops like %hi and %lo with
> > nested parentheses, e.g.
> > 
> >    lui t0, %hi((0xa0000000 + 0x10001000))
> > 
> > produces parsing errors because of unmatched parens
> > (sorry, I don't have the exact error message right now).

I overlooked this possibility when I changed/reimplemented this
functions to support NewABI's nested percent op's like

	lui $1, %hi(%neg(%pc_rel(symbol)))

[snip]
> > I attempted to fix this problem (patch attached), but unfortunately
> > my understanding of gas' expression parser is very limited.
> > My patch is thus more a workaround-hack than a fix.
> > 
> > I tried hard to figure out how my_getSmallExpression() in
> > gas/config/tc-mips.c works for nested precent-ops, but
> > either I failed or the thing is totally broken.

It is broken in several ways as I found out now.

> > I dont't know all the details of the MIPS assembler syntax,
> > but wouldn't it be the right way to use expr() (in gas/expr.c) for
> > parsing, and provide support for percent-ops via the
> > md_operand() hook?  This should work since is_name_beginner('%')
> > returns FALSE and LITERAL_PREFIXPERCENT_BIN is #undef'd.

AFAICS this does not work for nested percent op's, so I expanded
your patch to fix some more flaws and did also some code cleanup.
It still looks ugly.


Thiemo


2002-01-12  Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
            Johannes Stezenbach <js@convergence.de>

	/gas/ChangeLog
	* config/tc-mips.c (percent_op): Ensure longer percent_op's are
	matched before the shorter ones.
	(my_getSmallParser): Fix handling of nested parentheses in
	percent_op's. Code cleanup.
	(my_getPercentOp): New function, code from my_getSmallParser.
	(my_getSmallExpression): Fix handling of closing parentheses.
	Code cleanup. Better comments.


diff -BurpNX /bigdisk/src/binutils-exclude src-orig/gas/config/tc-mips.c src/gas/config/tc-mips.c
--- src-orig/gas/config/tc-mips.c	Thu Jan 10 21:14:28 2002
+++ src/gas/config/tc-mips.c	Sat Jan 12 12:42:30 2002
@@ -702,6 +702,7 @@ static void mips16_ip PARAMS ((char *str
 static void mips16_immed PARAMS ((char *, unsigned int, int, offsetT, boolean,
 				  boolean, boolean, unsigned long *,
 				  boolean *, unsigned short *));
+static int my_getPercentOp PARAMS ((char **, unsigned int *, int *));
 static int my_getSmallParser PARAMS ((char **, unsigned int *, int *));
 static int my_getSmallExpression PARAMS ((expressionS *, char *));
 static void my_getExpression PARAMS ((expressionS *, char *));
@@ -9314,26 +9380,24 @@ static struct percent_op_match
    const enum small_ex_type type;
 } percent_op[] =
 {
-#ifdef OBJ_ELF
-  {"%half", S_EX_HALF},
-#endif
-  {"%hi", S_EX_HI},
   {"%lo", S_EX_LO},
 #ifdef OBJ_ELF
-  {"%gp_rel", S_EX_GP_REL},
-  {"%got", S_EX_GOT},
+  {"%call_hi", S_EX_CALL_HI},
+  {"%call_lo", S_EX_CALL_LO},
   {"%call16", S_EX_CALL16},
   {"%got_disp", S_EX_GOT_DISP},
   {"%got_page", S_EX_GOT_PAGE},
   {"%got_ofst", S_EX_GOT_OFST},
   {"%got_hi", S_EX_GOT_HI},
   {"%got_lo", S_EX_GOT_LO},
-  {"%neg", S_EX_NEG},
-  {"%higher", S_EX_HIGHER},
+  {"%got", S_EX_GOT},
+  {"%gp_rel", S_EX_GP_REL},
+  {"%half", S_EX_HALF},
   {"%highest", S_EX_HIGHEST},
-  {"%call_hi", S_EX_CALL_HI},
-  {"%call_lo", S_EX_CALL_LO}
+  {"%higher", S_EX_HIGHER},
+  {"%neg", S_EX_NEG},
 #endif
+  {"%hi", S_EX_HI}
 };
 
 /* Parse small expression input.  STR gets adjusted to eat up whitespace.
@@ -9347,10 +9411,9 @@ my_getSmallParser (str, len, nestlevel)
      unsigned int *len;
      int *nestlevel;
 {
-  int type = S_EX_NONE;
-
   *len = 0;
   *str += strspn (*str, " \t");
+  /* Check for expression in parentheses.  */
   if (**str == '(')
     {
       char *b = *str + 1 + strspn (*str + 1, " \t");
@@ -9377,50 +9440,68 @@ my_getSmallParser (str, len, nestlevel)
 		 }
 	    }
 	}
+      /* Check for percent_op (in parentheses).  */
       else if (b[0] == '%')
 	{
 	  *str = b;
-	  goto percent_op;
+	  return my_getPercentOp (str, len, nestlevel);
 	}
 
-      /* Some other expression in the braces.  */
-      *len = strcspn (*str, ")") + 1;
+      /* Some other expression in the parentheses, which can contain
+	 parentheses itself. Attempt to find the matching one.  */
+      {
+	int pcnt = 1;
+	char *s;
+
+	*len = 1;
+	for (s = *str + 1; *s && pcnt; s++, (*len)++)
+	  {
+	    if (*s == '(')
+	      pcnt++;
+	    else if (*s == ')')
+	      pcnt--;
+	  }
+      }
     }
-  /* Check for percent_op.  */
+  /* Check for percent_op (outside of parentheses).  */
   else if (*str[0] == '%')
-    {
-      char *tmp;
-      unsigned int i;
+    return my_getPercentOp (str, len, nestlevel);
 
-percent_op:
-      tmp = *str + 1;
-      i = 0;
+  /* Any other expression.  */
+  return S_EX_NONE;
+}
 
-      while (ISALPHA (*tmp) || *tmp == '_')
-	{
-	  *tmp = TOLOWER (*tmp);
-	  tmp++;
-	}
-      while (i < (sizeof (percent_op) / sizeof (struct percent_op_match)))
+static int
+my_getPercentOp (str, len, nestlevel)
+     char **str;
+     unsigned int *len;
+     int *nestlevel;
+{
+  char *tmp = *str + 1;
+  unsigned int i = 0;
+
+  while (ISALPHA (*tmp) || *tmp == '_')
+    {
+      *tmp = TOLOWER (*tmp);
+      tmp++;
+    }
+  while (i < (sizeof (percent_op) / sizeof (struct percent_op_match)))
+    {
+      if (strncmp (*str, percent_op[i].str, strlen (percent_op[i].str)))
+	  i++;
+      else
 	{
-	  if (strncmp (*str, percent_op[i].str, strlen (percent_op[i].str)))
-	      i++;
-	  else
-	    {
-	      type = percent_op[i].type;
+	  int type = percent_op[i].type;
 
-	      /* Only %hi and %lo are allowed for OldABI.  */
-	      if (! HAVE_NEWABI && type != S_EX_HI && type != S_EX_LO)
-		return S_EX_NONE;
-
-	      *len = strlen (percent_op[i].str);
-	      (*nestlevel)++;
-	      return type;
-	    }
+	  /* Only %hi and %lo are allowed for OldABI.  */
+	  if (! HAVE_NEWABI && type != S_EX_HI && type != S_EX_LO)
+	    return S_EX_NONE;
+
+	  *len = strlen (percent_op[i].str);
+	  (*nestlevel)++;
+	  return type;
 	}
     }
-
-  /* Any other expression.  */
   return S_EX_NONE;
 }
 
@@ -9432,46 +9513,59 @@ my_getSmallExpression (ep, str)
   static char *oldstr = NULL;
   int c = S_EX_NONE;
   int oldc;
-  int nest_level = 0;
+  int nestlevel = -1;
   unsigned int len;
 
-  /* Don't update oldstr if the last call had nested percent_op's.  */
+  /* Don't update oldstr if the last call had nested percent_op's. We need
+     it to parse the outer ones later.  */
   if (! oldstr)
     oldstr = str;
 
   do
     {
       oldc = c;
-      c = my_getSmallParser (&str, &len, &nest_level);
+      c = my_getSmallParser (&str, &len, &nestlevel);
       if (c != S_EX_NONE && c != S_EX_REGISTER)
 	str += len;
     }
   while (c != S_EX_NONE && c != S_EX_REGISTER);
 
-  /* A percent_op was encountered.  */
-  if (nest_level)
+  if (nestlevel >= 0)
     {
-      /* Don't try to get an expression if it is already blanked out.  */
+      /* A percent_op was encountered.  Don't try to get an expression if
+	 it is already blanked out.  */
       if (*(str + strspn (str + 1, " )")) != ')')
 	{
 	  char save;
 
+	  /* Let my_getExpression() stop at the closing parenthesis.  */
 	  save = *(str + len);
 	  *(str + len) = '\0';
 	  my_getExpression (ep, str);
 	  *(str + len) = save;
 	}
-      if (nest_level > 1)
+      if (nestlevel > 0)
 	{
-	  /* blank out including the % sign.  */
-	  char *p = strrchr (oldstr, '%');
-	  memset (p, ' ', str - p + len);
+	  /* Blank out including the % sign and the proper matching
+	     parenthesis.  */
+	  int pcnt = 1;
+	  char *s = strrchr (oldstr, '%');
+	  char *end;
+
+	  for (end = strchr (s, '(') + 1; *end && pcnt; end++)
+	    {
+	      if (*end == '(')
+		pcnt++;
+	      else if (*end == ')')
+		pcnt--;
+	    }
+
+	  memset (s, ' ', end - s);
 	  str = oldstr;
 	}
       else
-	{
-	  expr_end = strchr (str, ')') + 1;
-	}
+	expr_end = str + len;
+
       c = oldc;
     }
   else if (c == S_EX_NONE)
@@ -9491,7 +9585,8 @@ my_getSmallExpression (ep, str)
       as_fatal(_("internal error"));
     }
 
-  if (nest_level <= 1)
+  if (nestlevel <= 0)
+    /* All percent_op's have been handled.  */
     oldstr = NULL;
 
   return c;


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