aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gas/app.c57
-rw-r--r--gas/testsuite/gas/all/end-no-dot.l3
-rw-r--r--gas/testsuite/gas/all/end-no-dot.s11
-rw-r--r--gas/testsuite/gas/all/end.l3
-rw-r--r--gas/testsuite/gas/all/end.s11
-rw-r--r--gas/testsuite/gas/all/gas.exp24
6 files changed, 108 insertions, 1 deletions
diff --git a/gas/app.c b/gas/app.c
index 743062e..8dc69ff 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 0000000..fa47ae3
--- /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 0000000..bee10c8
--- /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 0000000..e18518d
--- /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 0000000..3090792
--- /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 45d037c..5fff61f 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"