[binutils-gdb] gas: avoid (scrubber) diagnostics for stuff past .end

Jan Beulich jbeulich@sourceware.org
Wed Sep 11 11:56:52 GMT 2024


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=6fc346a4b39f7658e99522529308a23b8543ffe3

commit 6fc346a4b39f7658e99522529308a23b8543ffe3
Author: Jan Beulich <jbeulich@suse.com>
Date:   Wed Sep 11 13:56:36 2024 +0200

    gas: avoid (scrubber) diagnostics for stuff past .end
    
    What's past an active .end directive (when that has its default purpose)
    is supposed to be entirely ignored. That should be true not just for
    regular processing, but also for "pre-processing" (aka scrubbing). A
    complication is that such a directive may of course occur inside a
    (false) conditional or a macro definition. To deal with that make sure
    we can continue as usual if called another time.
    
    Note however that .end inside a macro will still have the full macro
    body expanded; dealing with that would require further (perhaps
    intrusive) adjustments in sb_scrub_and_add_sb() and/or callers thereof.
    However, at least some of the warnings issued by do_scrub_chars() are
    unlikely to occur when expanding a macro. (If we needed to go that far,
    presumably .exitm would also want recognizing.)

Diff:
---
 gas/app.c                          | 57 +++++++++++++++++++++++++++++++++++++-
 gas/testsuite/gas/all/end-no-dot.l |  3 ++
 gas/testsuite/gas/all/end-no-dot.s | 11 ++++++++
 gas/testsuite/gas/all/end.l        |  3 ++
 gas/testsuite/gas/all/end.s        | 11 ++++++++
 gas/testsuite/gas/all/gas.exp      | 24 ++++++++++++++++
 6 files changed, 108 insertions(+), 1 deletion(-)

diff --git a/gas/app.c b/gas/app.c
index 743062e8b82..8dc69ff4ce0 100644
--- a/gas/app.c
+++ b/gas/app.c
@@ -58,6 +58,15 @@ static const char   symver_pseudo[] = ".symver";
 static const char * symver_state;
 #endif
 
+/* The pseudo-op (without leading dot) at which we want to (perhaps just
+   temporarily) stop processing.  See the comments in do_scrub_chars().  */
+static const char   end_pseudo[] = "end ";
+static const char * end_state;
+
+/* Whether, considering the state at start of assembly, NO_PSEUDO_DOT is
+   active.  */
+static bool no_pseudo_dot;
+
 static char last_char;
 
 #define LEX_IS_SYMBOL_COMPONENT		1
@@ -161,6 +170,12 @@ do_scrub_begin (int m68k_mri ATTRIBUTE_UNUSED)
 {
   const char *p;
 
+  /* Latch this once at start.  xtensa uses a hook function, yet context isn't
+     meaningful for scrubbing (or else we'd need to sync scrubber behavior as
+     state changes).  */
+  if (lex['/'] == 0)
+    no_pseudo_dot = NO_PSEUDO_DOT;
+
 #ifdef TC_M68K
   scrub_m68k_mri = m68k_mri;
 
@@ -282,6 +297,7 @@ struct app_save
   int          add_newlines;
   char *       saved_input;
   size_t       saved_input_len;
+  const char * end_state;
 #ifdef TC_M68K
   int          scrub_m68k_mri;
   const char * mri_state;
@@ -312,6 +328,7 @@ app_push (void)
       memcpy (saved->saved_input, saved_input, saved_input_len);
       saved->saved_input_len = saved_input_len;
     }
+  saved->end_state = end_state;
 #ifdef TC_M68K
   saved->scrub_m68k_mri = scrub_m68k_mri;
   saved->mri_state = mri_state;
@@ -352,6 +369,7 @@ app_pop (char *arg)
       saved_input_len = saved->saved_input_len;
       free (saved->saved_input);
     }
+  end_state = saved->end_state;
 #ifdef TC_M68K
   scrub_m68k_mri = saved->scrub_m68k_mri;
   mri_state = saved->mri_state;
@@ -800,6 +818,43 @@ do_scrub_chars (size_t (*get) (char *, size_t), char *tostart, size_t tolen,
 
     recycle:
 
+      /* We need to watch out for .end directives: We should in particular not
+	 issue diagnostics for anything after an active one.  */
+      if (end_state == NULL)
+	{
+	  if ((state == 0 || state == 1)
+	      && (ch == '.'
+		  || (no_pseudo_dot && ch == end_pseudo[0])))
+	    end_state = end_pseudo + (ch != '.');
+	}
+      else if (ch != '\0'
+	       && (*end_state == ch
+		   /* Avoid triggering on directives like .endif or .endr.  */
+		   || (*end_state == ' ' && !IS_SYMBOL_COMPONENT (ch))))
+	{
+ 	  if (IS_NEWLINE (ch) || IS_LINE_SEPARATOR (ch))
+ 	    goto end_end;
+	  ++end_state;
+	}
+      else if (*end_state != '\0')
+	/* We did not get the expected character, or we didn't
+	   get a valid terminating character after seeing the
+	   entire pseudo-op, so we must go back to the beginning.  */
+	end_state = NULL;
+      else if (IS_NEWLINE (ch) || IS_LINE_SEPARATOR (ch))
+	{
+	end_end:
+	  /* We've read the entire pseudo-op.  If this is the end of the line,
+	     bail out now by (ab)using the output-full path.  This allows the
+	     caller to process input up to here and terminate processing if this
+	     directive is actually active (not on the false branch of a
+	     conditional and not in a macro definition).  */
+	  end_state = NULL;
+	  state = 0;
+	  PUT (ch);
+	  goto tofull;
+	}
+
 #if defined TC_ARM && defined OBJ_ELF
       /* We need to watch out for .symver directives.  See the comment later
 	 in this function.  */
@@ -1440,7 +1495,7 @@ do_scrub_chars (size_t (*get) (char *, size_t), char *tostart, size_t tolen,
 #if defined TC_ARM && defined OBJ_ELF
 	      && symver_state == NULL
 #endif
-	      )
+	      && end_state == NULL)
 	    {
 	      char *s;
 	      ptrdiff_t len;
diff --git a/gas/testsuite/gas/all/end-no-dot.l b/gas/testsuite/gas/all/end-no-dot.l
new file mode 100644
index 00000000000..fa47ae3f7a9
--- /dev/null
+++ b/gas/testsuite/gas/all/end-no-dot.l
@@ -0,0 +1,3 @@
+# No diagnostics should appear for anything past "end".
+>3<
+>4<
diff --git a/gas/testsuite/gas/all/end-no-dot.s b/gas/testsuite/gas/all/end-no-dot.s
new file mode 100644
index 00000000000..bee10c859bc
--- /dev/null
+++ b/gas/testsuite/gas/all/end-no-dot.s
@@ -0,0 +1,11 @@
+	if 0
+	end a b c
+	endif
+
+	irpc n,34
+	print ">\n<"
+	endr
+
+	end q r, s
+	"\z"
+	äöü'\
\ No newline at end of file
diff --git a/gas/testsuite/gas/all/end.l b/gas/testsuite/gas/all/end.l
new file mode 100644
index 00000000000..e18518dffa1
--- /dev/null
+++ b/gas/testsuite/gas/all/end.l
@@ -0,0 +1,3 @@
+# No diagnostics should appear for anything past .end.
+>1<
+>2<
diff --git a/gas/testsuite/gas/all/end.s b/gas/testsuite/gas/all/end.s
new file mode 100644
index 00000000000..3090792125e
--- /dev/null
+++ b/gas/testsuite/gas/all/end.s
@@ -0,0 +1,11 @@
+	.if 0
+	.end a b c
+	.endif
+
+	.irpc n,12
+	.print ">\n<"
+	.endr
+
+	.end q r, s
+	"\z"
+	äöü'\
\ No newline at end of file
diff --git a/gas/testsuite/gas/all/gas.exp b/gas/testsuite/gas/all/gas.exp
index 45d037cc190..5fff61f86ed 100644
--- a/gas/testsuite/gas/all/gas.exp
+++ b/gas/testsuite/gas/all/gas.exp
@@ -464,6 +464,30 @@ switch -glob $target_triplet {
 	run_dump_test weakref1w
     }
 }
+
+# .end works differently on some targets. Also make sure to test the dot-less
+# form on targets setting NO_PSEUDO_DOT (and not overriding the directive).
+switch -glob $target_triplet {
+    alpha*-*-* { }
+    hppa*-*-* { }
+    iq2000-*-* { }
+    microblaze-*-* { }
+    mips*-*-* { }
+    score*-*-* { }
+    xtensa*-*-* { }
+    m68hc1*-*-* -
+    s12z-*-*    -
+    spu-*-*     -
+    xgate-*-*   -
+    z80-*-* {
+	run_list_test "end"
+	run_list_test "end-no-dot"
+    }
+    default {
+	run_list_test "end"
+    }
+}
+
 gas_test_error "weakref2.s" "" "e: would close weakref loop: e => a => b => c => d => e"
 gas_test_error "weakref3.s" "" "a: would close weakref loop: a => b => c => d => e => a"
 gas_test_error "weakref4.s" "" "is already defined"


More information about the Binutils-cvs mailing list