[PATCH RFC 3/3] gas: introduce .errif and .warnif
Jan Beulich
jbeulich@suse.com
Mon Dec 9 09:22:15 GMT 2024
Rather than having people resort to indirect means to issue a certain
kind of diagnostic conditionally upon an expression which can (or
should) only be evaluated when all sections were sized and all symbols
has their final values established, provide directives to directly
achieve this.
---
Should we save the (textual) expression, to quote it when emitting the
diagnostic?
NOTE: Depends on "aarch64: re-work PR gas/27217 fix again"
(latched_dot_expression()), unless that would be re-worked such
that deferred_expression() would need using here.
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,8 @@
-*- text -*-
+* Add .errif and .warnif directives, permitting user-controlled diagnostics
+ with conditionals that are evaluated only at the end of assembly.
+
* Add support for the x86 Intel MSR_IMM instructions.
* Add support for the x86 Zhaoxin GMI instructions.
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -4577,6 +4577,7 @@ Some machine configurations provide addi
* Equiv:: @code{.equiv @var{symbol}, @var{expression}}
* Eqv:: @code{.eqv @var{symbol}, @var{expression}}
* Err:: @code{.err}
+* Errif:: @code{.errif @var{expression}}
* Error:: @code{.error @var{string}}
* Exitm:: @code{.exitm}
* Extern:: @code{.extern}
@@ -4709,6 +4710,7 @@ Some machine configurations provide addi
* VTableInherit:: @code{.vtable_inherit @var{child}, @var{parent}}
@end ifset
+* Warnif:: @code{.warnif @var{expression}}
* Warning:: @code{.warning @var{string}}
* Weak:: @code{.weak @var{names}}
* Weakref:: @code{.weakref @var{alias}, @var{symbol}}
@@ -5529,6 +5531,13 @@ If @command{@value{AS}} assembles a @cod
message and, unless the @option{-Z} option was used, it will not generate an
object file. This can be used to signal an error in conditionally compiled code.
+@node Errif
+@section @code{.errif "@var{expression}"}
+@cindex errif directive
+
+Record @var{expression} for evaluation at the end of assembly. Raise an error
+if the expression evaluates to non-zero.
+
@node Error
@section @code{.error "@var{string}"}
@cindex error directive
@@ -7714,6 +7723,13 @@ parent whose addend is the value of the
parent name of @code{0} is treated as referring to the @code{*ABS*} section.
@end ifset
+@node Warnif
+@section @code{.warnif "@var{expression}"}
+@cindex errif directive
+
+Record @var{expression} for evaluation at the end of assembly. Raise a
+warning if the expression evaluates to non-zero.
+
@node Warning
@section @code{.warning "@var{string}"}
@cindex warning directive
--- a/gas/read.c
+++ b/gas/read.c
@@ -257,6 +257,7 @@ static void do_s_func (int end_p, const
static void s_align (int, int);
static void s_altmacro (int);
static void s_bad_end (int);
+static void s_errwarn_if (int);
static void s_reloc (int);
static int hex_float (int, char *);
static segT get_known_segmented_expression (expressionS * expP);
@@ -415,6 +416,7 @@ static const pseudo_typeS potable[] = {
{"equiv", s_set, 1},
{"eqv", s_set, -1},
{"err", s_err, 0},
+ {"errif", s_errwarn_if, 1},
{"error", s_errwarn, 1},
{"exitm", s_mexit, 0},
/* extend */
@@ -529,6 +531,7 @@ static const pseudo_typeS potable[] = {
{"xdef", s_globl, 0},
{"xref", s_ignore, 0},
{"xstabs", s_xstab, 's'},
+ {"warnif", s_errwarn_if, 0},
{"warning", s_errwarn, 0},
{"weakref", s_weakref, 0},
{"word", cons, 2},
@@ -2236,6 +2239,62 @@ s_errwarn (int err)
demand_empty_rest_of_line ();
}
+/* Handle the .errif and .warnif pseudo-ops. */
+
+static struct deferred_diag {
+ struct deferred_diag *next;
+ const char *file;
+ unsigned int lineno;
+ bool err;
+ expressionS exp;
+} *deferred_diags, *last_deferred_diag;
+
+static void
+s_errwarn_if (int err)
+{
+ struct deferred_diag *diag = XNEW (struct deferred_diag);
+ int errcnt = had_errors ();
+
+ latched_dot_expression (&diag->exp);
+ if (errcnt != had_errors ())
+ {
+ ignore_rest_of_line ();
+ return;
+ }
+
+ diag->err = err;
+ diag->file = as_where (&diag->lineno);
+ diag->next = NULL;
+ if ( deferred_diags == NULL )
+ deferred_diags = diag;
+ else
+ last_deferred_diag->next = diag;
+ last_deferred_diag = diag;
+
+ demand_empty_rest_of_line ();
+}
+
+void
+evaluate_deferred_diags (void)
+{
+ struct deferred_diag *diag;
+
+ for (diag = deferred_diags; diag != NULL; diag = diag->next)
+ {
+ if (!resolve_expression (&diag->exp) || diag->exp.X_op != O_constant)
+ as_warn_where (diag->file, diag->lineno,
+ _("expression does not evaluate to a constant"));
+ else if (diag->exp.X_add_number == 0)
+ continue;
+ else if (diag->err)
+ as_bad_where (diag->file, diag->lineno,
+ _(".errif expression evaluates to true"));
+ else
+ as_warn_where (diag->file, diag->lineno,
+ _(".warnif expression evaluates to true"));
+ }
+}
+
/* Handle the MRI fail pseudo-op. */
void
--- a/gas/read.h
+++ b/gas/read.h
@@ -162,6 +162,7 @@ extern symbolS *s_comm_internal (int, sy
extern symbolS *s_lcomm_internal (int, symbolS *, addressT);
extern void temp_ilp (char *);
extern void restore_ilp (void);
+extern void evaluate_deferred_diags (void);
extern void s_file_string (char *);
extern void s_abort (int) ATTRIBUTE_NORETURN;
--- a/gas/write.c
+++ b/gas/write.c
@@ -2329,6 +2329,8 @@ write_object_file (void)
resolve_local_symbol_values ();
resolve_reloc_expr_symbols ();
+ evaluate_deferred_diags ();
+
#ifdef OBJ_ELF
if (IS_ELF)
maybe_generate_build_notes ();
--- /dev/null
+++ b/gas/testsuite/gas/all/cond-diag.l
@@ -0,0 +1,6 @@
+# This should match the output of gas cond-diag.s.
+.*: Assembler messages:
+.*:1: Error: non-constant .*
+.*:6: Error: backward ref .*
+.*:7: Warning: \.warning .*
+.*:4: Warning: \.warnif .*
--- /dev/null
+++ b/gas/testsuite/gas/all/cond-diag.s
@@ -0,0 +1,12 @@
+ .if end - start > 16
+ .warning
+ .endif
+ .warnif end - start < 16
+ .errif end - start >= 16
+ .warnif 1b
+ .warning
+
+ .data
+start:
+ .uleb128 end - start
+end:
--- a/gas/testsuite/gas/all/gas.exp
+++ b/gas/testsuite/gas/all/gas.exp
@@ -488,6 +488,19 @@ switch -glob $target_triplet {
}
}
+# This test uses a local label, which some targets don't support.
+# MeP can't deal with forward ref labels in .uleb128.
+switch -glob $target_triplet {
+ *c54x*-*-* { }
+ hppa*-*-* { }
+ ia64-*-*vms* { }
+ mep-*-* { }
+ sh-*-pe* { }
+ default {
+ run_list_test "cond-diag"
+ }
+}
+
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
mailing list