public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* Re: [PATCH] ia64 unwind directive semantics
@ 2005-02-02 14:52 Jan Beulich
  2005-02-11  1:39 ` James E Wilson
  0 siblings, 1 reply; 10+ messages in thread
From: Jan Beulich @ 2005-02-02 14:52 UTC (permalink / raw)
  To: binutils

[-- Attachment #1: Type: text/plain, Size: 10758 bytes --]

>>> Alan Modra <amodra@bigpond.net.au> 02.02.05 09:16:15 >>>
>On Mon, Jan 24, 2005 at 12:29:07PM +0100, Jan Beulich wrote:
>> 	(dot_endp): Call in_procedure. Declare proc_end. Check for
non-zero-
>> 	length entry point names. Check that entry points became
defined.
>
>This one breaks glibc build.
>
>csu/crtn.S: Assembler messages:
>csu/crtn.S:22: Error: `_init#' was not defined within procedure
>csu/crtn.S:36: Error: `_fini#' was not defined within procedure

While the case mentioned here validly reports an error, as outlined in
a previous mail, during the research of the reasons for the failure I
realized that in various places, the # suffix used to distinguish
user-defined symbols from built-in ones (i.e. register names) did not
work as expected.

Built and tested on ia64-unknown-linux-gnu.

Jan

gas/
2005-02-02  Jan Beulich  <jbeulich@novell.com>

	* config/tc-ia64.c (dot_rot): Free name strings when wiping out
	previous state. Canonicalize names before use. Free name string
	when detecting redefinition.
	(dot_pred_rel): Call generic expression parser to process
arguments.
	Handle O_register case for individual predicates and O_subtract
for
	ranges.
	(ia64_parse_name): Canonicalize name before looking it up in
dynamic
	register hash.
	(ia64_canonicalize_symbol_name): Strip off all trailing #
characters.
	Warn if multiple found, issue error if resulting symbol name has
zero
	length.
	(dot_alias): Canonicalize name before use.

gas/testsuite/
2005-02-02  Jan Beulich  <jbeulich@novell.com>

	* gas/ia64/pound.[ls]: New.
	* gas/ia64/ia64.exp: Run new test.

---
/home/jbeulich/src/binutils/mainline/2005-02-01/gas/config/tc-ia64.c	2005-02-01
16:15:58.000000000 +0100
+++ 2005-02-01/gas/config/tc-ia64.c	2005-02-02 15:39:08.152745265
+0100
@@ -4499,6 +4499,7 @@ dot_rot (type)
   for (dr = md.dynreg[type]; dr && dr->num_regs; dr = dr->next)
     {
       hash_delete (md.dynreg_hash, dr->name);
+      obstack_free (&notes, (void *) dr->name);
       dr->num_regs = 0;
     }
 
@@ -4507,8 +4508,8 @@ dot_rot (type)
     {
       start = input_line_pointer;
       ch = get_symbol_end ();
+      len = strlen (ia64_canonicalize_symbol_name (start));
       *input_line_pointer = ch;
-      len = (input_line_pointer - start);
 
       SKIP_WHITESPACE ();
       if (*input_line_pointer != '[')
@@ -4577,6 +4578,7 @@ dot_rot (type)
       if (hash_insert (md.dynreg_hash, name, dr))
 	{
 	  as_bad ("Attempt to redefine register set `%s'", name);
+	  obstack_free (&notes, name);
 	  goto err;
 	}
 
@@ -4975,59 +4977,57 @@ dot_pred_rel (type)
   SKIP_WHITESPACE ();
   while (1)
     {
-      valueT bit = 1;
+      valueT bits = 1;
       int regno;
+      expressionS pr, *pr1, *pr2;
 
-      if (TOUPPER (*input_line_pointer) != 'P'
-	  || (regno = atoi (++input_line_pointer)) < 0
-	  || regno > 63)
-	{
-	  as_bad (_("Predicate register expected"));
-	  ignore_rest_of_line ();
-	  return;
-	}
-      while (ISDIGIT (*input_line_pointer))
-	++input_line_pointer;
-      if (p1 == -1)
-	p1 = regno;
-      else if (p2 == -1)
-	p2 = regno;
-      bit <<= regno;
-      if (mask & bit)
-	as_warn (_("Duplicate predicate register ignored"));
-      mask |= bit;
-      count++;
-      /* See if it's a range.  */
-      if (*input_line_pointer == '-')
-	{
-	  valueT stop = 1;
-	  ++input_line_pointer;
-
-	  if (TOUPPER (*input_line_pointer) != 'P'
-	      || (regno = atoi (++input_line_pointer)) < 0
-	      || regno > 63)
-	    {
-	      as_bad (_("Predicate register expected"));
-	      ignore_rest_of_line ();
-	      return;
-	    }
-	  while (ISDIGIT (*input_line_pointer))
-	    ++input_line_pointer;
-	  stop <<= regno;
-	  if (bit >= stop)
+      expression (&pr);
+      if (pr.X_op == O_register
+	  && pr.X_add_number >= REG_P
+	  && pr.X_add_number <= REG_P + 63)
+	{
+	  regno = pr.X_add_number - REG_P;
+	  bits <<= regno;
+	  count++;
+	  if (p1 == -1)
+	    p1 = regno;
+	  else if (p2 == -1)
+	    p2 = regno;
+	}
+      else if (type != 'i'
+	  && pr.X_op == O_subtract
+	  && (pr1 = symbol_get_value_expression (pr.X_add_symbol))
+	  && pr1->X_op == O_register
+	  && pr1->X_add_number >= REG_P
+	  && pr1->X_add_number <= REG_P + 63
+	  && (pr2 = symbol_get_value_expression (pr.X_op_symbol))
+	  && pr2->X_op == O_register
+	  && pr2->X_add_number >= REG_P
+	  && pr2->X_add_number <= REG_P + 63)
+	{
+	  /* It's a range.  */
+	  int stop;
+
+	  regno = pr1->X_add_number - REG_P;
+	  stop = pr2->X_add_number - REG_P;
+	  if (regno >= stop)
 	    {
 	      as_bad (_("Bad register range"));
 	      ignore_rest_of_line ();
 	      return;
 	    }
-	  while (bit < stop)
-	    {
-	      bit <<= 1;
-	      mask |= bit;
-	      count++;
-	    }
-	  SKIP_WHITESPACE ();
+	  bits = ((bits << stop) << 1) - (bits << regno);
+	  count += stop - regno + 1;
+	}
+      else
+	{
+	  as_bad (_("Predicate register expected"));
+	  ignore_rest_of_line ();
+	  return;
 	}
+      if (mask & bits)
+	as_warn (_("Duplicate predicate register ignored"));
+      mask |= bits;
       if (*input_line_pointer != ',')
 	break;
       ++input_line_pointer;
@@ -7644,6 +7644,9 @@ ia64_parse_name (name, e)
 	}
     }
 
+  end = alloca (strlen (name) + 1);
+  strcpy (end, name);
+  name = ia64_canonicalize_symbol_name (end);
   if ((dr = hash_find (md.dynreg_hash, name)))
     {
       /* We've got ourselves the name of a rotating register set.
@@ -7663,9 +7666,20 @@ char *
 ia64_canonicalize_symbol_name (name)
      char *name;
 {
-  size_t len = strlen (name);
-  if (len > 1 && name[len - 1] == '#')
-    name[len - 1] = '\0';
+  size_t len = strlen (name), full = len;
+
+  while (len > 0 && name[len - 1] == '#')
+    --len;
+  if (len <= 0)
+    {
+      if (full > 0)
+	as_bad ("Standalone `#' is illegal");
+      else
+	as_bad ("Zero-length symbol is illegal");
+    }
+  else if (len < full - 1)
+    as_warn ("Redundant `#' suffix operators");
+  name[len] = '\0';
   return name;
 }
 
@@ -11324,6 +11338,7 @@ dot_alias (int section)
 
   input_line_pointer++;
   *end_name = 0;
+  ia64_canonicalize_symbol_name (name);
 
   /* We call demand_copy_C_string to check if alias string is valid.
      There should be a closing `"' and no `\0' in the string.  */
---
/home/jbeulich/src/binutils/mainline/2005-02-01/gas/testsuite/gas/ia64/ia64.exp	2005-01-31
10:52:17.000000000 +0100
+++ 2005-02-01/gas/testsuite/gas/ia64/ia64.exp	2005-02-02
15:39:24.418370066 +0100
@@ -66,6 +66,7 @@ if [istarget "ia64-*"] then {
     run_dump_test "bundling"
     run_list_test "label" ""
     run_list_test "last" ""
+    run_list_test "pound" "-al"
     run_list_test "proc" ""
     run_list_test "slot2" ""
     run_list_test "unwind-err" ""
---
/home/jbeulich/src/binutils/mainline/2005-02-01/gas/testsuite/gas/ia64/pound.l	1970-01-01
01:00:00.000000000 +0100
+++ 2005-02-01/gas/testsuite/gas/ia64/pound.l	2005-02-02
14:20:57.000000000 +0100
@@ -0,0 +1,58 @@
+.*: Assembler messages:
+.*:35: Warning: .* WAW .*
+#...
+.*:41: Error: symbol .esym. .* .efunction.
+.*:43: Error: section .\.extra. .* .esection.
+GAS LISTING .*
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+\.explicit
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.global esym#
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.section \.extra#, "a",
@progbits
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.text
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+	break		0
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+[[:xdigit:]]+[[:space:]]+\.proc
psym
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+psym:
+[[:space:]]*[[:digit:]]+[[:space:]]+	mov\.ret\.sptk	b7 = r0, tag#
+[[:space:]]*[[:digit:]]+[[:space:]]+	mov		r8 = 0
+[[:space:]]*[[:digit:]]+[[:space:]]+\[tag:\]	br\.ret\.sptk	rp
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+[[:xdigit:]]+[[:space:]]+\.endp
psym
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.proc esym#
+[[:space:]]*[[:digit:]]+[[:space:]]+\.entry entry#
+[[:space:]]*[[:digit:]]+[[:space:]]+esym:
+[[:space:]]*[[:digit:]]+[[:space:]]+\.unwentry
+[[:space:]]*[[:digit:]]+[[:space:]]+\.personality psym#
+[[:space:]]*[[:digit:]]+[[:space:]]+\.regstk 0, 8, 0, 8
+[[:space:]]*[[:digit:]]+[[:space:]]+\.rotp p#\[2\], p1#\[4\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\.rotr r#\[2\], r1#\[4\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\.reg\.val r#\[1\], 0
+[[:space:]]*[[:digit:]]+[[:space:]]+\.reg\.val r1#\[3\], 0
+[[:space:]]*[[:digit:]]+[[:space:]]+\(p1#\[1\]\) cmp\.eq	p\[0\] =
r\[1\], r1#\[1\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\(p1#\[3\]\) cmp\.eq	p#\[1\]
= r#\[1\], r1#\[3\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\.pred\.rel "mutex", p#\[0\],
p\[1\]
+[[:space:]]*[[:digit:]]+[[:space:]]+	nop		0
+[[:space:]]*[[:digit:]]+[[:space:]]+	;;
+[[:space:]]*[[:digit:]]+[[:space:]]+entry:
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+61828446[[:space:]]+\(p\[0\]\)	mov		r8
= 1
+[[:space:]]*[[:digit:]]+[[:space:]]+00781509[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+95007000[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+00000400[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+\(p#\[1\]\)	mov		r8
= 0
+[[:space:]]*[[:digit:]]+[[:space:]]+	br\.ret\.sptk	rp
+[[:space:]]*[[:digit:]]+[[:space:]]+\.xdata4 \.extra#, -1
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+11420400+[[:space:]]+\.endp
esym#
+[[:space:]]*[[:digit:]]+[[:space:]]+00648400[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+00004880[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+00008400[[:space:]]*
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+\.alias esym#, "efunction"
+[[:space:]]*[[:digit:]]+[[:space:]]+\.alias esym, "efunc"
+[[:space:]]*[[:digit:]]+[[:space:]]+\.secalias \.extra#, "esection"
+[[:space:]]*[[:digit:]]+[[:space:]]+\.secalias \.extra, "esec"
---
/home/jbeulich/src/binutils/mainline/2005-02-01/gas/testsuite/gas/ia64/pound.s	1970-01-01
01:00:00.000000000 +0100
+++ 2005-02-01/gas/testsuite/gas/ia64/pound.s	2005-02-02
13:23:59.000000000 +0100
@@ -0,0 +1,43 @@
+.explicit
+
+.global esym#
+
+.section .extra#, "a", @progbits
+
+.text
+
+	break		0
+
+.proc psym
+psym:
+	mov.ret.sptk	b7 = r0, tag#
+	mov		r8 = 0
+[tag:]	br.ret.sptk	rp
+.endp psym
+
+.proc esym#
+.entry entry#
+esym:
+.unwentry
+.personality psym#
+.regstk 0, 8, 0, 8
+.rotp p#[2], p1#[4]
+.rotr r#[2], r1#[4]
+.reg.val r#[1], 0
+.reg.val r1#[3], 0
+(p1#[1]) cmp.eq	p[0] = r[1], r1#[1]
+(p1#[3]) cmp.eq	p#[1] = r#[1], r1#[3]
+.pred.rel "mutex", p#[0], p[1]
+	nop		0
+	;;
+entry:
+(p[0])	mov		r8 = 1
+(p#[1])	mov		r8 = 0
+	br.ret.sptk	rp
+.xdata4 .extra#, -1
+.endp esym#
+
+.alias esym#, "efunction"
+.alias esym, "efunc"
+.secalias .extra#, "esection"
+.secalias .extra, "esec"


[-- Attachment #2: binutils-mainline-ia64-pound.patch --]
[-- Type: text/plain, Size: 10138 bytes --]

In various places, the # suffix used to distinguish user-defined symbols from
built-in ones (i.e. register names) did not work as expected.

Built and tested on ia64-unknown-linux-gnu.

Jan

gas/
2005-02-02  Jan Beulich  <jbeulich@novell.com>

	* config/tc-ia64.c (dot_rot): Free name strings when wiping out
	previous state. Canonicalize names before use. Free name string
	when detecting redefinition.
	(dot_pred_rel): Call generic expression parser to process arguments.
	Handle O_register case for individual predicates and O_subtract for
	ranges.
	(ia64_parse_name): Canonicalize name before looking it up in dynamic
	register hash.
	(ia64_canonicalize_symbol_name): Strip off all trailing # characters.
	Warn if multiple found, issue error if resulting symbol name has zero
	length.
	(dot_alias): Canonicalize name before use.

gas/testsuite/
2005-02-02  Jan Beulich  <jbeulich@novell.com>

	* gas/ia64/pound.[ls]: New.
	* gas/ia64/ia64.exp: Run new test.

--- /home/jbeulich/src/binutils/mainline/2005-02-01/gas/config/tc-ia64.c	2005-02-01 16:15:58.000000000 +0100
+++ 2005-02-01/gas/config/tc-ia64.c	2005-02-02 15:39:08.152745265 +0100
@@ -4499,6 +4499,7 @@ dot_rot (type)
   for (dr = md.dynreg[type]; dr && dr->num_regs; dr = dr->next)
     {
       hash_delete (md.dynreg_hash, dr->name);
+      obstack_free (&notes, (void *) dr->name);
       dr->num_regs = 0;
     }
 
@@ -4507,8 +4508,8 @@ dot_rot (type)
     {
       start = input_line_pointer;
       ch = get_symbol_end ();
+      len = strlen (ia64_canonicalize_symbol_name (start));
       *input_line_pointer = ch;
-      len = (input_line_pointer - start);
 
       SKIP_WHITESPACE ();
       if (*input_line_pointer != '[')
@@ -4577,6 +4578,7 @@ dot_rot (type)
       if (hash_insert (md.dynreg_hash, name, dr))
 	{
 	  as_bad ("Attempt to redefine register set `%s'", name);
+	  obstack_free (&notes, name);
 	  goto err;
 	}
 
@@ -4975,59 +4977,57 @@ dot_pred_rel (type)
   SKIP_WHITESPACE ();
   while (1)
     {
-      valueT bit = 1;
+      valueT bits = 1;
       int regno;
+      expressionS pr, *pr1, *pr2;
 
-      if (TOUPPER (*input_line_pointer) != 'P'
-	  || (regno = atoi (++input_line_pointer)) < 0
-	  || regno > 63)
-	{
-	  as_bad (_("Predicate register expected"));
-	  ignore_rest_of_line ();
-	  return;
-	}
-      while (ISDIGIT (*input_line_pointer))
-	++input_line_pointer;
-      if (p1 == -1)
-	p1 = regno;
-      else if (p2 == -1)
-	p2 = regno;
-      bit <<= regno;
-      if (mask & bit)
-	as_warn (_("Duplicate predicate register ignored"));
-      mask |= bit;
-      count++;
-      /* See if it's a range.  */
-      if (*input_line_pointer == '-')
-	{
-	  valueT stop = 1;
-	  ++input_line_pointer;
-
-	  if (TOUPPER (*input_line_pointer) != 'P'
-	      || (regno = atoi (++input_line_pointer)) < 0
-	      || regno > 63)
-	    {
-	      as_bad (_("Predicate register expected"));
-	      ignore_rest_of_line ();
-	      return;
-	    }
-	  while (ISDIGIT (*input_line_pointer))
-	    ++input_line_pointer;
-	  stop <<= regno;
-	  if (bit >= stop)
+      expression (&pr);
+      if (pr.X_op == O_register
+	  && pr.X_add_number >= REG_P
+	  && pr.X_add_number <= REG_P + 63)
+	{
+	  regno = pr.X_add_number - REG_P;
+	  bits <<= regno;
+	  count++;
+	  if (p1 == -1)
+	    p1 = regno;
+	  else if (p2 == -1)
+	    p2 = regno;
+	}
+      else if (type != 'i'
+	  && pr.X_op == O_subtract
+	  && (pr1 = symbol_get_value_expression (pr.X_add_symbol))
+	  && pr1->X_op == O_register
+	  && pr1->X_add_number >= REG_P
+	  && pr1->X_add_number <= REG_P + 63
+	  && (pr2 = symbol_get_value_expression (pr.X_op_symbol))
+	  && pr2->X_op == O_register
+	  && pr2->X_add_number >= REG_P
+	  && pr2->X_add_number <= REG_P + 63)
+	{
+	  /* It's a range.  */
+	  int stop;
+
+	  regno = pr1->X_add_number - REG_P;
+	  stop = pr2->X_add_number - REG_P;
+	  if (regno >= stop)
 	    {
 	      as_bad (_("Bad register range"));
 	      ignore_rest_of_line ();
 	      return;
 	    }
-	  while (bit < stop)
-	    {
-	      bit <<= 1;
-	      mask |= bit;
-	      count++;
-	    }
-	  SKIP_WHITESPACE ();
+	  bits = ((bits << stop) << 1) - (bits << regno);
+	  count += stop - regno + 1;
+	}
+      else
+	{
+	  as_bad (_("Predicate register expected"));
+	  ignore_rest_of_line ();
+	  return;
 	}
+      if (mask & bits)
+	as_warn (_("Duplicate predicate register ignored"));
+      mask |= bits;
       if (*input_line_pointer != ',')
 	break;
       ++input_line_pointer;
@@ -7644,6 +7644,9 @@ ia64_parse_name (name, e)
 	}
     }
 
+  end = alloca (strlen (name) + 1);
+  strcpy (end, name);
+  name = ia64_canonicalize_symbol_name (end);
   if ((dr = hash_find (md.dynreg_hash, name)))
     {
       /* We've got ourselves the name of a rotating register set.
@@ -7663,9 +7666,20 @@ char *
 ia64_canonicalize_symbol_name (name)
      char *name;
 {
-  size_t len = strlen (name);
-  if (len > 1 && name[len - 1] == '#')
-    name[len - 1] = '\0';
+  size_t len = strlen (name), full = len;
+
+  while (len > 0 && name[len - 1] == '#')
+    --len;
+  if (len <= 0)
+    {
+      if (full > 0)
+	as_bad ("Standalone `#' is illegal");
+      else
+	as_bad ("Zero-length symbol is illegal");
+    }
+  else if (len < full - 1)
+    as_warn ("Redundant `#' suffix operators");
+  name[len] = '\0';
   return name;
 }
 
@@ -11324,6 +11338,7 @@ dot_alias (int section)
 
   input_line_pointer++;
   *end_name = 0;
+  ia64_canonicalize_symbol_name (name);
 
   /* We call demand_copy_C_string to check if alias string is valid.
      There should be a closing `"' and no `\0' in the string.  */
--- /home/jbeulich/src/binutils/mainline/2005-02-01/gas/testsuite/gas/ia64/ia64.exp	2005-01-31 10:52:17.000000000 +0100
+++ 2005-02-01/gas/testsuite/gas/ia64/ia64.exp	2005-02-02 15:39:24.418370066 +0100
@@ -66,6 +66,7 @@ if [istarget "ia64-*"] then {
     run_dump_test "bundling"
     run_list_test "label" ""
     run_list_test "last" ""
+    run_list_test "pound" "-al"
     run_list_test "proc" ""
     run_list_test "slot2" ""
     run_list_test "unwind-err" ""
--- /home/jbeulich/src/binutils/mainline/2005-02-01/gas/testsuite/gas/ia64/pound.l	1970-01-01 01:00:00.000000000 +0100
+++ 2005-02-01/gas/testsuite/gas/ia64/pound.l	2005-02-02 14:20:57.000000000 +0100
@@ -0,0 +1,58 @@
+.*: Assembler messages:
+.*:35: Warning: .* WAW .*
+#...
+.*:41: Error: symbol .esym. .* .efunction.
+.*:43: Error: section .\.extra. .* .esection.
+GAS LISTING .*
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+\.explicit
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.global esym#
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.section \.extra#, "a", @progbits
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.text
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+	break		0
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+[[:xdigit:]]+[[:space:]]+\.proc psym
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+psym:
+[[:space:]]*[[:digit:]]+[[:space:]]+	mov\.ret\.sptk	b7 = r0, tag#
+[[:space:]]*[[:digit:]]+[[:space:]]+	mov		r8 = 0
+[[:space:]]*[[:digit:]]+[[:space:]]+\[tag:\]	br\.ret\.sptk	rp
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+[[:xdigit:]]+[[:space:]]+\.endp psym
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.proc esym#
+[[:space:]]*[[:digit:]]+[[:space:]]+\.entry entry#
+[[:space:]]*[[:digit:]]+[[:space:]]+esym:
+[[:space:]]*[[:digit:]]+[[:space:]]+\.unwentry
+[[:space:]]*[[:digit:]]+[[:space:]]+\.personality psym#
+[[:space:]]*[[:digit:]]+[[:space:]]+\.regstk 0, 8, 0, 8
+[[:space:]]*[[:digit:]]+[[:space:]]+\.rotp p#\[2\], p1#\[4\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\.rotr r#\[2\], r1#\[4\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\.reg\.val r#\[1\], 0
+[[:space:]]*[[:digit:]]+[[:space:]]+\.reg\.val r1#\[3\], 0
+[[:space:]]*[[:digit:]]+[[:space:]]+\(p1#\[1\]\) cmp\.eq	p\[0\] = r\[1\], r1#\[1\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\(p1#\[3\]\) cmp\.eq	p#\[1\] = r#\[1\], r1#\[3\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\.pred\.rel "mutex", p#\[0\], p\[1\]
+[[:space:]]*[[:digit:]]+[[:space:]]+	nop		0
+[[:space:]]*[[:digit:]]+[[:space:]]+	;;
+[[:space:]]*[[:digit:]]+[[:space:]]+entry:
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+61828446[[:space:]]+\(p\[0\]\)	mov		r8 = 1
+[[:space:]]*[[:digit:]]+[[:space:]]+00781509[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+95007000[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+00000400[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+\(p#\[1\]\)	mov		r8 = 0
+[[:space:]]*[[:digit:]]+[[:space:]]+	br\.ret\.sptk	rp
+[[:space:]]*[[:digit:]]+[[:space:]]+\.xdata4 \.extra#, -1
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+11420400+[[:space:]]+\.endp esym#
+[[:space:]]*[[:digit:]]+[[:space:]]+00648400[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+00004880[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+00008400[[:space:]]*
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+\.alias esym#, "efunction"
+[[:space:]]*[[:digit:]]+[[:space:]]+\.alias esym, "efunc"
+[[:space:]]*[[:digit:]]+[[:space:]]+\.secalias \.extra#, "esection"
+[[:space:]]*[[:digit:]]+[[:space:]]+\.secalias \.extra, "esec"
--- /home/jbeulich/src/binutils/mainline/2005-02-01/gas/testsuite/gas/ia64/pound.s	1970-01-01 01:00:00.000000000 +0100
+++ 2005-02-01/gas/testsuite/gas/ia64/pound.s	2005-02-02 13:23:59.000000000 +0100
@@ -0,0 +1,43 @@
+.explicit
+
+.global esym#
+
+.section .extra#, "a", @progbits
+
+.text
+
+	break		0
+
+.proc psym
+psym:
+	mov.ret.sptk	b7 = r0, tag#
+	mov		r8 = 0
+[tag:]	br.ret.sptk	rp
+.endp psym
+
+.proc esym#
+.entry entry#
+esym:
+.unwentry
+.personality psym#
+.regstk 0, 8, 0, 8
+.rotp p#[2], p1#[4]
+.rotr r#[2], r1#[4]
+.reg.val r#[1], 0
+.reg.val r1#[3], 0
+(p1#[1]) cmp.eq	p[0] = r[1], r1#[1]
+(p1#[3]) cmp.eq	p#[1] = r#[1], r1#[3]
+.pred.rel "mutex", p#[0], p[1]
+	nop		0
+	;;
+entry:
+(p[0])	mov		r8 = 1
+(p#[1])	mov		r8 = 0
+	br.ret.sptk	rp
+.xdata4 .extra#, -1
+.endp esym#
+
+.alias esym#, "efunction"
+.alias esym, "efunc"
+.secalias .extra#, "esection"
+.secalias .extra, "esec"

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ia64 unwind directive semantics
  2005-02-02 14:52 [PATCH] ia64 unwind directive semantics Jan Beulich
@ 2005-02-11  1:39 ` James E Wilson
  0 siblings, 0 replies; 10+ messages in thread
From: James E Wilson @ 2005-02-11  1:39 UTC (permalink / raw)
  To: Jan Beulich; +Cc: binutils

On Wed, 2005-02-02 at 06:52, Jan Beulich wrote:
>        hash_delete (md.dynreg_hash, dr->name);
> +      obstack_free (&notes, (void *) dr->name);

I don't believe this is safe.  obstacks are stack based.  When you call
obstack_free, not only does it free dr->name, but also everything newer
than it.  There is no guarantee that everything newer than dr->name is
unused.  This is very unlikely to be the case.  There could have been an
obstack call used for something else (non hash table) in the meantime.

There is also an efficiency issue here, as the right way to free these
string if we could would be with a single obstack_free call, for the
oldest string.  Calling obstack_free on each string means we are freeing
them multiple times, which is probably not good.

This is different than the demand_copy_C_string case, as in that case we
know that there is no other obstack allocation between the
demand_copy_C_string call and the obstack_free.

If we want to be able to free these strings here, then we can't use
obstack to allocate them.

>  	  as_bad ("Attempt to redefine register set `%s'", name);
> +	  obstack_free (&notes, name);

This one is safe, because we know that there are no other allocations on
the notes obstack since this string was allocated.

The rest of the patch looks OK.  This is your ia64-pound patch.
-- 
Jim Wilson, GNU Tools Support, http://www.SpecifixInc.com


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ia64 unwind directive semantics
       [not found] <s20ca004.024@emea1-mh.id2.novell.com>
@ 2005-02-11 23:15 ` James E Wilson
  0 siblings, 0 replies; 10+ messages in thread
From: James E Wilson @ 2005-02-11 23:15 UTC (permalink / raw)
  To: Jan Beulich; +Cc: binutils

On Fri, 2005-02-11 at 04:08, Jan Beulich wrote:
>Indeed. What lead me to think these aren't, despite their name,
>stack-like was the fact that dot_alias, in its error path, has two
>invocations of obstack_free; according what you say (the later) one
>should be sufficient there...

Yes, an oversight.  We only need one obstack_free call here.

> >If we want to be able to free these strings here, then we can't use
> >obstack to allocate them.
> Perhaps we should.

Or, alternatively, we can use a different obstack than notes.  If we
have an obstack used for dot_rot only, then we know that it will be save
to free everything, and we can do it with one obstack_free call.

> >This one is safe, because we know that there are no other allocations
> on
> >the notes obstack since this string was allocated.
> After you stated the above, it would seem to me that this isn't safe
> either, because there is another (conditional allocation inbetween).
> Thus the order of these two needs to be changed.

If hash_insert fails, then dr did not get allocated to the hash table,
and hence it is OK to free it.  However, looking again, I do see that
there is a possible problem with a dangling pointer.  I believe we can
fix that by moving the "drpp = &dr->next;" assignment after the
hash_insert if statement, and putting "*drpp = NULL;" inside the if
statement.

Your solution of allocating name after dr is also acceptable.

> 	* config/tc-ia64.c (dot_rot): Add comment that name strings
> should
> 	be freed when wiping out previous state. Canonicalize names
> before
> 	use. ...

Thanks.  This is OK.
-- 
Jim Wilson, GNU Tools Support, http://www.SpecifixInc.com


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ia64 unwind directive semantics
@ 2005-02-11 15:58 Jan Beulich
  0 siblings, 0 replies; 10+ messages in thread
From: Jan Beulich @ 2005-02-11 15:58 UTC (permalink / raw)
  To: wilson; +Cc: binutils

[-- Attachment #1: Type: text/plain, Size: 12276 bytes --]

>>> James E Wilson <wilson@specifixinc.com> 11.02.05 00:40:35 >>>
>On Wed, 2005-02-02 at 06:52, Jan Beulich wrote:
>>        hash_delete (md.dynreg_hash, dr->name);
>> +      obstack_free (&notes, (void *) dr->name);
>
>I don't believe this is safe.  obstacks are stack based.  When you
call
>obstack_free, not only does it free dr->name, but also everything
newer
>than it.  There is no guarantee that everything newer than dr->name
is
>unused.  This is very unlikely to be the case.  There could have been
an
>obstack call used for something else (non hash table) in the
meantime.

Indeed. What lead me to think these aren't, despite their name,
stack-like was the fact that dot_alias, in its error path, has two
invocations of obstack_free; according what you say (the later) one
should be sufficient there...

>There is also an efficiency issue here, as the right way to free
these
>string if we could would be with a single obstack_free call, for the
>oldest string.  Calling obstack_free on each string means we are
freeing
>them multiple times, which is probably not good.
>
>This is different than the demand_copy_C_string case, as in that case
we
>know that there is no other obstack allocation between the
>demand_copy_C_string call and the obstack_free.
>
>If we want to be able to free these strings here, then we can't use
>obstack to allocate them.

Perhaps we should.

>>  	  as_bad ("Attempt to redefine register set `%s'", name);
>> +	  obstack_free (&notes, name);
>
>This one is safe, because we know that there are no other allocations
on
>the notes obstack since this string was allocated.

After you stated the above, it would seem to me that this isn't safe
either, because there is another (conditional allocation inbetween).
Thus the order of these two needs to be changed.

Below/attached an updated patch.

Jan

gas/
2005-02-11  Jan Beulich  <jbeulich@novell.com>

	* config/tc-ia64.c (dot_rot): Add comment that name strings
should
	be freed when wiping out previous state. Canonicalize names
before
	use. Free name string when detecting redefinition.
	(dot_pred_rel): Call generic expression parser to process
arguments.
	Handle O_register case for individual predicates and O_subtract
for
	ranges.
	(ia64_parse_name): Canonicalize name before looking it up in
dynamic
	register hash.
	(ia64_canonicalize_symbol_name): Strip off all trailing #
characters.
	Warn if multiple found, issue error if resulting symbol name has
zero
	length.
	(dot_alias): Canonicalize name before use.

gas/testsuite/
2005-02-11  Jan Beulich  <jbeulich@novell.com>

	* gas/ia64/pound.[ls]: New.
	* gas/ia64/ia64.exp: Run new test.

---
/home/jbeulich/src/binutils/mainline/2005-02-11/gas/config/tc-ia64.c	2005-02-11
11:09:20.000000000 +0100
+++ 2005-02-11/gas/config/tc-ia64.c	2005-02-11 12:33:39.408990008
+0100
@@ -4479,6 +4479,7 @@ dot_rot (type)
   for (dr = md.dynreg[type]; dr && dr->num_regs; dr = dr->next)
     {
       hash_delete (md.dynreg_hash, dr->name);
+      /* FIXME: Free dr->name.  */
       dr->num_regs = 0;
     }
 
@@ -4487,8 +4488,8 @@ dot_rot (type)
     {
       start = input_line_pointer;
       ch = get_symbol_end ();
+      len = strlen (ia64_canonicalize_symbol_name (start));
       *input_line_pointer = ch;
-      len = (input_line_pointer - start);
 
       SKIP_WHITESPACE ();
       if (*input_line_pointer != '[')
@@ -4537,16 +4538,16 @@ dot_rot (type)
 	  break;
 	}
 
-      name = obstack_alloc (&notes, len + 1);
-      memcpy (name, start, len);
-      name[len] = '\0';
-
       if (!*drpp)
 	{
 	  *drpp = obstack_alloc (&notes, sizeof (*dr));
 	  memset (*drpp, 0, sizeof (*dr));
 	}
 
+      name = obstack_alloc (&notes, len + 1);
+      memcpy (name, start, len);
+      name[len] = '\0';
+
       dr = *drpp;
       dr->name = name;
       dr->num_regs = num_regs;
@@ -4557,6 +4558,7 @@ dot_rot (type)
       if (hash_insert (md.dynreg_hash, name, dr))
 	{
 	  as_bad ("Attempt to redefine register set `%s'", name);
+	  obstack_free (&notes, name);
 	  goto err;
 	}
 
@@ -4984,59 +4986,57 @@ dot_pred_rel (type)
   SKIP_WHITESPACE ();
   while (1)
     {
-      valueT bit = 1;
+      valueT bits = 1;
       int regno;
+      expressionS pr, *pr1, *pr2;
 
-      if (TOUPPER (*input_line_pointer) != 'P'
-	  || (regno = atoi (++input_line_pointer)) < 0
-	  || regno > 63)
-	{
-	  as_bad (_("Predicate register expected"));
-	  ignore_rest_of_line ();
-	  return;
-	}
-      while (ISDIGIT (*input_line_pointer))
-	++input_line_pointer;
-      if (p1 == -1)
-	p1 = regno;
-      else if (p2 == -1)
-	p2 = regno;
-      bit <<= regno;
-      if (mask & bit)
-	as_warn (_("Duplicate predicate register ignored"));
-      mask |= bit;
-      count++;
-      /* See if it's a range.  */
-      if (*input_line_pointer == '-')
-	{
-	  valueT stop = 1;
-	  ++input_line_pointer;
-
-	  if (TOUPPER (*input_line_pointer) != 'P'
-	      || (regno = atoi (++input_line_pointer)) < 0
-	      || regno > 63)
-	    {
-	      as_bad (_("Predicate register expected"));
-	      ignore_rest_of_line ();
-	      return;
-	    }
-	  while (ISDIGIT (*input_line_pointer))
-	    ++input_line_pointer;
-	  stop <<= regno;
-	  if (bit >= stop)
+      expression (&pr);
+      if (pr.X_op == O_register
+	  && pr.X_add_number >= REG_P
+	  && pr.X_add_number <= REG_P + 63)
+	{
+	  regno = pr.X_add_number - REG_P;
+	  bits <<= regno;
+	  count++;
+	  if (p1 == -1)
+	    p1 = regno;
+	  else if (p2 == -1)
+	    p2 = regno;
+	}
+      else if (type != 'i'
+	  && pr.X_op == O_subtract
+	  && (pr1 = symbol_get_value_expression (pr.X_add_symbol))
+	  && pr1->X_op == O_register
+	  && pr1->X_add_number >= REG_P
+	  && pr1->X_add_number <= REG_P + 63
+	  && (pr2 = symbol_get_value_expression (pr.X_op_symbol))
+	  && pr2->X_op == O_register
+	  && pr2->X_add_number >= REG_P
+	  && pr2->X_add_number <= REG_P + 63)
+	{
+	  /* It's a range.  */
+	  int stop;
+
+	  regno = pr1->X_add_number - REG_P;
+	  stop = pr2->X_add_number - REG_P;
+	  if (regno >= stop)
 	    {
 	      as_bad (_("Bad register range"));
 	      ignore_rest_of_line ();
 	      return;
 	    }
-	  while (bit < stop)
-	    {
-	      bit <<= 1;
-	      mask |= bit;
-	      count++;
-	    }
-	  SKIP_WHITESPACE ();
+	  bits = ((bits << stop) << 1) - (bits << regno);
+	  count += stop - regno + 1;
+	}
+      else
+	{
+	  as_bad (_("Predicate register expected"));
+	  ignore_rest_of_line ();
+	  return;
 	}
+      if (mask & bits)
+	as_warn (_("Duplicate predicate register ignored"));
+      mask |= bits;
       if (*input_line_pointer != ',')
 	break;
       ++input_line_pointer;
@@ -7639,6 +7639,9 @@ ia64_parse_name (name, e, nextcharP)
 	}
     }
 
+  end = alloca (strlen (name) + 1);
+  strcpy (end, name);
+  name = ia64_canonicalize_symbol_name (end);
   if ((dr = hash_find (md.dynreg_hash, name)))
     {
       /* We've got ourselves the name of a rotating register set.
@@ -7658,9 +7661,20 @@ char *
 ia64_canonicalize_symbol_name (name)
      char *name;
 {
-  size_t len = strlen (name);
-  if (len > 1 && name[len - 1] == '#')
-    name[len - 1] = '\0';
+  size_t len = strlen (name), full = len;
+
+  while (len > 0 && name[len - 1] == '#')
+    --len;
+  if (len <= 0)
+    {
+      if (full > 0)
+	as_bad ("Standalone `#' is illegal");
+      else
+	as_bad ("Zero-length symbol is illegal");
+    }
+  else if (len < full - 1)
+    as_warn ("Redundant `#' suffix operators");
+  name[len] = '\0';
   return name;
 }
 
@@ -11229,6 +11243,7 @@ dot_alias (int section)
 
   input_line_pointer++;
   *end_name = 0;
+  ia64_canonicalize_symbol_name (name);
 
   /* We call demand_copy_C_string to check if alias string is valid.
      There should be a closing `"' and no `\0' in the string.  */
---
/home/jbeulich/src/binutils/mainline/2005-02-11/gas/testsuite/gas/ia64/ia64.exp	2005-02-02
08:33:18.000000000 +0100
+++ 2005-02-11/gas/testsuite/gas/ia64/ia64.exp	2005-02-11
12:29:05.257667344 +0100
@@ -67,6 +67,7 @@ if [istarget "ia64-*"] then {
     run_dump_test "bundling"
     run_list_test "label" ""
     run_list_test "last" ""
+    run_list_test "pound" "-al"
     run_list_test "proc" ""
     run_list_test "slot2" ""
     run_list_test "unwind-err" ""
---
/home/jbeulich/src/binutils/mainline/2005-02-11/gas/testsuite/gas/ia64/pound.l	1970-01-01
01:00:00.000000000 +0100
+++ 2005-02-11/gas/testsuite/gas/ia64/pound.l	2005-02-02
14:20:57.000000000 +0100
@@ -0,0 +1,58 @@
+.*: Assembler messages:
+.*:35: Warning: .* WAW .*
+#...
+.*:41: Error: symbol .esym. .* .efunction.
+.*:43: Error: section .\.extra. .* .esection.
+GAS LISTING .*
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+\.explicit
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.global esym#
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.section \.extra#, "a",
@progbits
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.text
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+	break		0
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+[[:xdigit:]]+[[:space:]]+\.proc
psym
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+psym:
+[[:space:]]*[[:digit:]]+[[:space:]]+	mov\.ret\.sptk	b7 = r0, tag#
+[[:space:]]*[[:digit:]]+[[:space:]]+	mov		r8 = 0
+[[:space:]]*[[:digit:]]+[[:space:]]+\[tag:\]	br\.ret\.sptk	rp
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+[[:xdigit:]]+[[:space:]]+\.endp
psym
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.proc esym#
+[[:space:]]*[[:digit:]]+[[:space:]]+\.entry entry#
+[[:space:]]*[[:digit:]]+[[:space:]]+esym:
+[[:space:]]*[[:digit:]]+[[:space:]]+\.unwentry
+[[:space:]]*[[:digit:]]+[[:space:]]+\.personality psym#
+[[:space:]]*[[:digit:]]+[[:space:]]+\.regstk 0, 8, 0, 8
+[[:space:]]*[[:digit:]]+[[:space:]]+\.rotp p#\[2\], p1#\[4\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\.rotr r#\[2\], r1#\[4\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\.reg\.val r#\[1\], 0
+[[:space:]]*[[:digit:]]+[[:space:]]+\.reg\.val r1#\[3\], 0
+[[:space:]]*[[:digit:]]+[[:space:]]+\(p1#\[1\]\) cmp\.eq	p\[0\] =
r\[1\], r1#\[1\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\(p1#\[3\]\) cmp\.eq	p#\[1\]
= r#\[1\], r1#\[3\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\.pred\.rel "mutex", p#\[0\],
p\[1\]
+[[:space:]]*[[:digit:]]+[[:space:]]+	nop		0
+[[:space:]]*[[:digit:]]+[[:space:]]+	;;
+[[:space:]]*[[:digit:]]+[[:space:]]+entry:
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+61828446[[:space:]]+\(p\[0\]\)	mov		r8
= 1
+[[:space:]]*[[:digit:]]+[[:space:]]+00781509[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+95007000[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+00000400[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+\(p#\[1\]\)	mov		r8
= 0
+[[:space:]]*[[:digit:]]+[[:space:]]+	br\.ret\.sptk	rp
+[[:space:]]*[[:digit:]]+[[:space:]]+\.xdata4 \.extra#, -1
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+11420400+[[:space:]]+\.endp
esym#
+[[:space:]]*[[:digit:]]+[[:space:]]+00648400[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+00004880[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+00008400[[:space:]]*
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+\.alias esym#, "efunction"
+[[:space:]]*[[:digit:]]+[[:space:]]+\.alias esym, "efunc"
+[[:space:]]*[[:digit:]]+[[:space:]]+\.secalias \.extra#, "esection"
+[[:space:]]*[[:digit:]]+[[:space:]]+\.secalias \.extra, "esec"
---
/home/jbeulich/src/binutils/mainline/2005-02-11/gas/testsuite/gas/ia64/pound.s	1970-01-01
01:00:00.000000000 +0100
+++ 2005-02-11/gas/testsuite/gas/ia64/pound.s	2005-02-02
13:23:59.000000000 +0100
@@ -0,0 +1,43 @@
+.explicit
+
+.global esym#
+
+.section .extra#, "a", @progbits
+
+.text
+
+	break		0
+
+.proc psym
+psym:
+	mov.ret.sptk	b7 = r0, tag#
+	mov		r8 = 0
+[tag:]	br.ret.sptk	rp
+.endp psym
+
+.proc esym#
+.entry entry#
+esym:
+.unwentry
+.personality psym#
+.regstk 0, 8, 0, 8
+.rotp p#[2], p1#[4]
+.rotr r#[2], r1#[4]
+.reg.val r#[1], 0
+.reg.val r1#[3], 0
+(p1#[1]) cmp.eq	p[0] = r[1], r1#[1]
+(p1#[3]) cmp.eq	p#[1] = r#[1], r1#[3]
+.pred.rel "mutex", p#[0], p[1]
+	nop		0
+	;;
+entry:
+(p[0])	mov		r8 = 1
+(p#[1])	mov		r8 = 0
+	br.ret.sptk	rp
+.xdata4 .extra#, -1
+.endp esym#
+
+.alias esym#, "efunction"
+.alias esym, "efunc"
+.secalias .extra#, "esection"
+.secalias .extra, "esec"


[-- Attachment #2: binutils-mainline-ia64-pound.patch --]
[-- Type: text/plain, Size: 10627 bytes --]

In various places, the # suffix used to distinguish user-defined symbols from
built-in ones (i.e. register names) did not work as expected.

Built and tested on ia64-unknown-linux-gnu.

Jan

gas/
2005-02-11  Jan Beulich  <jbeulich@novell.com>

	* config/tc-ia64.c (dot_rot): Add comment that name strings should
	be freed when wiping out previous state. Canonicalize names before
	use. Free name string when detecting redefinition.
	(dot_pred_rel): Call generic expression parser to process arguments.
	Handle O_register case for individual predicates and O_subtract for
	ranges.
	(ia64_parse_name): Canonicalize name before looking it up in dynamic
	register hash.
	(ia64_canonicalize_symbol_name): Strip off all trailing # characters.
	Warn if multiple found, issue error if resulting symbol name has zero
	length.
	(dot_alias): Canonicalize name before use.

gas/testsuite/
2005-02-11  Jan Beulich  <jbeulich@novell.com>

	* gas/ia64/pound.[ls]: New.
	* gas/ia64/ia64.exp: Run new test.

--- /home/jbeulich/src/binutils/mainline/2005-02-11/gas/config/tc-ia64.c	2005-02-11 11:09:20.000000000 +0100
+++ 2005-02-11/gas/config/tc-ia64.c	2005-02-11 12:33:39.408990008 +0100
@@ -4479,6 +4479,7 @@ dot_rot (type)
   for (dr = md.dynreg[type]; dr && dr->num_regs; dr = dr->next)
     {
       hash_delete (md.dynreg_hash, dr->name);
+      /* FIXME: Free dr->name.  */
       dr->num_regs = 0;
     }
 
@@ -4487,8 +4488,8 @@ dot_rot (type)
     {
       start = input_line_pointer;
       ch = get_symbol_end ();
+      len = strlen (ia64_canonicalize_symbol_name (start));
       *input_line_pointer = ch;
-      len = (input_line_pointer - start);
 
       SKIP_WHITESPACE ();
       if (*input_line_pointer != '[')
@@ -4537,16 +4538,16 @@ dot_rot (type)
 	  break;
 	}
 
-      name = obstack_alloc (&notes, len + 1);
-      memcpy (name, start, len);
-      name[len] = '\0';
-
       if (!*drpp)
 	{
 	  *drpp = obstack_alloc (&notes, sizeof (*dr));
 	  memset (*drpp, 0, sizeof (*dr));
 	}
 
+      name = obstack_alloc (&notes, len + 1);
+      memcpy (name, start, len);
+      name[len] = '\0';
+
       dr = *drpp;
       dr->name = name;
       dr->num_regs = num_regs;
@@ -4557,6 +4558,7 @@ dot_rot (type)
       if (hash_insert (md.dynreg_hash, name, dr))
 	{
 	  as_bad ("Attempt to redefine register set `%s'", name);
+	  obstack_free (&notes, name);
 	  goto err;
 	}
 
@@ -4984,59 +4986,57 @@ dot_pred_rel (type)
   SKIP_WHITESPACE ();
   while (1)
     {
-      valueT bit = 1;
+      valueT bits = 1;
       int regno;
+      expressionS pr, *pr1, *pr2;
 
-      if (TOUPPER (*input_line_pointer) != 'P'
-	  || (regno = atoi (++input_line_pointer)) < 0
-	  || regno > 63)
-	{
-	  as_bad (_("Predicate register expected"));
-	  ignore_rest_of_line ();
-	  return;
-	}
-      while (ISDIGIT (*input_line_pointer))
-	++input_line_pointer;
-      if (p1 == -1)
-	p1 = regno;
-      else if (p2 == -1)
-	p2 = regno;
-      bit <<= regno;
-      if (mask & bit)
-	as_warn (_("Duplicate predicate register ignored"));
-      mask |= bit;
-      count++;
-      /* See if it's a range.  */
-      if (*input_line_pointer == '-')
-	{
-	  valueT stop = 1;
-	  ++input_line_pointer;
-
-	  if (TOUPPER (*input_line_pointer) != 'P'
-	      || (regno = atoi (++input_line_pointer)) < 0
-	      || regno > 63)
-	    {
-	      as_bad (_("Predicate register expected"));
-	      ignore_rest_of_line ();
-	      return;
-	    }
-	  while (ISDIGIT (*input_line_pointer))
-	    ++input_line_pointer;
-	  stop <<= regno;
-	  if (bit >= stop)
+      expression (&pr);
+      if (pr.X_op == O_register
+	  && pr.X_add_number >= REG_P
+	  && pr.X_add_number <= REG_P + 63)
+	{
+	  regno = pr.X_add_number - REG_P;
+	  bits <<= regno;
+	  count++;
+	  if (p1 == -1)
+	    p1 = regno;
+	  else if (p2 == -1)
+	    p2 = regno;
+	}
+      else if (type != 'i'
+	  && pr.X_op == O_subtract
+	  && (pr1 = symbol_get_value_expression (pr.X_add_symbol))
+	  && pr1->X_op == O_register
+	  && pr1->X_add_number >= REG_P
+	  && pr1->X_add_number <= REG_P + 63
+	  && (pr2 = symbol_get_value_expression (pr.X_op_symbol))
+	  && pr2->X_op == O_register
+	  && pr2->X_add_number >= REG_P
+	  && pr2->X_add_number <= REG_P + 63)
+	{
+	  /* It's a range.  */
+	  int stop;
+
+	  regno = pr1->X_add_number - REG_P;
+	  stop = pr2->X_add_number - REG_P;
+	  if (regno >= stop)
 	    {
 	      as_bad (_("Bad register range"));
 	      ignore_rest_of_line ();
 	      return;
 	    }
-	  while (bit < stop)
-	    {
-	      bit <<= 1;
-	      mask |= bit;
-	      count++;
-	    }
-	  SKIP_WHITESPACE ();
+	  bits = ((bits << stop) << 1) - (bits << regno);
+	  count += stop - regno + 1;
+	}
+      else
+	{
+	  as_bad (_("Predicate register expected"));
+	  ignore_rest_of_line ();
+	  return;
 	}
+      if (mask & bits)
+	as_warn (_("Duplicate predicate register ignored"));
+      mask |= bits;
       if (*input_line_pointer != ',')
 	break;
       ++input_line_pointer;
@@ -7639,6 +7639,9 @@ ia64_parse_name (name, e, nextcharP)
 	}
     }
 
+  end = alloca (strlen (name) + 1);
+  strcpy (end, name);
+  name = ia64_canonicalize_symbol_name (end);
   if ((dr = hash_find (md.dynreg_hash, name)))
     {
       /* We've got ourselves the name of a rotating register set.
@@ -7658,9 +7661,20 @@ char *
 ia64_canonicalize_symbol_name (name)
      char *name;
 {
-  size_t len = strlen (name);
-  if (len > 1 && name[len - 1] == '#')
-    name[len - 1] = '\0';
+  size_t len = strlen (name), full = len;
+
+  while (len > 0 && name[len - 1] == '#')
+    --len;
+  if (len <= 0)
+    {
+      if (full > 0)
+	as_bad ("Standalone `#' is illegal");
+      else
+	as_bad ("Zero-length symbol is illegal");
+    }
+  else if (len < full - 1)
+    as_warn ("Redundant `#' suffix operators");
+  name[len] = '\0';
   return name;
 }
 
@@ -11229,6 +11243,7 @@ dot_alias (int section)
 
   input_line_pointer++;
   *end_name = 0;
+  ia64_canonicalize_symbol_name (name);
 
   /* We call demand_copy_C_string to check if alias string is valid.
      There should be a closing `"' and no `\0' in the string.  */
--- /home/jbeulich/src/binutils/mainline/2005-02-11/gas/testsuite/gas/ia64/ia64.exp	2005-02-02 08:33:18.000000000 +0100
+++ 2005-02-11/gas/testsuite/gas/ia64/ia64.exp	2005-02-11 12:29:05.257667344 +0100
@@ -67,6 +67,7 @@ if [istarget "ia64-*"] then {
     run_dump_test "bundling"
     run_list_test "label" ""
     run_list_test "last" ""
+    run_list_test "pound" "-al"
     run_list_test "proc" ""
     run_list_test "slot2" ""
     run_list_test "unwind-err" ""
--- /home/jbeulich/src/binutils/mainline/2005-02-11/gas/testsuite/gas/ia64/pound.l	1970-01-01 01:00:00.000000000 +0100
+++ 2005-02-11/gas/testsuite/gas/ia64/pound.l	2005-02-02 14:20:57.000000000 +0100
@@ -0,0 +1,58 @@
+.*: Assembler messages:
+.*:35: Warning: .* WAW .*
+#...
+.*:41: Error: symbol .esym. .* .efunction.
+.*:43: Error: section .\.extra. .* .esection.
+GAS LISTING .*
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+\.explicit
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.global esym#
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.section \.extra#, "a", @progbits
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.text
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+	break		0
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+[[:xdigit:]]+[[:space:]]+\.proc psym
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+psym:
+[[:space:]]*[[:digit:]]+[[:space:]]+	mov\.ret\.sptk	b7 = r0, tag#
+[[:space:]]*[[:digit:]]+[[:space:]]+	mov		r8 = 0
+[[:space:]]*[[:digit:]]+[[:space:]]+\[tag:\]	br\.ret\.sptk	rp
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+[[:xdigit:]]+[[:space:]]+\.endp psym
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+
+[[:space:]]*[[:digit:]]+[[:space:]]+\.proc esym#
+[[:space:]]*[[:digit:]]+[[:space:]]+\.entry entry#
+[[:space:]]*[[:digit:]]+[[:space:]]+esym:
+[[:space:]]*[[:digit:]]+[[:space:]]+\.unwentry
+[[:space:]]*[[:digit:]]+[[:space:]]+\.personality psym#
+[[:space:]]*[[:digit:]]+[[:space:]]+\.regstk 0, 8, 0, 8
+[[:space:]]*[[:digit:]]+[[:space:]]+\.rotp p#\[2\], p1#\[4\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\.rotr r#\[2\], r1#\[4\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\.reg\.val r#\[1\], 0
+[[:space:]]*[[:digit:]]+[[:space:]]+\.reg\.val r1#\[3\], 0
+[[:space:]]*[[:digit:]]+[[:space:]]+\(p1#\[1\]\) cmp\.eq	p\[0\] = r\[1\], r1#\[1\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\(p1#\[3\]\) cmp\.eq	p#\[1\] = r#\[1\], r1#\[3\]
+[[:space:]]*[[:digit:]]+[[:space:]]+\.pred\.rel "mutex", p#\[0\], p\[1\]
+[[:space:]]*[[:digit:]]+[[:space:]]+	nop		0
+[[:space:]]*[[:digit:]]+[[:space:]]+	;;
+[[:space:]]*[[:digit:]]+[[:space:]]+entry:
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+61828446[[:space:]]+\(p\[0\]\)	mov		r8 = 1
+[[:space:]]*[[:digit:]]+[[:space:]]+00781509[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+95007000[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+00000400[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+\(p#\[1\]\)	mov		r8 = 0
+[[:space:]]*[[:digit:]]+[[:space:]]+	br\.ret\.sptk	rp
+[[:space:]]*[[:digit:]]+[[:space:]]+\.xdata4 \.extra#, -1
+[[:space:]]*[[:digit:]]+[[:space:]]+\?*[[:space:]]+11420400+[[:space:]]+\.endp esym#
+[[:space:]]*[[:digit:]]+[[:space:]]+00648400[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+00004880[[:space:]]*
+[[:space:]]*[[:digit:]]+[[:space:]]+00008400[[:space:]]*
+#...
+[[:space:]]*[[:digit:]]+[[:space:]]+\.alias esym#, "efunction"
+[[:space:]]*[[:digit:]]+[[:space:]]+\.alias esym, "efunc"
+[[:space:]]*[[:digit:]]+[[:space:]]+\.secalias \.extra#, "esection"
+[[:space:]]*[[:digit:]]+[[:space:]]+\.secalias \.extra, "esec"
--- /home/jbeulich/src/binutils/mainline/2005-02-11/gas/testsuite/gas/ia64/pound.s	1970-01-01 01:00:00.000000000 +0100
+++ 2005-02-11/gas/testsuite/gas/ia64/pound.s	2005-02-02 13:23:59.000000000 +0100
@@ -0,0 +1,43 @@
+.explicit
+
+.global esym#
+
+.section .extra#, "a", @progbits
+
+.text
+
+	break		0
+
+.proc psym
+psym:
+	mov.ret.sptk	b7 = r0, tag#
+	mov		r8 = 0
+[tag:]	br.ret.sptk	rp
+.endp psym
+
+.proc esym#
+.entry entry#
+esym:
+.unwentry
+.personality psym#
+.regstk 0, 8, 0, 8
+.rotp p#[2], p1#[4]
+.rotr r#[2], r1#[4]
+.reg.val r#[1], 0
+.reg.val r1#[3], 0
+(p1#[1]) cmp.eq	p[0] = r[1], r1#[1]
+(p1#[3]) cmp.eq	p#[1] = r#[1], r1#[3]
+.pred.rel "mutex", p#[0], p[1]
+	nop		0
+	;;
+entry:
+(p[0])	mov		r8 = 1
+(p#[1])	mov		r8 = 0
+	br.ret.sptk	rp
+.xdata4 .extra#, -1
+.endp esym#
+
+.alias esym#, "efunction"
+.alias esym, "efunc"
+.secalias .extra#, "esection"
+.secalias .extra, "esec"

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ia64 unwind directive semantics
@ 2005-02-02 13:56 Jan Beulich
  0 siblings, 0 replies; 10+ messages in thread
From: Jan Beulich @ 2005-02-02 13:56 UTC (permalink / raw)
  To: amodra; +Cc: binutils

Sure, that's exactly what the (generated) assembly file asks for: .proc
and .endp are there, but the symbol surely can't get defined there
(because it has to live in crti.s). You have to either remove the ill
.proc/.endp pairs (and thus also the unwind info), or give these
(currently anonymous) functions names (i.e. .init and .fini, hiding them
completely from the outside world).

The whole setup seems a little odd to me, though: By having these
procedures split into two pieces (with, in the final executable, an
intervening range not covered by a procedure at all), unwind information
will be useless during the execution of all the init/fini functions (not
even their sizes will be set correctly), and thus the use of .proc/.endp
is pointless here except for the implict setting of the symbol's type.
I'd consider it much cleaner if it used just a label and a .type
directive.

In any case, the change to gas is correct (and both Jim Wilson, who
approved it, and I expected cases like this to come up).

Jan

>>> Alan Modra <amodra@bigpond.net.au> 02.02.05 09:16:15 >>>
On Mon, Jan 24, 2005 at 12:29:07PM +0100, Jan Beulich wrote:
> 	(dot_endp): Call in_procedure. Declare proc_end. Check for
non-zero-
> 	length entry point names. Check that entry points became
defined.

This one breaks glibc build.

csu/crtn.S: Assembler messages:
csu/crtn.S:22: Error: `_init#' was not defined within procedure
csu/crtn.S:36: Error: `_fini#' was not defined within procedure

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ia64 unwind directive semantics
  2005-01-24 11:29 Jan Beulich
  2005-01-28  3:52 ` James E Wilson
@ 2005-02-02  8:16 ` Alan Modra
  1 sibling, 0 replies; 10+ messages in thread
From: Alan Modra @ 2005-02-02  8:16 UTC (permalink / raw)
  To: Jan Beulich; +Cc: binutils

On Mon, Jan 24, 2005 at 12:29:07PM +0100, Jan Beulich wrote:
> 	(dot_endp): Call in_procedure. Declare proc_end. Check for non-zero-
> 	length entry point names. Check that entry points became defined.

This one breaks glibc build.

csu/crtn.S: Assembler messages:
csu/crtn.S:22: Error: `_init#' was not defined within procedure
csu/crtn.S:36: Error: `_fini#' was not defined within procedure

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ia64 unwind directive semantics
       [not found] <s1fa08eb.028@emea1-mh.id2.novell.com>
@ 2005-01-29  1:49 ` James E Wilson
  0 siblings, 0 replies; 10+ messages in thread
From: James E Wilson @ 2005-01-29  1:49 UTC (permalink / raw)
  To: Jan Beulich; +Cc: binutils

On Fri, 2005-01-28 at 01:42, Jan Beulich wrote:
>  Jim wilson wrote:
> >Hopefully gcc emits unwind info that passes all of these tests. 
> So do I hope. But if not, they're at fault...

I already noticed one.  The gcc -pg support is broken, it both emits
instructions without unwind info, and does a section switch.  This will
need to be fixed.  It won't work anymore after this patch goes in.  This
is GCC PR 12455, and Steve Ellcey is looking at the problem because gcc
-pg doesn't work right under HPUX.

> Actually, if you use expr_build_dot at the point or .proc, things may
> get entirely wrong if the primary entry point doesn't immediately
> follow.

Yes, either way, we need to make assumptions, and it isn't clear that
either set of assumptions is worse than the other.  I'm willing to go
along with your patch, but if I find a problem I will switch back to the
old way.

In theory, everyone should be emitting the function label immediately
after the .proc, and giving the function name as the first argument to
the .proc, in which case it doesn't matter which way we do this.  Either
way we get the same answer, so in theory this change should be harmless.

This patch is OK.
-- 
Jim Wilson, GNU Tools Support, http://www.SpecifixInc.com


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ia64 unwind directive semantics
@ 2005-01-28  9:43 Jan Beulich
  0 siblings, 0 replies; 10+ messages in thread
From: Jan Beulich @ 2005-01-28  9:43 UTC (permalink / raw)
  To: wilson; +Cc: binutils

[-- Attachment #1: Type: text/plain, Size: 22821 bytes --]

>The testcases don't test all of the errors you added.  In particular,
>the prologue/body before first insn messages.  Also the proc/endp
errors
>for a missing name, but those ones are obvious enough that I don't
see
>the need for tests for them.

Added.

>Hopefully gcc emits unwind info that passes all of these tests. 
>Likewise, for assembly code in glibc and the linux kernel.  I will
have
>to check all of this after all of these patches go in.

So do I hope. But if not, they're at fault...

>I am not sure about one of the proc/endp changes you added.  For
proc,
>you replaced unwind.proc_start with sym.  But that works only if sym
is
>defined immediately after the proc.  I would expect that to be true,
but
>don't think it is safe to assume it.  Also, if a procedure has
multiple
>entry points, can we really be sure that the first name listed is the
>entry point with the lowest address?  Using expr_build_dot here
avoids
>these problems, and should be perfectly safe.  I am not sure why the
>existing code sets proc_start to sym if it is zero.  I think that is
a
>bug, as it should never be zero here, as expr_build_dot should never
>return zero.  I suspect the code originally worked as you wrote it,
and
>then later got fixed to use expr_build_dot instead of sym because
that
>didn't work, but we forgot to remove part of the old code.

This was actually intentional, and again to match ias behavior.
Actually, if you use expr_build_dot at the point or .proc, things may
get entirely wrong if the primary entry point doesn't immediately
follow. Just consider the case where you have some auxiliary
instructions there (no matter how you might be able to reach/use them).
Of course, such constructs could equally well live outside the function,
so the issue here might be similar to the one with data embedded in
functions. Hence I would perhaps be ready to agree to do the replacement
you suggest, provided ias compatibility is of no interest here. Let me
know...

>> +	  if (!sym || !S_IS_DEFINED (sym))
>> +	    as_bad ("`%s' was not defined within procedure", name);
>> +	  else if (sym && unwind.proc_start
>
>You have a redundant check for sym here.  It is guaranteed to be
>non-zero in the second if, so we don't need to check it again.

Indeed, removed (I had just converted the original 'if' into an 'else
if').

Jan

gas/
2005-01-28  Jan Beulich  <jbeulich@novell.com>

	* config/tc-ia64.c (unwind): Remove proc_end (now an automatic
	variable in dot_endp). Add body and insn. Make prologue,
	prologue_mask, body, and insn bitfields.
	(fixup_unw_records): Remove spurious new-lines from end of
diagnostic
	messages.
	(in_procedure, in_prologue, in_body): New.
	(dot_fframe, dot_vframe, dot_vframesp, dot_vframepsp, dot_save,
	dot_restore, dot_restorereg, dot_restorereg_p, dot_handlerdata,
	dot_unwentry, dot_altrp, dot_savemem, dot_saveg, dot_savef,
dot_saveb,
	dot_savegf, dot_spill, dot_spillreg, dot_spillmem,
dot_spillreg_p,
	dot_spillmem_p, dot_label_state, dot_copy_state, dot_unwabi,
	dot_personality): Use the appropriate one of the above.
	(dot_proc): Clear unwind.proc_start; set to current location
only if
	none of the entry points were valid. Check for non-zero-length
entry
	point names. Check that entry points aren't defined, yet. Clear
	unwind.prologue, unwind.body, and unwind.insn.
	(dot_body): Call in_procedure. Check that first directive in
procedure
	had no insns emitted before. Set unwind.body.
	(dot_prologue): Call in_procedure. Check that not already in
prologue.
	Check that first directive in procedure had no insns emitted
before.
	Clear unwind.body.
	(dot_endp): Call in_procedure. Declare proc_end. Check for
non-zero-
	length entry point names. Check that entry points became
defined.
	(md_assemble): Set unwind.insn once unwind.proc_start is
defined.

gas/testsuite/
2005-01-28  Jan Beulich  <jbeulich@novell.com>

	* gas/ia64/proc.[ls]: New.
	* gas/ia64/unwind-err.[ls]: New.
	* gas/ia64/ia64.exp: Run new tests.

---
/home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/config/tc-ia64.c	2005-01-18
10:43:33.000000000 +0100
+++ 2005-01-24.08.40/gas/config/tc-ia64.c	2005-01-28
09:08:24.001717204 +0100
@@ -684,7 +684,6 @@ static struct
 
   /* These are used to create the unwind table entry for this
function.  */
   symbolS *proc_start;
-  symbolS *proc_end;
   symbolS *info;		/* pointer to unwind info */
   symbolS *personality_routine;
   segT saved_text_seg;
@@ -692,8 +691,10 @@ static struct
   unsigned int force_unwind_entry : 1;	/* force generation of
unwind entry? */
 
   /* TRUE if processing unwind directives in a prologue region.  */
-  int prologue;
-  int prologue_mask;
+  unsigned int prologue : 1;
+  unsigned int prologue_mask : 4;
+  unsigned int body : 1;
+  unsigned int insn : 1;
   unsigned int prologue_count;	/* number of .prologues seen so
far */
   /* Prologue counts at previous .label_state directives.  */
   struct label_prologue_count * saved_prologue_counts;
@@ -2785,7 +2786,7 @@ fixup_unw_records (list, before_relax)
 	case frgr_mem:
 	  if (!region)
 	    {
-	      as_bad ("frgr_mem record before region record!\n");
+	      as_bad ("frgr_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.fr_mem |= ptr->r.record.p.frmask;
@@ -2796,7 +2797,7 @@ fixup_unw_records (list, before_relax)
 	case fr_mem:
 	  if (!region)
 	    {
-	      as_bad ("fr_mem record before region record!\n");
+	      as_bad ("fr_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.fr_mem |= ptr->r.record.p.rmask;
@@ -2805,7 +2806,7 @@ fixup_unw_records (list, before_relax)
 	case gr_mem:
 	  if (!region)
 	    {
-	      as_bad ("gr_mem record before region record!\n");
+	      as_bad ("gr_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.gr_mem |= ptr->r.record.p.rmask;
@@ -2814,7 +2815,7 @@ fixup_unw_records (list, before_relax)
 	case br_mem:
 	  if (!region)
 	    {
-	      as_bad ("br_mem record before region record!\n");
+	      as_bad ("br_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.br_mem |= ptr->r.record.p.brmask;
@@ -2824,7 +2825,7 @@ fixup_unw_records (list, before_relax)
 	case gr_gr:
 	  if (!region)
 	    {
-	      as_bad ("gr_gr record before region record!\n");
+	      as_bad ("gr_gr record before region record!");
 	      return;
 	    }
 	  set_imask (region, ptr->r.record.p.grmask, t, 2);
@@ -2832,7 +2833,7 @@ fixup_unw_records (list, before_relax)
 	case br_gr:
 	  if (!region)
 	    {
-	      as_bad ("br_gr record before region record!\n");
+	      as_bad ("br_gr record before region record!");
 	      return;
 	    }
 	  set_imask (region, ptr->r.record.p.brmask, t, 3);
@@ -3061,6 +3062,43 @@ dot_special_section (which)
   set_section ((char *) special_section_name[which]);
 }
 
+static int
+in_procedure (const char *directive)
+{
+  if (unwind.proc_start
+      && (!unwind.saved_text_seg || strcmp (directive, "endp") == 0))
+    return 1;
+  as_bad (".%s outside of procedure", directive);
+  ignore_rest_of_line ();
+  return 0;
+}
+
+static int
+in_prologue (const char *directive)
+{
+  if (in_procedure (directive))
+    {
+      if (unwind.prologue)
+	return 1;
+      as_bad (".%s outside of prologue", directive);
+      ignore_rest_of_line ();
+    }
+  return 0;
+}
+
+static int
+in_body (const char *directive)
+{
+  if (in_procedure (directive))
+    {
+      if (unwind.body)
+	return 1;
+      as_bad (".%s outside of body region", directive);
+      ignore_rest_of_line ();
+    }
+  return 0;
+}
+
 static void
 add_unwind_entry (ptr)
      unw_rec_list *ptr;
@@ -3082,6 +3120,9 @@ dot_fframe (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("fframe"))
+    return;
+
   parse_operand (&e);
 
   if (e.X_op != O_constant)
@@ -3097,6 +3138,9 @@ dot_vframe (dummy)
   expressionS e;
   unsigned reg;
 
+  if (!in_prologue ("vframe"))
+    return;
+
   parse_operand (&e);
   reg = e.X_add_number - REG_GR;
   if (e.X_op == O_register && reg < 128)
@@ -3115,6 +3159,9 @@ dot_vframesp (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("vframesp"))
+    return;
+
   parse_operand (&e);
   if (e.X_op == O_constant)
     {
@@ -3131,6 +3178,9 @@ dot_vframepsp (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("vframepsp"))
+    return;
+
   parse_operand (&e);
   if (e.X_op == O_constant)
     {
@@ -3149,6 +3199,9 @@ dot_save (dummy)
   int sep;
   int reg1, reg2;
 
+  if (!in_prologue ("save"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     as_bad ("No second operand to .save");
@@ -3226,6 +3279,9 @@ dot_restore (dummy)
   unsigned long ecount;	/* # of _additional_ regions to pop */
   int sep;
 
+  if (!in_body ("restore"))
+    return;
+
   sep = parse_operand (&e1);
   if (e1.X_op != O_register || e1.X_add_number != REG_GR + 12)
     {
@@ -3268,6 +3324,9 @@ dot_restorereg (dummy)
   unsigned int ab, reg;
   expressionS e;
 
+  if (!in_procedure ("restorereg"))
+    return;
+
   parse_operand (&e);
 
   if (!convert_expr_to_ab_reg (&e, &ab, &reg))
@@ -3286,6 +3345,9 @@ dot_restorereg_p (dummy)
   expressionS e1, e2;
   int sep;
 
+  if (!in_procedure ("restorereg.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3517,6 +3579,8 @@ static void
 dot_handlerdata (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  if (!in_procedure ("handlerdata"))
+    return;
   unwind.force_unwind_entry = 1;
 
   /* Remember which segment we're in so we can switch back after .endp
*/
@@ -3534,6 +3598,8 @@ static void
 dot_unwentry (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  if (!in_procedure ("unwentry"))
+    return;
   unwind.force_unwind_entry = 1;
   demand_empty_rest_of_line ();
 }
@@ -3545,6 +3611,9 @@ dot_altrp (dummy)
   expressionS e;
   unsigned reg;
 
+  if (!in_prologue ("altrp"))
+    return;
+
   parse_operand (&e);
   reg = e.X_add_number - REG_BR;
   if (e.X_op == O_register && reg < 8)
@@ -3561,6 +3630,9 @@ dot_savemem (psprel)
   int sep;
   int reg1, val;
 
+  if (!in_prologue (psprel ? "savepsp" : "savesp"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     as_bad ("No second operand to .save%ssp", psprel ? "p" : "");
@@ -3653,6 +3725,10 @@ dot_saveg (dummy)
 {
   expressionS e1, e2;
   int sep;
+
+  if (!in_prologue ("save.g"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep == ',')
     parse_operand (&e2);
@@ -3681,6 +3757,10 @@ dot_savef (dummy)
 {
   expressionS e1;
   int sep;
+
+  if (!in_prologue ("save.f"))
+    return;
+
   sep = parse_operand (&e1);
 
   if (e1.X_op != O_constant)
@@ -3698,6 +3778,9 @@ dot_saveb (dummy)
   unsigned char sep;
   int brmask;
 
+  if (!in_prologue ("save.b"))
+    return;
+
   sep = parse_operand (&e1);
   if (e1.X_op != O_constant)
     {
@@ -3730,6 +3813,10 @@ dot_savegf (dummy)
 {
   expressionS e1, e2;
   int sep;
+
+  if (!in_prologue ("save.gf"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep == ',')
     parse_operand (&e2);
@@ -3751,6 +3838,9 @@ dot_spill (dummy)
   expressionS e;
   unsigned char sep;
 
+  if (!in_prologue ("spill"))
+    return;
+
   sep = parse_operand (&e);
   if (!is_end_of_line[sep] && !is_it_end_of_statement ())
     demand_empty_rest_of_line ();
@@ -3768,6 +3858,9 @@ dot_spillreg (dummy)
   int sep, ab, xy, reg, treg;
   expressionS e1, e2;
 
+  if (!in_procedure ("spillreg"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3799,6 +3892,9 @@ dot_spillmem (psprel)
   expressionS e1, e2;
   int sep, ab, reg;
 
+  if (!in_procedure ("spillmem"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3836,6 +3932,9 @@ dot_spillreg_p (dummy)
   expressionS e1, e2, e3;
   unsigned int qp;
 
+  if (!in_procedure ("spillreg.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3883,6 +3982,9 @@ dot_spillmem_p (psprel)
   int sep, ab, reg;
   unsigned int qp;
 
+  if (!in_procedure ("spillmem.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3988,6 +4090,9 @@ dot_label_state (dummy)
 {
   expressionS e;
 
+  if (!in_body ("label_state"))
+    return;
+
   parse_operand (&e);
   if (e.X_op != O_constant)
     {
@@ -4004,6 +4109,9 @@ dot_copy_state (dummy)
 {
   expressionS e;
 
+  if (!in_body ("copy_state"))
+    return;
+
   parse_operand (&e);
   if (e.X_op != O_constant)
     {
@@ -4021,6 +4129,9 @@ dot_unwabi (dummy)
   expressionS e1, e2;
   unsigned char sep;
 
+  if (!in_procedure ("unwabi"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -4051,6 +4162,8 @@ dot_personality (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
   char *name, *p, c;
+  if (!in_procedure ("personality"))
+    return;
   SKIP_WHITESPACE ();
   name = input_line_pointer;
   c = get_symbol_end ();
@@ -4069,7 +4182,7 @@ dot_proc (dummy)
   char *name, *p, c;
   symbolS *sym;
 
-  unwind.proc_start = expr_build_dot ();
+  unwind.proc_start = 0;
   /* Parse names of main and alternate entry points and mark them as
      function symbols:  */
   while (1)
@@ -4078,22 +4191,34 @@ dot_proc (dummy)
       name = input_line_pointer;
       c = get_symbol_end ();
       p = input_line_pointer;
-      sym = symbol_find_or_make (name);
-      if (unwind.proc_start == 0)
+      if (!*name)
+	as_bad ("Empty argument of .proc");
+      else
 	{
-	  unwind.proc_start = sym;
+	  sym = symbol_find_or_make (name);
+	  if (S_IS_DEFINED (sym))
+	    as_bad ("`%s' was already defined", name);
+	  else if (unwind.proc_start == 0)
+	    {
+	      unwind.proc_start = sym;
+	    }
+	  symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
 	}
-      symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
       *p = c;
       SKIP_WHITESPACE ();
       if (*input_line_pointer != ',')
 	break;
       ++input_line_pointer;
     }
+  if (unwind.proc_start == 0)
+    unwind.proc_start = expr_build_dot ();
   demand_empty_rest_of_line ();
   ia64_do_align (16);
 
+  unwind.prologue = 0;
   unwind.prologue_count = 0;
+  unwind.body = 0;
+  unwind.insn = 0;
   unwind.list = unwind.tail = unwind.current_entry = NULL;
   unwind.personality_routine = 0;
 }
@@ -4102,8 +4227,14 @@ static void
 dot_body (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  if (!in_procedure ("body"))
+    return;
+  if (!unwind.prologue && !unwind.body && unwind.insn)
+    as_warn ("Initial .body should precede any instructions");
+
   unwind.prologue = 0;
   unwind.prologue_mask = 0;
+  unwind.body = 1;
 
   add_unwind_entry (output_body ());
   demand_empty_rest_of_line ();
@@ -4116,6 +4247,17 @@ dot_prologue (dummy)
   unsigned char sep;
   int mask = 0, grsave = 0;
 
+  if (!in_procedure ("prologue"))
+    return;
+  if (unwind.prologue)
+    {
+      as_bad (".prologue within prologue");
+      ignore_rest_of_line ();
+      return;
+    }
+  if (!unwind.body && unwind.insn)
+    as_warn ("Initial .prologue should precede any instructions");
+
   if (!is_it_end_of_statement ())
     {
       expressionS e1, e2;
@@ -4148,6 +4290,7 @@ dot_prologue (dummy)
 
   unwind.prologue = 1;
   unwind.prologue_mask = mask;
+  unwind.body = 0;
   ++unwind.prologue_count;
 }
 
@@ -4164,6 +4307,9 @@ dot_endp (dummy)
   char *name, *p, c;
   symbolS *sym;
 
+  if (!in_procedure ("endp"))
+    return;
+
   if (unwind.saved_text_seg)
     {
       saved_seg = unwind.saved_text_seg;
@@ -4184,8 +4330,10 @@ dot_endp (dummy)
 
   if (unwind.info || unwind.force_unwind_entry)
     {
+      symbolS *proc_end;
+
       subseg_set (md.last_text_seg, 0);
-      unwind.proc_end = expr_build_dot ();
+      proc_end = expr_build_dot ();
 
       start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 0);
 
@@ -4209,7 +4357,7 @@ dot_endp (dummy)
       e.X_op = O_pseudo_fixup;
       e.X_op_symbol = pseudo_func[FUNC_SEG_RELATIVE].u.sym;
       e.X_add_number = 0;
-      e.X_add_symbol = unwind.proc_end;
+      e.X_add_symbol = proc_end;
       ia64_cons_fix_new (frag_now, where + bytes_per_address,
 			 bytes_per_address, &e);
 
@@ -4239,32 +4387,39 @@ dot_endp (dummy)
       name = input_line_pointer;
       c = get_symbol_end ();
       p = input_line_pointer;
-      sym = symbol_find (name);
-      if (sym && unwind.proc_start
-	  && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
-	  && S_GET_SIZE (sym) == 0 && symbol_get_obj (sym)->size ==
NULL)
-	{
-	  fragS *fr = symbol_get_frag (unwind.proc_start);
-	  fragS *frag = symbol_get_frag (sym);
-
-	  /* Check whether the function label is at or beyond last
-	     .proc directive.  */
-	  while (fr && fr != frag)
-	    fr = fr->fr_next;
-	  if (fr)
-	    {
-	      if (frag == frag_now && SEG_NORMAL (now_seg))
-		S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
-	      else
+      if (!*name)
+	as_bad ("Empty argument of .endp");
+      else
+	{
+	  sym = symbol_find (name);
+	  if (!sym || !S_IS_DEFINED (sym))
+	    as_bad ("`%s' was not defined within procedure", name);
+	  else if (unwind.proc_start
+	      && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
+	      && S_GET_SIZE (sym) == 0 && symbol_get_obj (sym)->size ==
NULL)
+	    {
+	      fragS *fr = symbol_get_frag (unwind.proc_start);
+	      fragS *frag = symbol_get_frag (sym);
+
+	      /* Check whether the function label is at or beyond last
+		 .proc directive.  */
+	      while (fr && fr != frag)
+		fr = fr->fr_next;
+	      if (fr)
 		{
-		  symbol_get_obj (sym)->size =
-		    (expressionS *) xmalloc (sizeof (expressionS));
-		  symbol_get_obj (sym)->size->X_op = O_subtract;
-		  symbol_get_obj (sym)->size->X_add_symbol
-		    = symbol_new (FAKE_LABEL_NAME, now_seg,
-				  frag_now_fix (), frag_now);
-		  symbol_get_obj (sym)->size->X_op_symbol = sym;
-		  symbol_get_obj (sym)->size->X_add_number = 0;
+		  if (frag == frag_now && SEG_NORMAL (now_seg))
+		    S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE
(sym));
+		  else
+		    {
+		      symbol_get_obj (sym)->size =
+			(expressionS *) xmalloc (sizeof (expressionS));
+		      symbol_get_obj (sym)->size->X_op = O_subtract;
+		      symbol_get_obj (sym)->size->X_add_symbol
+			= symbol_new (FAKE_LABEL_NAME, now_seg,
+				      frag_now_fix (), frag_now);
+		      symbol_get_obj (sym)->size->X_op_symbol = sym;
+		      symbol_get_obj (sym)->size->X_add_number = 0;
+		    }
 		}
 	    }
 	}
@@ -4275,7 +4430,7 @@ dot_endp (dummy)
       ++input_line_pointer;
     }
   demand_empty_rest_of_line ();
-  unwind.proc_start = unwind.proc_end = unwind.info = 0;
+  unwind.proc_start = unwind.info = 0;
 }
 
 static void
@@ -10162,6 +10317,8 @@ md_assemble (str)
       CURR_SLOT.unwind_record = unwind.current_entry;
       unwind.current_entry = NULL;
     }
+  if (unwind.proc_start && S_IS_DEFINED (unwind.proc_start))
+    unwind.insn = 1;
 
   /* Check for dependency violations.  */
   if (md.detect_dv)
---
/home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/ia64.exp	2004-07-02
08:26:34.000000000 +0200
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/ia64.exp	2005-01-24
12:01:13.000000000 +0100
@@ -58,4 +58,7 @@ if [istarget "ia64-*"] then {
 	run_dump_test "alias"
 	run_dump_test "group-1"
     }
+
+    run_list_test "proc" ""
+    run_list_test "unwind-err" ""
 }
---
/home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/proc.l	1970-01-01
01:00:00.000000000 +0100
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/proc.l	2005-01-28
10:23:04.404006069 +0100
@@ -0,0 +1,5 @@
+.*: Assembler messages:
+.*:4: Error: .* already defined.*
+.*:7: Error: .* not defined.*
+.*:12: Error: Empty argument of .proc
+.*:13: Error: Empty argument of .endp
---
/home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/proc.s	1970-01-01
01:00:00.000000000 +0100
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/proc.s	2005-01-28
10:22:31.626662721 +0100
@@ -0,0 +1,13 @@
+func1::
+	br.ret.sptk rp
+
+.proc	func, func1, func2
+func::
+	br.ret.sptk rp
+.endp	func, func1, func2
+
+func2::
+	br.ret.sptk rp
+
+.proc
+.endp
---
/home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.l	1970-01-01
01:00:00.000000000 +0100
+++
2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.l	2005-01-28
10:15:26.815144487 +0100
@@ -0,0 +1,34 @@
+.*: Assembler messages:
+.*:1: Error: .endp outside of procedure
+.*:2: Error: .personality outside of procedure
+.*:3: Error: .unwentry outside of procedure
+.*:4: Error: .unwabi outside of procedure
+.*:5: Error: .handlerdata outside of procedure
+.*:6: Error: .prologue outside of procedure
+.*:7: Error: .body outside of procedure
+.*:8: Error: .spillreg outside of procedure
+.*:9: Error: .spillreg.p outside of procedure
+.*:10: Error: .spillmem outside of procedure
+.*:11: Error: .spillmem.p outside of procedure
+.*:12: Error: .spillmem outside of procedure
+.*:13: Error: .spillmem.p outside of procedure
+.*:14: Error: .restorereg outside of procedure
+.*:15: Error: .restorereg.p outside of procedure
+.*:24: Error: .label_state outside of body region
+.*:25: Error: .copy_state outside of body region
+.*:26: Error: .fframe outside of prologue
+.*:27: Error: .vframe outside of prologue
+.*:28: Error: .spill outside of prologue
+.*:29: Error: .restore outside of body region
+.*:30: Error: .save outside of prologue
+.*:31: Error: .savesp outside of prologue
+.*:32: Error: .savepsp outside of prologue
+.*:33: Error: .save.g outside of prologue
+.*:34: Error: .save.gf outside of prologue
+.*:35: Error: .save.f outside of prologue
+.*:36: Error: .save.b outside of prologue
+.*:37: Error: .altrp outside of prologue
+.*:42: Error: .prologue within prologue
+.*:52: Error: .body outside of procedure
+.*:59: Warning: Initial .prologue.*
+.*:66: Warning: Initial .body.*
---
/home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.s	1970-01-01
01:00:00.000000000 +0100
+++
2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.s	2005-01-28
09:11:40.220464800 +0100
@@ -0,0 +1,68 @@
+.endp	xyz
+.personality personality
+.unwentry
+.unwabi @svr4, 0
+.handlerdata
+.prologue
+.body
+.spillreg r4, r8
+.spillreg.p p1, r4, r8
+.spillsp r5, 0
+.spillsp.p p2, r5, 0
+.spillpsp r6, 0
+.spillpsp.p p2, r6, 0
+.restorereg r4
+.restorereg.p p1, r4
+
+.proc	personality
+personality:
+.endp	personality
+
+.proc	start
+start:
+
+.label_state 1
+.copy_state 1
+.fframe 0
+.vframe r0
+.spill 0
+.restore sp
+.save rp, r0
+.savesp pr, 0
+.savepsp ar.fpsr, 0
+.save.g 2
+.save.gf 2,2
+.save.f 2
+.save.b 2
+.altrp b7
+.body
+
+
+	.prologue
+	.prologue
+	.save		ar.lc, r31
+	mov		r31 = ar.lc
+	;;
+	.body
+	.body
+	br.ret.sptk	rp
+	;;
+.personality personality
+.handlerdata
+.body
+
+.endp	start
+
+.proc	late_prologue
+late_prologue:
+	nop	0
+	.prologue
+	nop	0
+.endp	late_prologue
+
+.proc	late_body
+late_body:
+	nop	0
+	.body
+	nop	0
+.endp	late_body


[-- Attachment #2: binutils-mainline-ia64-unwind-directives.patch --]
[-- Type: text/plain, Size: 20666 bytes --]

Unwind directives were not checked for proper placement. Semantics of the
entry points specified by .proc and .endp were not enforced.

Built and tested on ia64-unknown-linux-gnu.

Jan

gas/
2005-01-28  Jan Beulich  <jbeulich@novell.com>

	* config/tc-ia64.c (unwind): Remove proc_end (now an automatic
	variable in dot_endp). Add body and insn. Make prologue,
	prologue_mask, body, and insn bitfields.
	(fixup_unw_records): Remove spurious new-lines from end of diagnostic
	messages.
	(in_procedure, in_prologue, in_body): New.
	(dot_fframe, dot_vframe, dot_vframesp, dot_vframepsp, dot_save,
	dot_restore, dot_restorereg, dot_restorereg_p, dot_handlerdata,
	dot_unwentry, dot_altrp, dot_savemem, dot_saveg, dot_savef, dot_saveb,
	dot_savegf, dot_spill, dot_spillreg, dot_spillmem, dot_spillreg_p,
	dot_spillmem_p, dot_label_state, dot_copy_state, dot_unwabi,
	dot_personality): Use the appropriate one of the above.
	(dot_proc): Clear unwind.proc_start; set to current location only if
	none of the entry points were valid. Check for non-zero-length entry
	point names. Check that entry points aren't defined, yet. Clear
	unwind.prologue, unwind.body, and unwind.insn.
	(dot_body): Call in_procedure. Check that first directive in procedure
	had no insns emitted before. Set unwind.body.
	(dot_prologue): Call in_procedure. Check that not already in prologue.
	Check that first directive in procedure had no insns emitted before.
	Clear unwind.body.
	(dot_endp): Call in_procedure. Declare proc_end. Check for non-zero-
	length entry point names. Check that entry points became defined.
	(md_assemble): Set unwind.insn once unwind.proc_start is defined.

gas/testsuite/
2005-01-28  Jan Beulich  <jbeulich@novell.com>

	* gas/ia64/proc.[ls]: New.
	* gas/ia64/unwind-err.[ls]: New.
	* gas/ia64/ia64.exp: Run new tests.

--- /home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/config/tc-ia64.c	2005-01-18 10:43:33.000000000 +0100
+++ 2005-01-24.08.40/gas/config/tc-ia64.c	2005-01-28 09:08:24.001717204 +0100
@@ -684,7 +684,6 @@ static struct
 
   /* These are used to create the unwind table entry for this function.  */
   symbolS *proc_start;
-  symbolS *proc_end;
   symbolS *info;		/* pointer to unwind info */
   symbolS *personality_routine;
   segT saved_text_seg;
@@ -692,8 +691,10 @@ static struct
   unsigned int force_unwind_entry : 1;	/* force generation of unwind entry? */
 
   /* TRUE if processing unwind directives in a prologue region.  */
-  int prologue;
-  int prologue_mask;
+  unsigned int prologue : 1;
+  unsigned int prologue_mask : 4;
+  unsigned int body : 1;
+  unsigned int insn : 1;
   unsigned int prologue_count;	/* number of .prologues seen so far */
   /* Prologue counts at previous .label_state directives.  */
   struct label_prologue_count * saved_prologue_counts;
@@ -2785,7 +2786,7 @@ fixup_unw_records (list, before_relax)
 	case frgr_mem:
 	  if (!region)
 	    {
-	      as_bad ("frgr_mem record before region record!\n");
+	      as_bad ("frgr_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.fr_mem |= ptr->r.record.p.frmask;
@@ -2796,7 +2797,7 @@ fixup_unw_records (list, before_relax)
 	case fr_mem:
 	  if (!region)
 	    {
-	      as_bad ("fr_mem record before region record!\n");
+	      as_bad ("fr_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.fr_mem |= ptr->r.record.p.rmask;
@@ -2805,7 +2806,7 @@ fixup_unw_records (list, before_relax)
 	case gr_mem:
 	  if (!region)
 	    {
-	      as_bad ("gr_mem record before region record!\n");
+	      as_bad ("gr_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.gr_mem |= ptr->r.record.p.rmask;
@@ -2814,7 +2815,7 @@ fixup_unw_records (list, before_relax)
 	case br_mem:
 	  if (!region)
 	    {
-	      as_bad ("br_mem record before region record!\n");
+	      as_bad ("br_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.br_mem |= ptr->r.record.p.brmask;
@@ -2824,7 +2825,7 @@ fixup_unw_records (list, before_relax)
 	case gr_gr:
 	  if (!region)
 	    {
-	      as_bad ("gr_gr record before region record!\n");
+	      as_bad ("gr_gr record before region record!");
 	      return;
 	    }
 	  set_imask (region, ptr->r.record.p.grmask, t, 2);
@@ -2832,7 +2833,7 @@ fixup_unw_records (list, before_relax)
 	case br_gr:
 	  if (!region)
 	    {
-	      as_bad ("br_gr record before region record!\n");
+	      as_bad ("br_gr record before region record!");
 	      return;
 	    }
 	  set_imask (region, ptr->r.record.p.brmask, t, 3);
@@ -3061,6 +3062,43 @@ dot_special_section (which)
   set_section ((char *) special_section_name[which]);
 }
 
+static int
+in_procedure (const char *directive)
+{
+  if (unwind.proc_start
+      && (!unwind.saved_text_seg || strcmp (directive, "endp") == 0))
+    return 1;
+  as_bad (".%s outside of procedure", directive);
+  ignore_rest_of_line ();
+  return 0;
+}
+
+static int
+in_prologue (const char *directive)
+{
+  if (in_procedure (directive))
+    {
+      if (unwind.prologue)
+	return 1;
+      as_bad (".%s outside of prologue", directive);
+      ignore_rest_of_line ();
+    }
+  return 0;
+}
+
+static int
+in_body (const char *directive)
+{
+  if (in_procedure (directive))
+    {
+      if (unwind.body)
+	return 1;
+      as_bad (".%s outside of body region", directive);
+      ignore_rest_of_line ();
+    }
+  return 0;
+}
+
 static void
 add_unwind_entry (ptr)
      unw_rec_list *ptr;
@@ -3082,6 +3120,9 @@ dot_fframe (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("fframe"))
+    return;
+
   parse_operand (&e);
 
   if (e.X_op != O_constant)
@@ -3097,6 +3138,9 @@ dot_vframe (dummy)
   expressionS e;
   unsigned reg;
 
+  if (!in_prologue ("vframe"))
+    return;
+
   parse_operand (&e);
   reg = e.X_add_number - REG_GR;
   if (e.X_op == O_register && reg < 128)
@@ -3115,6 +3159,9 @@ dot_vframesp (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("vframesp"))
+    return;
+
   parse_operand (&e);
   if (e.X_op == O_constant)
     {
@@ -3131,6 +3178,9 @@ dot_vframepsp (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("vframepsp"))
+    return;
+
   parse_operand (&e);
   if (e.X_op == O_constant)
     {
@@ -3149,6 +3199,9 @@ dot_save (dummy)
   int sep;
   int reg1, reg2;
 
+  if (!in_prologue ("save"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     as_bad ("No second operand to .save");
@@ -3226,6 +3279,9 @@ dot_restore (dummy)
   unsigned long ecount;	/* # of _additional_ regions to pop */
   int sep;
 
+  if (!in_body ("restore"))
+    return;
+
   sep = parse_operand (&e1);
   if (e1.X_op != O_register || e1.X_add_number != REG_GR + 12)
     {
@@ -3268,6 +3324,9 @@ dot_restorereg (dummy)
   unsigned int ab, reg;
   expressionS e;
 
+  if (!in_procedure ("restorereg"))
+    return;
+
   parse_operand (&e);
 
   if (!convert_expr_to_ab_reg (&e, &ab, &reg))
@@ -3286,6 +3345,9 @@ dot_restorereg_p (dummy)
   expressionS e1, e2;
   int sep;
 
+  if (!in_procedure ("restorereg.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3517,6 +3579,8 @@ static void
 dot_handlerdata (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  if (!in_procedure ("handlerdata"))
+    return;
   unwind.force_unwind_entry = 1;
 
   /* Remember which segment we're in so we can switch back after .endp */
@@ -3534,6 +3598,8 @@ static void
 dot_unwentry (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  if (!in_procedure ("unwentry"))
+    return;
   unwind.force_unwind_entry = 1;
   demand_empty_rest_of_line ();
 }
@@ -3545,6 +3611,9 @@ dot_altrp (dummy)
   expressionS e;
   unsigned reg;
 
+  if (!in_prologue ("altrp"))
+    return;
+
   parse_operand (&e);
   reg = e.X_add_number - REG_BR;
   if (e.X_op == O_register && reg < 8)
@@ -3561,6 +3630,9 @@ dot_savemem (psprel)
   int sep;
   int reg1, val;
 
+  if (!in_prologue (psprel ? "savepsp" : "savesp"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     as_bad ("No second operand to .save%ssp", psprel ? "p" : "");
@@ -3653,6 +3725,10 @@ dot_saveg (dummy)
 {
   expressionS e1, e2;
   int sep;
+
+  if (!in_prologue ("save.g"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep == ',')
     parse_operand (&e2);
@@ -3681,6 +3757,10 @@ dot_savef (dummy)
 {
   expressionS e1;
   int sep;
+
+  if (!in_prologue ("save.f"))
+    return;
+
   sep = parse_operand (&e1);
 
   if (e1.X_op != O_constant)
@@ -3698,6 +3778,9 @@ dot_saveb (dummy)
   unsigned char sep;
   int brmask;
 
+  if (!in_prologue ("save.b"))
+    return;
+
   sep = parse_operand (&e1);
   if (e1.X_op != O_constant)
     {
@@ -3730,6 +3813,10 @@ dot_savegf (dummy)
 {
   expressionS e1, e2;
   int sep;
+
+  if (!in_prologue ("save.gf"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep == ',')
     parse_operand (&e2);
@@ -3751,6 +3838,9 @@ dot_spill (dummy)
   expressionS e;
   unsigned char sep;
 
+  if (!in_prologue ("spill"))
+    return;
+
   sep = parse_operand (&e);
   if (!is_end_of_line[sep] && !is_it_end_of_statement ())
     demand_empty_rest_of_line ();
@@ -3768,6 +3858,9 @@ dot_spillreg (dummy)
   int sep, ab, xy, reg, treg;
   expressionS e1, e2;
 
+  if (!in_procedure ("spillreg"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3799,6 +3892,9 @@ dot_spillmem (psprel)
   expressionS e1, e2;
   int sep, ab, reg;
 
+  if (!in_procedure ("spillmem"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3836,6 +3932,9 @@ dot_spillreg_p (dummy)
   expressionS e1, e2, e3;
   unsigned int qp;
 
+  if (!in_procedure ("spillreg.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3883,6 +3982,9 @@ dot_spillmem_p (psprel)
   int sep, ab, reg;
   unsigned int qp;
 
+  if (!in_procedure ("spillmem.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3988,6 +4090,9 @@ dot_label_state (dummy)
 {
   expressionS e;
 
+  if (!in_body ("label_state"))
+    return;
+
   parse_operand (&e);
   if (e.X_op != O_constant)
     {
@@ -4004,6 +4109,9 @@ dot_copy_state (dummy)
 {
   expressionS e;
 
+  if (!in_body ("copy_state"))
+    return;
+
   parse_operand (&e);
   if (e.X_op != O_constant)
     {
@@ -4021,6 +4129,9 @@ dot_unwabi (dummy)
   expressionS e1, e2;
   unsigned char sep;
 
+  if (!in_procedure ("unwabi"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -4051,6 +4162,8 @@ dot_personality (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
   char *name, *p, c;
+  if (!in_procedure ("personality"))
+    return;
   SKIP_WHITESPACE ();
   name = input_line_pointer;
   c = get_symbol_end ();
@@ -4069,7 +4182,7 @@ dot_proc (dummy)
   char *name, *p, c;
   symbolS *sym;
 
-  unwind.proc_start = expr_build_dot ();
+  unwind.proc_start = 0;
   /* Parse names of main and alternate entry points and mark them as
      function symbols:  */
   while (1)
@@ -4078,22 +4191,34 @@ dot_proc (dummy)
       name = input_line_pointer;
       c = get_symbol_end ();
       p = input_line_pointer;
-      sym = symbol_find_or_make (name);
-      if (unwind.proc_start == 0)
+      if (!*name)
+	as_bad ("Empty argument of .proc");
+      else
 	{
-	  unwind.proc_start = sym;
+	  sym = symbol_find_or_make (name);
+	  if (S_IS_DEFINED (sym))
+	    as_bad ("`%s' was already defined", name);
+	  else if (unwind.proc_start == 0)
+	    {
+	      unwind.proc_start = sym;
+	    }
+	  symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
 	}
-      symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
       *p = c;
       SKIP_WHITESPACE ();
       if (*input_line_pointer != ',')
 	break;
       ++input_line_pointer;
     }
+  if (unwind.proc_start == 0)
+    unwind.proc_start = expr_build_dot ();
   demand_empty_rest_of_line ();
   ia64_do_align (16);
 
+  unwind.prologue = 0;
   unwind.prologue_count = 0;
+  unwind.body = 0;
+  unwind.insn = 0;
   unwind.list = unwind.tail = unwind.current_entry = NULL;
   unwind.personality_routine = 0;
 }
@@ -4102,8 +4227,14 @@ static void
 dot_body (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  if (!in_procedure ("body"))
+    return;
+  if (!unwind.prologue && !unwind.body && unwind.insn)
+    as_warn ("Initial .body should precede any instructions");
+
   unwind.prologue = 0;
   unwind.prologue_mask = 0;
+  unwind.body = 1;
 
   add_unwind_entry (output_body ());
   demand_empty_rest_of_line ();
@@ -4116,6 +4247,17 @@ dot_prologue (dummy)
   unsigned char sep;
   int mask = 0, grsave = 0;
 
+  if (!in_procedure ("prologue"))
+    return;
+  if (unwind.prologue)
+    {
+      as_bad (".prologue within prologue");
+      ignore_rest_of_line ();
+      return;
+    }
+  if (!unwind.body && unwind.insn)
+    as_warn ("Initial .prologue should precede any instructions");
+
   if (!is_it_end_of_statement ())
     {
       expressionS e1, e2;
@@ -4148,6 +4290,7 @@ dot_prologue (dummy)
 
   unwind.prologue = 1;
   unwind.prologue_mask = mask;
+  unwind.body = 0;
   ++unwind.prologue_count;
 }
 
@@ -4164,6 +4307,9 @@ dot_endp (dummy)
   char *name, *p, c;
   symbolS *sym;
 
+  if (!in_procedure ("endp"))
+    return;
+
   if (unwind.saved_text_seg)
     {
       saved_seg = unwind.saved_text_seg;
@@ -4184,8 +4330,10 @@ dot_endp (dummy)
 
   if (unwind.info || unwind.force_unwind_entry)
     {
+      symbolS *proc_end;
+
       subseg_set (md.last_text_seg, 0);
-      unwind.proc_end = expr_build_dot ();
+      proc_end = expr_build_dot ();
 
       start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 0);
 
@@ -4209,7 +4357,7 @@ dot_endp (dummy)
       e.X_op = O_pseudo_fixup;
       e.X_op_symbol = pseudo_func[FUNC_SEG_RELATIVE].u.sym;
       e.X_add_number = 0;
-      e.X_add_symbol = unwind.proc_end;
+      e.X_add_symbol = proc_end;
       ia64_cons_fix_new (frag_now, where + bytes_per_address,
 			 bytes_per_address, &e);
 
@@ -4239,32 +4387,39 @@ dot_endp (dummy)
       name = input_line_pointer;
       c = get_symbol_end ();
       p = input_line_pointer;
-      sym = symbol_find (name);
-      if (sym && unwind.proc_start
-	  && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
-	  && S_GET_SIZE (sym) == 0 && symbol_get_obj (sym)->size == NULL)
-	{
-	  fragS *fr = symbol_get_frag (unwind.proc_start);
-	  fragS *frag = symbol_get_frag (sym);
-
-	  /* Check whether the function label is at or beyond last
-	     .proc directive.  */
-	  while (fr && fr != frag)
-	    fr = fr->fr_next;
-	  if (fr)
-	    {
-	      if (frag == frag_now && SEG_NORMAL (now_seg))
-		S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
-	      else
+      if (!*name)
+	as_bad ("Empty argument of .endp");
+      else
+	{
+	  sym = symbol_find (name);
+	  if (!sym || !S_IS_DEFINED (sym))
+	    as_bad ("`%s' was not defined within procedure", name);
+	  else if (unwind.proc_start
+	      && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
+	      && S_GET_SIZE (sym) == 0 && symbol_get_obj (sym)->size == NULL)
+	    {
+	      fragS *fr = symbol_get_frag (unwind.proc_start);
+	      fragS *frag = symbol_get_frag (sym);
+
+	      /* Check whether the function label is at or beyond last
+		 .proc directive.  */
+	      while (fr && fr != frag)
+		fr = fr->fr_next;
+	      if (fr)
 		{
-		  symbol_get_obj (sym)->size =
-		    (expressionS *) xmalloc (sizeof (expressionS));
-		  symbol_get_obj (sym)->size->X_op = O_subtract;
-		  symbol_get_obj (sym)->size->X_add_symbol
-		    = symbol_new (FAKE_LABEL_NAME, now_seg,
-				  frag_now_fix (), frag_now);
-		  symbol_get_obj (sym)->size->X_op_symbol = sym;
-		  symbol_get_obj (sym)->size->X_add_number = 0;
+		  if (frag == frag_now && SEG_NORMAL (now_seg))
+		    S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
+		  else
+		    {
+		      symbol_get_obj (sym)->size =
+			(expressionS *) xmalloc (sizeof (expressionS));
+		      symbol_get_obj (sym)->size->X_op = O_subtract;
+		      symbol_get_obj (sym)->size->X_add_symbol
+			= symbol_new (FAKE_LABEL_NAME, now_seg,
+				      frag_now_fix (), frag_now);
+		      symbol_get_obj (sym)->size->X_op_symbol = sym;
+		      symbol_get_obj (sym)->size->X_add_number = 0;
+		    }
 		}
 	    }
 	}
@@ -4275,7 +4430,7 @@ dot_endp (dummy)
       ++input_line_pointer;
     }
   demand_empty_rest_of_line ();
-  unwind.proc_start = unwind.proc_end = unwind.info = 0;
+  unwind.proc_start = unwind.info = 0;
 }
 
 static void
@@ -10162,6 +10317,8 @@ md_assemble (str)
       CURR_SLOT.unwind_record = unwind.current_entry;
       unwind.current_entry = NULL;
     }
+  if (unwind.proc_start && S_IS_DEFINED (unwind.proc_start))
+    unwind.insn = 1;
 
   /* Check for dependency violations.  */
   if (md.detect_dv)
--- /home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/ia64.exp	2004-07-02 08:26:34.000000000 +0200
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/ia64.exp	2005-01-24 12:01:13.000000000 +0100
@@ -58,4 +58,7 @@ if [istarget "ia64-*"] then {
 	run_dump_test "alias"
 	run_dump_test "group-1"
     }
+
+    run_list_test "proc" ""
+    run_list_test "unwind-err" ""
 }
--- /home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/proc.l	1970-01-01 01:00:00.000000000 +0100
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/proc.l	2005-01-28 10:23:04.404006069 +0100
@@ -0,0 +1,5 @@
+.*: Assembler messages:
+.*:4: Error: .* already defined.*
+.*:7: Error: .* not defined.*
+.*:12: Error: Empty argument of .proc
+.*:13: Error: Empty argument of .endp
--- /home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/proc.s	1970-01-01 01:00:00.000000000 +0100
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/proc.s	2005-01-28 10:22:31.626662721 +0100
@@ -0,0 +1,13 @@
+func1::
+	br.ret.sptk rp
+
+.proc	func, func1, func2
+func::
+	br.ret.sptk rp
+.endp	func, func1, func2
+
+func2::
+	br.ret.sptk rp
+
+.proc
+.endp
--- /home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.l	1970-01-01 01:00:00.000000000 +0100
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.l	2005-01-28 10:15:26.815144487 +0100
@@ -0,0 +1,34 @@
+.*: Assembler messages:
+.*:1: Error: .endp outside of procedure
+.*:2: Error: .personality outside of procedure
+.*:3: Error: .unwentry outside of procedure
+.*:4: Error: .unwabi outside of procedure
+.*:5: Error: .handlerdata outside of procedure
+.*:6: Error: .prologue outside of procedure
+.*:7: Error: .body outside of procedure
+.*:8: Error: .spillreg outside of procedure
+.*:9: Error: .spillreg.p outside of procedure
+.*:10: Error: .spillmem outside of procedure
+.*:11: Error: .spillmem.p outside of procedure
+.*:12: Error: .spillmem outside of procedure
+.*:13: Error: .spillmem.p outside of procedure
+.*:14: Error: .restorereg outside of procedure
+.*:15: Error: .restorereg.p outside of procedure
+.*:24: Error: .label_state outside of body region
+.*:25: Error: .copy_state outside of body region
+.*:26: Error: .fframe outside of prologue
+.*:27: Error: .vframe outside of prologue
+.*:28: Error: .spill outside of prologue
+.*:29: Error: .restore outside of body region
+.*:30: Error: .save outside of prologue
+.*:31: Error: .savesp outside of prologue
+.*:32: Error: .savepsp outside of prologue
+.*:33: Error: .save.g outside of prologue
+.*:34: Error: .save.gf outside of prologue
+.*:35: Error: .save.f outside of prologue
+.*:36: Error: .save.b outside of prologue
+.*:37: Error: .altrp outside of prologue
+.*:42: Error: .prologue within prologue
+.*:52: Error: .body outside of procedure
+.*:59: Warning: Initial .prologue.*
+.*:66: Warning: Initial .body.*
--- /home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.s	1970-01-01 01:00:00.000000000 +0100
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.s	2005-01-28 09:11:40.220464800 +0100
@@ -0,0 +1,68 @@
+.endp	xyz
+.personality personality
+.unwentry
+.unwabi @svr4, 0
+.handlerdata
+.prologue
+.body
+.spillreg r4, r8
+.spillreg.p p1, r4, r8
+.spillsp r5, 0
+.spillsp.p p2, r5, 0
+.spillpsp r6, 0
+.spillpsp.p p2, r6, 0
+.restorereg r4
+.restorereg.p p1, r4
+
+.proc	personality
+personality:
+.endp	personality
+
+.proc	start
+start:
+
+.label_state 1
+.copy_state 1
+.fframe 0
+.vframe r0
+.spill 0
+.restore sp
+.save rp, r0
+.savesp pr, 0
+.savepsp ar.fpsr, 0
+.save.g 2
+.save.gf 2,2
+.save.f 2
+.save.b 2
+.altrp b7
+.body
+
+
+	.prologue
+	.prologue
+	.save		ar.lc, r31
+	mov		r31 = ar.lc
+	;;
+	.body
+	.body
+	br.ret.sptk	rp
+	;;
+.personality personality
+.handlerdata
+.body
+
+.endp	start
+
+.proc	late_prologue
+late_prologue:
+	nop	0
+	.prologue
+	nop	0
+.endp	late_prologue
+
+.proc	late_body
+late_body:
+	nop	0
+	.body
+	nop	0
+.endp	late_body

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ia64 unwind directive semantics
  2005-01-24 11:29 Jan Beulich
@ 2005-01-28  3:52 ` James E Wilson
  2005-02-02  8:16 ` Alan Modra
  1 sibling, 0 replies; 10+ messages in thread
From: James E Wilson @ 2005-01-28  3:52 UTC (permalink / raw)
  To: Jan Beulich; +Cc: binutils

On Mon, 2005-01-24 at 03:29, Jan Beulich wrote:
> 	* config/tc-ia64.c (unwind): Remove proc_end (now an automatic
> 	variable in dot_endp). Add body and insn. Make prologue,
> 	...

GNU coding conventions require explanatory comments before every
function, though I realize most all of the unwind functions are already
missing comments.  I should really fix this before complaining about it
to others.

The testcases don't test all of the errors you added.  In particular,
the prologue/body before first insn messages.  Also the proc/endp errors
for a missing name, but those ones are obvious enough that I don't see
the need for tests for them.

Hopefully gcc emits unwind info that passes all of these tests. 
Likewise, for assembly code in glibc and the linux kernel.  I will have
to check all of this after all of these patches go in.

I am not sure about one of the proc/endp changes you added.  For proc,
you replaced unwind.proc_start with sym.  But that works only if sym is
defined immediately after the proc.  I would expect that to be true, but
don't think it is safe to assume it.  Also, if a procedure has multiple
entry points, can we really be sure that the first name listed is the
entry point with the lowest address?  Using expr_build_dot here avoids
these problems, and should be perfectly safe.  I am not sure why the
existing code sets proc_start to sym if it is zero.  I think that is a
bug, as it should never be zero here, as expr_build_dot should never
return zero.  I suspect the code originally worked as you wrote it, and
then later got fixed to use expr_build_dot instead of sym because that
didn't work, but we forgot to remove part of the old code.

> +	  if (!sym || !S_IS_DEFINED (sym))
> +	    as_bad ("`%s' was not defined within procedure", name);
> +	  else if (sym && unwind.proc_start

You have a redundant check for sym here.  It is guaranteed to be
non-zero in the second if, so we don't need to check it again.

Otherwise, this looks OK.
-- 
Jim Wilson, GNU Tools Support, http://www.SpecifixInc.com


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] ia64 unwind directive semantics
@ 2005-01-24 11:29 Jan Beulich
  2005-01-28  3:52 ` James E Wilson
  2005-02-02  8:16 ` Alan Modra
  0 siblings, 2 replies; 10+ messages in thread
From: Jan Beulich @ 2005-01-24 11:29 UTC (permalink / raw)
  To: binutils

[-- Attachment #1: Type: text/plain, Size: 20361 bytes --]

Unwind directives were not checked for proper placement. Semantics of
the
entry points specified by .proc and .endp were not enforced.

Built and tested on ia64-unknown-linux-gnu.

Jan

gas/
2005-01-24  Jan Beulich  <jbeulich@novell.com>

	* config/tc-ia64.c (unwind): Remove proc_end (now an automatic
	variable in dot_endp). Add body and insn. Make prologue,
	prologue_mask, body, and insn bitfields.
	(fixup_unw_records): Remove spurious new-lines from end of
diagnostic
	messages.
	(in_procedure, in_prologue, in_body): New.
	(dot_fframe, dot_vframe, dot_vframesp, dot_vframepsp, dot_save,
	dot_restore, dot_restorereg, dot_restorereg_p, dot_handlerdata,
	dot_unwentry, dot_altrp, dot_savemem, dot_saveg, dot_savef,
dot_saveb,
	dot_savegf, dot_spill, dot_spillreg, dot_spillmem,
dot_spillreg_p,
	dot_spillmem_p, dot_label_state, dot_copy_state, dot_unwabi,
	dot_personality): Use the appropriate one of the above.
	(dot_proc): Clear unwind.proc_start; set to current location
only if
	none of the entry points were valid. Check for non-zero-length
entry
	point names. Check that entry points aren't defined, yet. Clear
	unwind.prologue, unwind.body, and unwind.insn.
	(dot_body): Call in_procedure. Check that first directive in
procedure
	had no insns emitted before. Set unwind.body.
	(dot_prologue): Call in_procedure. Check that not already in
prologue.
	Check that first directive in procedure had no insns emitted
before.
	Clear unwind.body.
	(dot_endp): Call in_procedure. Declare proc_end. Check for
non-zero-
	length entry point names. Check that entry points became
defined.
	(md_assemble): Set unwind.insn once unwind.proc_start is
defined.

gas/testsuite/
2005-01-24  Jan Beulich  <jbeulich@novell.com>

	* gas/ia64/proc.[ls]: New.
	* gas/ia64/unwind-err.[ls]: New.
	* gas/ia64/ia64.exp: Run new tests.

---
/home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/config/tc-ia64.c	2005-01-18
10:43:33.000000000 +0100
+++ 2005-01-24.08.40/gas/config/tc-ia64.c	2005-01-24
12:03:38.038747462 +0100
@@ -684,7 +684,6 @@ static struct
 
   /* These are used to create the unwind table entry for this
function.  */
   symbolS *proc_start;
-  symbolS *proc_end;
   symbolS *info;		/* pointer to unwind info */
   symbolS *personality_routine;
   segT saved_text_seg;
@@ -692,8 +691,10 @@ static struct
   unsigned int force_unwind_entry : 1;	/* force generation of
unwind entry? */
 
   /* TRUE if processing unwind directives in a prologue region.  */
-  int prologue;
-  int prologue_mask;
+  unsigned int prologue : 1;
+  unsigned int prologue_mask : 4;
+  unsigned int body : 1;
+  unsigned int insn : 1;
   unsigned int prologue_count;	/* number of .prologues seen so
far */
   /* Prologue counts at previous .label_state directives.  */
   struct label_prologue_count * saved_prologue_counts;
@@ -2785,7 +2786,7 @@ fixup_unw_records (list, before_relax)
 	case frgr_mem:
 	  if (!region)
 	    {
-	      as_bad ("frgr_mem record before region record!\n");
+	      as_bad ("frgr_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.fr_mem |= ptr->r.record.p.frmask;
@@ -2796,7 +2797,7 @@ fixup_unw_records (list, before_relax)
 	case fr_mem:
 	  if (!region)
 	    {
-	      as_bad ("fr_mem record before region record!\n");
+	      as_bad ("fr_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.fr_mem |= ptr->r.record.p.rmask;
@@ -2805,7 +2806,7 @@ fixup_unw_records (list, before_relax)
 	case gr_mem:
 	  if (!region)
 	    {
-	      as_bad ("gr_mem record before region record!\n");
+	      as_bad ("gr_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.gr_mem |= ptr->r.record.p.rmask;
@@ -2814,7 +2815,7 @@ fixup_unw_records (list, before_relax)
 	case br_mem:
 	  if (!region)
 	    {
-	      as_bad ("br_mem record before region record!\n");
+	      as_bad ("br_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.br_mem |= ptr->r.record.p.brmask;
@@ -2824,7 +2825,7 @@ fixup_unw_records (list, before_relax)
 	case gr_gr:
 	  if (!region)
 	    {
-	      as_bad ("gr_gr record before region record!\n");
+	      as_bad ("gr_gr record before region record!");
 	      return;
 	    }
 	  set_imask (region, ptr->r.record.p.grmask, t, 2);
@@ -2832,7 +2833,7 @@ fixup_unw_records (list, before_relax)
 	case br_gr:
 	  if (!region)
 	    {
-	      as_bad ("br_gr record before region record!\n");
+	      as_bad ("br_gr record before region record!");
 	      return;
 	    }
 	  set_imask (region, ptr->r.record.p.brmask, t, 3);
@@ -3061,6 +3062,43 @@ dot_special_section (which)
   set_section ((char *) special_section_name[which]);
 }
 
+static int
+in_procedure (const char *directive)
+{
+  if (unwind.proc_start
+      && (!unwind.saved_text_seg || strcmp (directive, "endp") == 0))
+    return 1;
+  as_bad (".%s outside of procedure", directive);
+  ignore_rest_of_line ();
+  return 0;
+}
+
+static int
+in_prologue (const char *directive)
+{
+  if (in_procedure (directive))
+    {
+      if (unwind.prologue)
+	return 1;
+      as_bad (".%s outside of prologue", directive);
+      ignore_rest_of_line ();
+    }
+  return 0;
+}
+
+static int
+in_body (const char *directive)
+{
+  if (in_procedure (directive))
+    {
+      if (unwind.body)
+	return 1;
+      as_bad (".%s outside of body region", directive);
+      ignore_rest_of_line ();
+    }
+  return 0;
+}
+
 static void
 add_unwind_entry (ptr)
      unw_rec_list *ptr;
@@ -3082,6 +3120,9 @@ dot_fframe (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("fframe"))
+    return;
+
   parse_operand (&e);
 
   if (e.X_op != O_constant)
@@ -3097,6 +3138,9 @@ dot_vframe (dummy)
   expressionS e;
   unsigned reg;
 
+  if (!in_prologue ("vframe"))
+    return;
+
   parse_operand (&e);
   reg = e.X_add_number - REG_GR;
   if (e.X_op == O_register && reg < 128)
@@ -3115,6 +3159,9 @@ dot_vframesp (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("vframesp"))
+    return;
+
   parse_operand (&e);
   if (e.X_op == O_constant)
     {
@@ -3131,6 +3178,9 @@ dot_vframepsp (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("vframepsp"))
+    return;
+
   parse_operand (&e);
   if (e.X_op == O_constant)
     {
@@ -3149,6 +3199,9 @@ dot_save (dummy)
   int sep;
   int reg1, reg2;
 
+  if (!in_prologue ("save"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     as_bad ("No second operand to .save");
@@ -3226,6 +3279,9 @@ dot_restore (dummy)
   unsigned long ecount;	/* # of _additional_ regions to pop */
   int sep;
 
+  if (!in_body ("restore"))
+    return;
+
   sep = parse_operand (&e1);
   if (e1.X_op != O_register || e1.X_add_number != REG_GR + 12)
     {
@@ -3268,6 +3324,9 @@ dot_restorereg (dummy)
   unsigned int ab, reg;
   expressionS e;
 
+  if (!in_procedure ("restorereg"))
+    return;
+
   parse_operand (&e);
 
   if (!convert_expr_to_ab_reg (&e, &ab, &reg))
@@ -3286,6 +3345,9 @@ dot_restorereg_p (dummy)
   expressionS e1, e2;
   int sep;
 
+  if (!in_procedure ("restorereg.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3517,6 +3579,8 @@ static void
 dot_handlerdata (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  if (!in_procedure ("handlerdata"))
+    return;
   unwind.force_unwind_entry = 1;
 
   /* Remember which segment we're in so we can switch back after .endp
*/
@@ -3534,6 +3598,8 @@ static void
 dot_unwentry (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  if (!in_procedure ("unwentry"))
+    return;
   unwind.force_unwind_entry = 1;
   demand_empty_rest_of_line ();
 }
@@ -3545,6 +3611,9 @@ dot_altrp (dummy)
   expressionS e;
   unsigned reg;
 
+  if (!in_prologue ("altrp"))
+    return;
+
   parse_operand (&e);
   reg = e.X_add_number - REG_BR;
   if (e.X_op == O_register && reg < 8)
@@ -3561,6 +3630,9 @@ dot_savemem (psprel)
   int sep;
   int reg1, val;
 
+  if (!in_prologue (psprel ? "savepsp" : "savesp"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     as_bad ("No second operand to .save%ssp", psprel ? "p" : "");
@@ -3653,6 +3725,10 @@ dot_saveg (dummy)
 {
   expressionS e1, e2;
   int sep;
+
+  if (!in_prologue ("save.g"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep == ',')
     parse_operand (&e2);
@@ -3681,6 +3757,10 @@ dot_savef (dummy)
 {
   expressionS e1;
   int sep;
+
+  if (!in_prologue ("save.f"))
+    return;
+
   sep = parse_operand (&e1);
 
   if (e1.X_op != O_constant)
@@ -3698,6 +3778,9 @@ dot_saveb (dummy)
   unsigned char sep;
   int brmask;
 
+  if (!in_prologue ("save.b"))
+    return;
+
   sep = parse_operand (&e1);
   if (e1.X_op != O_constant)
     {
@@ -3730,6 +3813,10 @@ dot_savegf (dummy)
 {
   expressionS e1, e2;
   int sep;
+
+  if (!in_prologue ("save.gf"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep == ',')
     parse_operand (&e2);
@@ -3751,6 +3838,9 @@ dot_spill (dummy)
   expressionS e;
   unsigned char sep;
 
+  if (!in_prologue ("spill"))
+    return;
+
   sep = parse_operand (&e);
   if (!is_end_of_line[sep] && !is_it_end_of_statement ())
     demand_empty_rest_of_line ();
@@ -3768,6 +3858,9 @@ dot_spillreg (dummy)
   int sep, ab, xy, reg, treg;
   expressionS e1, e2;
 
+  if (!in_procedure ("spillreg"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3799,6 +3892,9 @@ dot_spillmem (psprel)
   expressionS e1, e2;
   int sep, ab, reg;
 
+  if (!in_procedure ("spillmem"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3836,6 +3932,9 @@ dot_spillreg_p (dummy)
   expressionS e1, e2, e3;
   unsigned int qp;
 
+  if (!in_procedure ("spillreg.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3883,6 +3982,9 @@ dot_spillmem_p (psprel)
   int sep, ab, reg;
   unsigned int qp;
 
+  if (!in_procedure ("spillmem.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3988,6 +4090,9 @@ dot_label_state (dummy)
 {
   expressionS e;
 
+  if (!in_body ("label_state"))
+    return;
+
   parse_operand (&e);
   if (e.X_op != O_constant)
     {
@@ -4004,6 +4109,9 @@ dot_copy_state (dummy)
 {
   expressionS e;
 
+  if (!in_body ("copy_state"))
+    return;
+
   parse_operand (&e);
   if (e.X_op != O_constant)
     {
@@ -4021,6 +4129,9 @@ dot_unwabi (dummy)
   expressionS e1, e2;
   unsigned char sep;
 
+  if (!in_procedure ("unwabi"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -4051,6 +4162,8 @@ dot_personality (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
   char *name, *p, c;
+  if (!in_procedure ("personality"))
+    return;
   SKIP_WHITESPACE ();
   name = input_line_pointer;
   c = get_symbol_end ();
@@ -4069,7 +4182,7 @@ dot_proc (dummy)
   char *name, *p, c;
   symbolS *sym;
 
-  unwind.proc_start = expr_build_dot ();
+  unwind.proc_start = 0;
   /* Parse names of main and alternate entry points and mark them as
      function symbols:  */
   while (1)
@@ -4078,22 +4191,34 @@ dot_proc (dummy)
       name = input_line_pointer;
       c = get_symbol_end ();
       p = input_line_pointer;
-      sym = symbol_find_or_make (name);
-      if (unwind.proc_start == 0)
+      if (!*name)
+	as_bad ("Empty argument of .proc");
+      else
 	{
-	  unwind.proc_start = sym;
+	  sym = symbol_find_or_make (name);
+	  if (S_IS_DEFINED (sym))
+	    as_bad ("`%s' was already defined", name);
+	  else if (unwind.proc_start == 0)
+	    {
+	      unwind.proc_start = sym;
+	    }
+	  symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
 	}
-      symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
       *p = c;
       SKIP_WHITESPACE ();
       if (*input_line_pointer != ',')
 	break;
       ++input_line_pointer;
     }
+  if (unwind.proc_start == 0)
+    unwind.proc_start = expr_build_dot ();
   demand_empty_rest_of_line ();
   ia64_do_align (16);
 
+  unwind.prologue = 0;
   unwind.prologue_count = 0;
+  unwind.body = 0;
+  unwind.insn = 0;
   unwind.list = unwind.tail = unwind.current_entry = NULL;
   unwind.personality_routine = 0;
 }
@@ -4102,8 +4227,14 @@ static void
 dot_body (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  if (!in_procedure ("body"))
+    return;
+  if (!unwind.prologue && !unwind.body && unwind.insn)
+    as_warn ("Initial .body should precede any instructions");
+
   unwind.prologue = 0;
   unwind.prologue_mask = 0;
+  unwind.body = 1;
 
   add_unwind_entry (output_body ());
   demand_empty_rest_of_line ();
@@ -4116,6 +4247,17 @@ dot_prologue (dummy)
   unsigned char sep;
   int mask = 0, grsave = 0;
 
+  if (!in_procedure ("prologue"))
+    return;
+  if (unwind.prologue)
+    {
+      as_bad (".prologue within prologue");
+      ignore_rest_of_line ();
+      return;
+    }
+  if (!unwind.body && unwind.insn)
+    as_warn ("Initial .prologue should precede any instructions");
+
   if (!is_it_end_of_statement ())
     {
       expressionS e1, e2;
@@ -4148,6 +4290,7 @@ dot_prologue (dummy)
 
   unwind.prologue = 1;
   unwind.prologue_mask = mask;
+  unwind.body = 0;
   ++unwind.prologue_count;
 }
 
@@ -4164,6 +4307,9 @@ dot_endp (dummy)
   char *name, *p, c;
   symbolS *sym;
 
+  if (!in_procedure ("endp"))
+    return;
+
   if (unwind.saved_text_seg)
     {
       saved_seg = unwind.saved_text_seg;
@@ -4184,8 +4330,10 @@ dot_endp (dummy)
 
   if (unwind.info || unwind.force_unwind_entry)
     {
+      symbolS *proc_end;
+
       subseg_set (md.last_text_seg, 0);
-      unwind.proc_end = expr_build_dot ();
+      proc_end = expr_build_dot ();
 
       start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 0);
 
@@ -4209,7 +4357,7 @@ dot_endp (dummy)
       e.X_op = O_pseudo_fixup;
       e.X_op_symbol = pseudo_func[FUNC_SEG_RELATIVE].u.sym;
       e.X_add_number = 0;
-      e.X_add_symbol = unwind.proc_end;
+      e.X_add_symbol = proc_end;
       ia64_cons_fix_new (frag_now, where + bytes_per_address,
 			 bytes_per_address, &e);
 
@@ -4239,32 +4387,39 @@ dot_endp (dummy)
       name = input_line_pointer;
       c = get_symbol_end ();
       p = input_line_pointer;
-      sym = symbol_find (name);
-      if (sym && unwind.proc_start
-	  && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
-	  && S_GET_SIZE (sym) == 0 && symbol_get_obj (sym)->size ==
NULL)
-	{
-	  fragS *fr = symbol_get_frag (unwind.proc_start);
-	  fragS *frag = symbol_get_frag (sym);
-
-	  /* Check whether the function label is at or beyond last
-	     .proc directive.  */
-	  while (fr && fr != frag)
-	    fr = fr->fr_next;
-	  if (fr)
-	    {
-	      if (frag == frag_now && SEG_NORMAL (now_seg))
-		S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
-	      else
+      if (!*name)
+	as_bad ("Empty argument of .endp");
+      else
+	{
+	  sym = symbol_find (name);
+	  if (!sym || !S_IS_DEFINED (sym))
+	    as_bad ("`%s' was not defined within procedure", name);
+	  else if (sym && unwind.proc_start
+	      && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
+	      && S_GET_SIZE (sym) == 0 && symbol_get_obj (sym)->size ==
NULL)
+	    {
+	      fragS *fr = symbol_get_frag (unwind.proc_start);
+	      fragS *frag = symbol_get_frag (sym);
+
+	      /* Check whether the function label is at or beyond last
+		 .proc directive.  */
+	      while (fr && fr != frag)
+		fr = fr->fr_next;
+	      if (fr)
 		{
-		  symbol_get_obj (sym)->size =
-		    (expressionS *) xmalloc (sizeof (expressionS));
-		  symbol_get_obj (sym)->size->X_op = O_subtract;
-		  symbol_get_obj (sym)->size->X_add_symbol
-		    = symbol_new (FAKE_LABEL_NAME, now_seg,
-				  frag_now_fix (), frag_now);
-		  symbol_get_obj (sym)->size->X_op_symbol = sym;
-		  symbol_get_obj (sym)->size->X_add_number = 0;
+		  if (frag == frag_now && SEG_NORMAL (now_seg))
+		    S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE
(sym));
+		  else
+		    {
+		      symbol_get_obj (sym)->size =
+			(expressionS *) xmalloc (sizeof (expressionS));
+		      symbol_get_obj (sym)->size->X_op = O_subtract;
+		      symbol_get_obj (sym)->size->X_add_symbol
+			= symbol_new (FAKE_LABEL_NAME, now_seg,
+				      frag_now_fix (), frag_now);
+		      symbol_get_obj (sym)->size->X_op_symbol = sym;
+		      symbol_get_obj (sym)->size->X_add_number = 0;
+		    }
 		}
 	    }
 	}
@@ -4275,7 +4430,7 @@ dot_endp (dummy)
       ++input_line_pointer;
     }
   demand_empty_rest_of_line ();
-  unwind.proc_start = unwind.proc_end = unwind.info = 0;
+  unwind.proc_start = unwind.info = 0;
 }
 
 static void
@@ -10162,6 +10317,8 @@ md_assemble (str)
       CURR_SLOT.unwind_record = unwind.current_entry;
       unwind.current_entry = NULL;
     }
+  if (unwind.proc_start && S_IS_DEFINED (unwind.proc_start))
+    unwind.insn = 1;
 
   /* Check for dependency violations.  */
   if (md.detect_dv)
---
/home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/ia64.exp	2004-07-02
08:26:34.000000000 +0200
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/ia64.exp	2005-01-24
12:01:13.450858608 +0100
@@ -58,4 +58,7 @@ if [istarget "ia64-*"] then {
 	run_dump_test "alias"
 	run_dump_test "group-1"
     }
+
+    run_list_test "proc" ""
+    run_list_test "unwind-err" ""
 }
---
/home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/proc.l	1970-01-01
01:00:00.000000000 +0100
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/proc.l	2005-01-21
15:59:27.000000000 +0100
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:5: Error: .* already defined.*
+.*:8: Error: .* not defined.*
---
/home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/proc.s	1970-01-01
01:00:00.000000000 +0100
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/proc.s	2005-01-21
10:58:40.000000000 +0100
@@ -0,0 +1,11 @@
+.explicit
+func1::
+	br.ret.sptk rp
+
+.proc	func, func1, func2
+func::
+	br.ret.sptk rp
+.endp	func, func1, func2
+
+func2::
+	br.ret.sptk rp
---
/home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.l	1970-01-01
01:00:00.000000000 +0100
+++
2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.l	2005-01-21
16:04:43.000000000 +0100
@@ -0,0 +1,32 @@
+.*: Assembler messages:
+.*:1: Error: .endp outside of procedure
+.*:2: Error: .personality outside of procedure
+.*:3: Error: .unwentry outside of procedure
+.*:4: Error: .unwabi outside of procedure
+.*:5: Error: .handlerdata outside of procedure
+.*:6: Error: .prologue outside of procedure
+.*:7: Error: .body outside of procedure
+.*:8: Error: .spillreg outside of procedure
+.*:9: Error: .spillreg.p outside of procedure
+.*:10: Error: .spillmem outside of procedure
+.*:11: Error: .spillmem.p outside of procedure
+.*:12: Error: .spillmem outside of procedure
+.*:13: Error: .spillmem.p outside of procedure
+.*:14: Error: .restorereg outside of procedure
+.*:15: Error: .restorereg.p outside of procedure
+.*:24: Error: .label_state outside of body region
+.*:25: Error: .copy_state outside of body region
+.*:26: Error: .fframe outside of prologue
+.*:27: Error: .vframe outside of prologue
+.*:28: Error: .spill outside of prologue
+.*:29: Error: .restore outside of body region
+.*:30: Error: .save outside of prologue
+.*:31: Error: .savesp outside of prologue
+.*:32: Error: .savepsp outside of prologue
+.*:33: Error: .save.g outside of prologue
+.*:34: Error: .save.gf outside of prologue
+.*:35: Error: .save.f outside of prologue
+.*:36: Error: .save.b outside of prologue
+.*:37: Error: .altrp outside of prologue
+.*:42: Error: .prologue within prologue
+.*:52: Error: .body outside of procedure
---
/home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.s	1970-01-01
01:00:00.000000000 +0100
+++
2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.s	2005-01-21
16:05:02.000000000 +0100
@@ -0,0 +1,54 @@
+.endp	xyz
+.personality personality
+.unwentry
+.unwabi @svr4, 0
+.handlerdata
+.prologue
+.body
+.spillreg r4, r8
+.spillreg.p p1, r4, r8
+.spillsp r5, 0
+.spillsp.p p2, r5, 0
+.spillpsp r6, 0
+.spillpsp.p p2, r6, 0
+.restorereg r4
+.restorereg.p p1, r4
+
+.proc	personality
+personality:
+.endp	personality
+
+.proc	start
+start:
+
+.label_state 1
+.copy_state 1
+.fframe 0
+.vframe r0
+.spill 0
+.restore sp
+.save rp, r0
+.savesp pr, 0
+.savepsp ar.fpsr, 0
+.save.g 2
+.save.gf 2,2
+.save.f 2
+.save.b 2
+.altrp b7
+.body
+
+
+	.prologue
+	.prologue
+	.save		ar.lc, r31
+	mov		r31 = ar.lc
+	;;
+	.body
+	.body
+	br.ret.sptk	rp
+	;;
+.personality personality
+.handlerdata
+.body
+
+.endp	start


[-- Attachment #2: binutils-mainline-ia64-unwind-directives.patch --]
[-- Type: text/plain, Size: 20360 bytes --]

Unwind directives were not checked for proper placement. Semantics of the
entry points specified by .proc and .endp were not enforced.

Built and tested on ia64-unknown-linux-gnu.

Jan

gas/
2005-01-24  Jan Beulich  <jbeulich@novell.com>

	* config/tc-ia64.c (unwind): Remove proc_end (now an automatic
	variable in dot_endp). Add body and insn. Make prologue,
	prologue_mask, body, and insn bitfields.
	(fixup_unw_records): Remove spurious new-lines from end of diagnostic
	messages.
	(in_procedure, in_prologue, in_body): New.
	(dot_fframe, dot_vframe, dot_vframesp, dot_vframepsp, dot_save,
	dot_restore, dot_restorereg, dot_restorereg_p, dot_handlerdata,
	dot_unwentry, dot_altrp, dot_savemem, dot_saveg, dot_savef, dot_saveb,
	dot_savegf, dot_spill, dot_spillreg, dot_spillmem, dot_spillreg_p,
	dot_spillmem_p, dot_label_state, dot_copy_state, dot_unwabi,
	dot_personality): Use the appropriate one of the above.
	(dot_proc): Clear unwind.proc_start; set to current location only if
	none of the entry points were valid. Check for non-zero-length entry
	point names. Check that entry points aren't defined, yet. Clear
	unwind.prologue, unwind.body, and unwind.insn.
	(dot_body): Call in_procedure. Check that first directive in procedure
	had no insns emitted before. Set unwind.body.
	(dot_prologue): Call in_procedure. Check that not already in prologue.
	Check that first directive in procedure had no insns emitted before.
	Clear unwind.body.
	(dot_endp): Call in_procedure. Declare proc_end. Check for non-zero-
	length entry point names. Check that entry points became defined.
	(md_assemble): Set unwind.insn once unwind.proc_start is defined.

gas/testsuite/
2005-01-24  Jan Beulich  <jbeulich@novell.com>

	* gas/ia64/proc.[ls]: New.
	* gas/ia64/unwind-err.[ls]: New.
	* gas/ia64/ia64.exp: Run new tests.

--- /home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/config/tc-ia64.c	2005-01-18 10:43:33.000000000 +0100
+++ 2005-01-24.08.40/gas/config/tc-ia64.c	2005-01-24 12:03:38.038747462 +0100
@@ -684,7 +684,6 @@ static struct
 
   /* These are used to create the unwind table entry for this function.  */
   symbolS *proc_start;
-  symbolS *proc_end;
   symbolS *info;		/* pointer to unwind info */
   symbolS *personality_routine;
   segT saved_text_seg;
@@ -692,8 +691,10 @@ static struct
   unsigned int force_unwind_entry : 1;	/* force generation of unwind entry? */
 
   /* TRUE if processing unwind directives in a prologue region.  */
-  int prologue;
-  int prologue_mask;
+  unsigned int prologue : 1;
+  unsigned int prologue_mask : 4;
+  unsigned int body : 1;
+  unsigned int insn : 1;
   unsigned int prologue_count;	/* number of .prologues seen so far */
   /* Prologue counts at previous .label_state directives.  */
   struct label_prologue_count * saved_prologue_counts;
@@ -2785,7 +2786,7 @@ fixup_unw_records (list, before_relax)
 	case frgr_mem:
 	  if (!region)
 	    {
-	      as_bad ("frgr_mem record before region record!\n");
+	      as_bad ("frgr_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.fr_mem |= ptr->r.record.p.frmask;
@@ -2796,7 +2797,7 @@ fixup_unw_records (list, before_relax)
 	case fr_mem:
 	  if (!region)
 	    {
-	      as_bad ("fr_mem record before region record!\n");
+	      as_bad ("fr_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.fr_mem |= ptr->r.record.p.rmask;
@@ -2805,7 +2806,7 @@ fixup_unw_records (list, before_relax)
 	case gr_mem:
 	  if (!region)
 	    {
-	      as_bad ("gr_mem record before region record!\n");
+	      as_bad ("gr_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.gr_mem |= ptr->r.record.p.rmask;
@@ -2814,7 +2815,7 @@ fixup_unw_records (list, before_relax)
 	case br_mem:
 	  if (!region)
 	    {
-	      as_bad ("br_mem record before region record!\n");
+	      as_bad ("br_mem record before region record!");
 	      return;
 	    }
 	  region->r.record.r.mask.br_mem |= ptr->r.record.p.brmask;
@@ -2824,7 +2825,7 @@ fixup_unw_records (list, before_relax)
 	case gr_gr:
 	  if (!region)
 	    {
-	      as_bad ("gr_gr record before region record!\n");
+	      as_bad ("gr_gr record before region record!");
 	      return;
 	    }
 	  set_imask (region, ptr->r.record.p.grmask, t, 2);
@@ -2832,7 +2833,7 @@ fixup_unw_records (list, before_relax)
 	case br_gr:
 	  if (!region)
 	    {
-	      as_bad ("br_gr record before region record!\n");
+	      as_bad ("br_gr record before region record!");
 	      return;
 	    }
 	  set_imask (region, ptr->r.record.p.brmask, t, 3);
@@ -3061,6 +3062,43 @@ dot_special_section (which)
   set_section ((char *) special_section_name[which]);
 }
 
+static int
+in_procedure (const char *directive)
+{
+  if (unwind.proc_start
+      && (!unwind.saved_text_seg || strcmp (directive, "endp") == 0))
+    return 1;
+  as_bad (".%s outside of procedure", directive);
+  ignore_rest_of_line ();
+  return 0;
+}
+
+static int
+in_prologue (const char *directive)
+{
+  if (in_procedure (directive))
+    {
+      if (unwind.prologue)
+	return 1;
+      as_bad (".%s outside of prologue", directive);
+      ignore_rest_of_line ();
+    }
+  return 0;
+}
+
+static int
+in_body (const char *directive)
+{
+  if (in_procedure (directive))
+    {
+      if (unwind.body)
+	return 1;
+      as_bad (".%s outside of body region", directive);
+      ignore_rest_of_line ();
+    }
+  return 0;
+}
+
 static void
 add_unwind_entry (ptr)
      unw_rec_list *ptr;
@@ -3082,6 +3120,9 @@ dot_fframe (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("fframe"))
+    return;
+
   parse_operand (&e);
 
   if (e.X_op != O_constant)
@@ -3097,6 +3138,9 @@ dot_vframe (dummy)
   expressionS e;
   unsigned reg;
 
+  if (!in_prologue ("vframe"))
+    return;
+
   parse_operand (&e);
   reg = e.X_add_number - REG_GR;
   if (e.X_op == O_register && reg < 128)
@@ -3115,6 +3159,9 @@ dot_vframesp (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("vframesp"))
+    return;
+
   parse_operand (&e);
   if (e.X_op == O_constant)
     {
@@ -3131,6 +3178,9 @@ dot_vframepsp (dummy)
 {
   expressionS e;
 
+  if (!in_prologue ("vframepsp"))
+    return;
+
   parse_operand (&e);
   if (e.X_op == O_constant)
     {
@@ -3149,6 +3199,9 @@ dot_save (dummy)
   int sep;
   int reg1, reg2;
 
+  if (!in_prologue ("save"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     as_bad ("No second operand to .save");
@@ -3226,6 +3279,9 @@ dot_restore (dummy)
   unsigned long ecount;	/* # of _additional_ regions to pop */
   int sep;
 
+  if (!in_body ("restore"))
+    return;
+
   sep = parse_operand (&e1);
   if (e1.X_op != O_register || e1.X_add_number != REG_GR + 12)
     {
@@ -3268,6 +3324,9 @@ dot_restorereg (dummy)
   unsigned int ab, reg;
   expressionS e;
 
+  if (!in_procedure ("restorereg"))
+    return;
+
   parse_operand (&e);
 
   if (!convert_expr_to_ab_reg (&e, &ab, &reg))
@@ -3286,6 +3345,9 @@ dot_restorereg_p (dummy)
   expressionS e1, e2;
   int sep;
 
+  if (!in_procedure ("restorereg.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3517,6 +3579,8 @@ static void
 dot_handlerdata (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  if (!in_procedure ("handlerdata"))
+    return;
   unwind.force_unwind_entry = 1;
 
   /* Remember which segment we're in so we can switch back after .endp */
@@ -3534,6 +3598,8 @@ static void
 dot_unwentry (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  if (!in_procedure ("unwentry"))
+    return;
   unwind.force_unwind_entry = 1;
   demand_empty_rest_of_line ();
 }
@@ -3545,6 +3611,9 @@ dot_altrp (dummy)
   expressionS e;
   unsigned reg;
 
+  if (!in_prologue ("altrp"))
+    return;
+
   parse_operand (&e);
   reg = e.X_add_number - REG_BR;
   if (e.X_op == O_register && reg < 8)
@@ -3561,6 +3630,9 @@ dot_savemem (psprel)
   int sep;
   int reg1, val;
 
+  if (!in_prologue (psprel ? "savepsp" : "savesp"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     as_bad ("No second operand to .save%ssp", psprel ? "p" : "");
@@ -3653,6 +3725,10 @@ dot_saveg (dummy)
 {
   expressionS e1, e2;
   int sep;
+
+  if (!in_prologue ("save.g"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep == ',')
     parse_operand (&e2);
@@ -3681,6 +3757,10 @@ dot_savef (dummy)
 {
   expressionS e1;
   int sep;
+
+  if (!in_prologue ("save.f"))
+    return;
+
   sep = parse_operand (&e1);
 
   if (e1.X_op != O_constant)
@@ -3698,6 +3778,9 @@ dot_saveb (dummy)
   unsigned char sep;
   int brmask;
 
+  if (!in_prologue ("save.b"))
+    return;
+
   sep = parse_operand (&e1);
   if (e1.X_op != O_constant)
     {
@@ -3730,6 +3813,10 @@ dot_savegf (dummy)
 {
   expressionS e1, e2;
   int sep;
+
+  if (!in_prologue ("save.gf"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep == ',')
     parse_operand (&e2);
@@ -3751,6 +3838,9 @@ dot_spill (dummy)
   expressionS e;
   unsigned char sep;
 
+  if (!in_prologue ("spill"))
+    return;
+
   sep = parse_operand (&e);
   if (!is_end_of_line[sep] && !is_it_end_of_statement ())
     demand_empty_rest_of_line ();
@@ -3768,6 +3858,9 @@ dot_spillreg (dummy)
   int sep, ab, xy, reg, treg;
   expressionS e1, e2;
 
+  if (!in_procedure ("spillreg"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3799,6 +3892,9 @@ dot_spillmem (psprel)
   expressionS e1, e2;
   int sep, ab, reg;
 
+  if (!in_procedure ("spillmem"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3836,6 +3932,9 @@ dot_spillreg_p (dummy)
   expressionS e1, e2, e3;
   unsigned int qp;
 
+  if (!in_procedure ("spillreg.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3883,6 +3982,9 @@ dot_spillmem_p (psprel)
   int sep, ab, reg;
   unsigned int qp;
 
+  if (!in_procedure ("spillmem.p"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -3988,6 +4090,9 @@ dot_label_state (dummy)
 {
   expressionS e;
 
+  if (!in_body ("label_state"))
+    return;
+
   parse_operand (&e);
   if (e.X_op != O_constant)
     {
@@ -4004,6 +4109,9 @@ dot_copy_state (dummy)
 {
   expressionS e;
 
+  if (!in_body ("copy_state"))
+    return;
+
   parse_operand (&e);
   if (e.X_op != O_constant)
     {
@@ -4021,6 +4129,9 @@ dot_unwabi (dummy)
   expressionS e1, e2;
   unsigned char sep;
 
+  if (!in_procedure ("unwabi"))
+    return;
+
   sep = parse_operand (&e1);
   if (sep != ',')
     {
@@ -4051,6 +4162,8 @@ dot_personality (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
   char *name, *p, c;
+  if (!in_procedure ("personality"))
+    return;
   SKIP_WHITESPACE ();
   name = input_line_pointer;
   c = get_symbol_end ();
@@ -4069,7 +4182,7 @@ dot_proc (dummy)
   char *name, *p, c;
   symbolS *sym;
 
-  unwind.proc_start = expr_build_dot ();
+  unwind.proc_start = 0;
   /* Parse names of main and alternate entry points and mark them as
      function symbols:  */
   while (1)
@@ -4078,22 +4191,34 @@ dot_proc (dummy)
       name = input_line_pointer;
       c = get_symbol_end ();
       p = input_line_pointer;
-      sym = symbol_find_or_make (name);
-      if (unwind.proc_start == 0)
+      if (!*name)
+	as_bad ("Empty argument of .proc");
+      else
 	{
-	  unwind.proc_start = sym;
+	  sym = symbol_find_or_make (name);
+	  if (S_IS_DEFINED (sym))
+	    as_bad ("`%s' was already defined", name);
+	  else if (unwind.proc_start == 0)
+	    {
+	      unwind.proc_start = sym;
+	    }
+	  symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
 	}
-      symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
       *p = c;
       SKIP_WHITESPACE ();
       if (*input_line_pointer != ',')
 	break;
       ++input_line_pointer;
     }
+  if (unwind.proc_start == 0)
+    unwind.proc_start = expr_build_dot ();
   demand_empty_rest_of_line ();
   ia64_do_align (16);
 
+  unwind.prologue = 0;
   unwind.prologue_count = 0;
+  unwind.body = 0;
+  unwind.insn = 0;
   unwind.list = unwind.tail = unwind.current_entry = NULL;
   unwind.personality_routine = 0;
 }
@@ -4102,8 +4227,14 @@ static void
 dot_body (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
+  if (!in_procedure ("body"))
+    return;
+  if (!unwind.prologue && !unwind.body && unwind.insn)
+    as_warn ("Initial .body should precede any instructions");
+
   unwind.prologue = 0;
   unwind.prologue_mask = 0;
+  unwind.body = 1;
 
   add_unwind_entry (output_body ());
   demand_empty_rest_of_line ();
@@ -4116,6 +4247,17 @@ dot_prologue (dummy)
   unsigned char sep;
   int mask = 0, grsave = 0;
 
+  if (!in_procedure ("prologue"))
+    return;
+  if (unwind.prologue)
+    {
+      as_bad (".prologue within prologue");
+      ignore_rest_of_line ();
+      return;
+    }
+  if (!unwind.body && unwind.insn)
+    as_warn ("Initial .prologue should precede any instructions");
+
   if (!is_it_end_of_statement ())
     {
       expressionS e1, e2;
@@ -4148,6 +4290,7 @@ dot_prologue (dummy)
 
   unwind.prologue = 1;
   unwind.prologue_mask = mask;
+  unwind.body = 0;
   ++unwind.prologue_count;
 }
 
@@ -4164,6 +4307,9 @@ dot_endp (dummy)
   char *name, *p, c;
   symbolS *sym;
 
+  if (!in_procedure ("endp"))
+    return;
+
   if (unwind.saved_text_seg)
     {
       saved_seg = unwind.saved_text_seg;
@@ -4184,8 +4330,10 @@ dot_endp (dummy)
 
   if (unwind.info || unwind.force_unwind_entry)
     {
+      symbolS *proc_end;
+
       subseg_set (md.last_text_seg, 0);
-      unwind.proc_end = expr_build_dot ();
+      proc_end = expr_build_dot ();
 
       start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 0);
 
@@ -4209,7 +4357,7 @@ dot_endp (dummy)
       e.X_op = O_pseudo_fixup;
       e.X_op_symbol = pseudo_func[FUNC_SEG_RELATIVE].u.sym;
       e.X_add_number = 0;
-      e.X_add_symbol = unwind.proc_end;
+      e.X_add_symbol = proc_end;
       ia64_cons_fix_new (frag_now, where + bytes_per_address,
 			 bytes_per_address, &e);
 
@@ -4239,32 +4387,39 @@ dot_endp (dummy)
       name = input_line_pointer;
       c = get_symbol_end ();
       p = input_line_pointer;
-      sym = symbol_find (name);
-      if (sym && unwind.proc_start
-	  && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
-	  && S_GET_SIZE (sym) == 0 && symbol_get_obj (sym)->size == NULL)
-	{
-	  fragS *fr = symbol_get_frag (unwind.proc_start);
-	  fragS *frag = symbol_get_frag (sym);
-
-	  /* Check whether the function label is at or beyond last
-	     .proc directive.  */
-	  while (fr && fr != frag)
-	    fr = fr->fr_next;
-	  if (fr)
-	    {
-	      if (frag == frag_now && SEG_NORMAL (now_seg))
-		S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
-	      else
+      if (!*name)
+	as_bad ("Empty argument of .endp");
+      else
+	{
+	  sym = symbol_find (name);
+	  if (!sym || !S_IS_DEFINED (sym))
+	    as_bad ("`%s' was not defined within procedure", name);
+	  else if (sym && unwind.proc_start
+	      && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
+	      && S_GET_SIZE (sym) == 0 && symbol_get_obj (sym)->size == NULL)
+	    {
+	      fragS *fr = symbol_get_frag (unwind.proc_start);
+	      fragS *frag = symbol_get_frag (sym);
+
+	      /* Check whether the function label is at or beyond last
+		 .proc directive.  */
+	      while (fr && fr != frag)
+		fr = fr->fr_next;
+	      if (fr)
 		{
-		  symbol_get_obj (sym)->size =
-		    (expressionS *) xmalloc (sizeof (expressionS));
-		  symbol_get_obj (sym)->size->X_op = O_subtract;
-		  symbol_get_obj (sym)->size->X_add_symbol
-		    = symbol_new (FAKE_LABEL_NAME, now_seg,
-				  frag_now_fix (), frag_now);
-		  symbol_get_obj (sym)->size->X_op_symbol = sym;
-		  symbol_get_obj (sym)->size->X_add_number = 0;
+		  if (frag == frag_now && SEG_NORMAL (now_seg))
+		    S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
+		  else
+		    {
+		      symbol_get_obj (sym)->size =
+			(expressionS *) xmalloc (sizeof (expressionS));
+		      symbol_get_obj (sym)->size->X_op = O_subtract;
+		      symbol_get_obj (sym)->size->X_add_symbol
+			= symbol_new (FAKE_LABEL_NAME, now_seg,
+				      frag_now_fix (), frag_now);
+		      symbol_get_obj (sym)->size->X_op_symbol = sym;
+		      symbol_get_obj (sym)->size->X_add_number = 0;
+		    }
 		}
 	    }
 	}
@@ -4275,7 +4430,7 @@ dot_endp (dummy)
       ++input_line_pointer;
     }
   demand_empty_rest_of_line ();
-  unwind.proc_start = unwind.proc_end = unwind.info = 0;
+  unwind.proc_start = unwind.info = 0;
 }
 
 static void
@@ -10162,6 +10317,8 @@ md_assemble (str)
       CURR_SLOT.unwind_record = unwind.current_entry;
       unwind.current_entry = NULL;
     }
+  if (unwind.proc_start && S_IS_DEFINED (unwind.proc_start))
+    unwind.insn = 1;
 
   /* Check for dependency violations.  */
   if (md.detect_dv)
--- /home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/ia64.exp	2004-07-02 08:26:34.000000000 +0200
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/ia64.exp	2005-01-24 12:01:13.450858608 +0100
@@ -58,4 +58,7 @@ if [istarget "ia64-*"] then {
 	run_dump_test "alias"
 	run_dump_test "group-1"
     }
+
+    run_list_test "proc" ""
+    run_list_test "unwind-err" ""
 }
--- /home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/proc.l	1970-01-01 01:00:00.000000000 +0100
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/proc.l	2005-01-21 15:59:27.000000000 +0100
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:5: Error: .* already defined.*
+.*:8: Error: .* not defined.*
--- /home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/proc.s	1970-01-01 01:00:00.000000000 +0100
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/proc.s	2005-01-21 10:58:40.000000000 +0100
@@ -0,0 +1,11 @@
+.explicit
+func1::
+	br.ret.sptk rp
+
+.proc	func, func1, func2
+func::
+	br.ret.sptk rp
+.endp	func, func1, func2
+
+func2::
+	br.ret.sptk rp
--- /home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.l	1970-01-01 01:00:00.000000000 +0100
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.l	2005-01-21 16:04:43.000000000 +0100
@@ -0,0 +1,32 @@
+.*: Assembler messages:
+.*:1: Error: .endp outside of procedure
+.*:2: Error: .personality outside of procedure
+.*:3: Error: .unwentry outside of procedure
+.*:4: Error: .unwabi outside of procedure
+.*:5: Error: .handlerdata outside of procedure
+.*:6: Error: .prologue outside of procedure
+.*:7: Error: .body outside of procedure
+.*:8: Error: .spillreg outside of procedure
+.*:9: Error: .spillreg.p outside of procedure
+.*:10: Error: .spillmem outside of procedure
+.*:11: Error: .spillmem.p outside of procedure
+.*:12: Error: .spillmem outside of procedure
+.*:13: Error: .spillmem.p outside of procedure
+.*:14: Error: .restorereg outside of procedure
+.*:15: Error: .restorereg.p outside of procedure
+.*:24: Error: .label_state outside of body region
+.*:25: Error: .copy_state outside of body region
+.*:26: Error: .fframe outside of prologue
+.*:27: Error: .vframe outside of prologue
+.*:28: Error: .spill outside of prologue
+.*:29: Error: .restore outside of body region
+.*:30: Error: .save outside of prologue
+.*:31: Error: .savesp outside of prologue
+.*:32: Error: .savepsp outside of prologue
+.*:33: Error: .save.g outside of prologue
+.*:34: Error: .save.gf outside of prologue
+.*:35: Error: .save.f outside of prologue
+.*:36: Error: .save.b outside of prologue
+.*:37: Error: .altrp outside of prologue
+.*:42: Error: .prologue within prologue
+.*:52: Error: .body outside of procedure
--- /home/jbeulich/src/binutils/mainline/2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.s	1970-01-01 01:00:00.000000000 +0100
+++ 2005-01-24.08.40/gas/testsuite/gas/ia64/unwind-err.s	2005-01-21 16:05:02.000000000 +0100
@@ -0,0 +1,54 @@
+.endp	xyz
+.personality personality
+.unwentry
+.unwabi @svr4, 0
+.handlerdata
+.prologue
+.body
+.spillreg r4, r8
+.spillreg.p p1, r4, r8
+.spillsp r5, 0
+.spillsp.p p2, r5, 0
+.spillpsp r6, 0
+.spillpsp.p p2, r6, 0
+.restorereg r4
+.restorereg.p p1, r4
+
+.proc	personality
+personality:
+.endp	personality
+
+.proc	start
+start:
+
+.label_state 1
+.copy_state 1
+.fframe 0
+.vframe r0
+.spill 0
+.restore sp
+.save rp, r0
+.savesp pr, 0
+.savepsp ar.fpsr, 0
+.save.g 2
+.save.gf 2,2
+.save.f 2
+.save.b 2
+.altrp b7
+.body
+
+
+	.prologue
+	.prologue
+	.save		ar.lc, r31
+	mov		r31 = ar.lc
+	;;
+	.body
+	.body
+	br.ret.sptk	rp
+	;;
+.personality personality
+.handlerdata
+.body
+
+.endp	start

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2005-02-11 19:49 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-02-02 14:52 [PATCH] ia64 unwind directive semantics Jan Beulich
2005-02-11  1:39 ` James E Wilson
     [not found] <s20ca004.024@emea1-mh.id2.novell.com>
2005-02-11 23:15 ` James E Wilson
  -- strict thread matches above, loose matches on Subject: below --
2005-02-11 15:58 Jan Beulich
2005-02-02 13:56 Jan Beulich
     [not found] <s1fa08eb.028@emea1-mh.id2.novell.com>
2005-01-29  1:49 ` James E Wilson
2005-01-28  9:43 Jan Beulich
2005-01-24 11:29 Jan Beulich
2005-01-28  3:52 ` James E Wilson
2005-02-02  8:16 ` Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).