gas: initialisation of expressionS in operand()
Commit Message
This patch removes clean_up_expression which runs just before operand()
returns. clean_up_expression sets as yet uninitialised fields of
expressionS. Well, it sets fields based on the value of X_op,
trusting that others have been written, and has one notable exception:
X_md is not initialised.
Instead initialise expressionS fully inside operand(), which is called
at the start of expr(), and introduce md_expr_init for the odd
backends that want to mess with X_md.
This is in response to an oss-fuzz report that read.c:pseudo_set calls
expr() leaving exp.X_md uninitialised and can copy that to a symbol
via symbol_set_value_expression. tc-i386-intel.c:565 is one place
that later tests the uninitialised X_md.
* config/tc-z80.h (md_expr_init, md_expr_init_rest): Define.
* config/tc-microblaze.h: Likewise.
* expr.c (clean_up_expression): Delete.
(operand): Init expression early.
(expr): Use md_expr_init_rest to init X_md when necessary.
@@ -57,6 +57,12 @@ extern bfd_reloc_code_real_type parse_cons_expression_microblaze
#define tc_fix_adjustable(X) tc_microblaze_fix_adjustable(X)
extern int tc_microblaze_fix_adjustable (struct fix *);
+/* X_md is managed by the backend. */
+#define md_expr_init(exp) \
+ do memset ((exp), 0, offsetof (expressionS, X_md)); while (0)
+#define md_expr_init_rest(exp) \
+ do (exp)->X_md = 0; while (0)
+
extern const struct relax_type md_relax_table[];
#define TC_GENERIC_RELAX_TABLE md_relax_table
@@ -39,6 +39,12 @@
will point to the start of the expression. */
#define md_operand(x)
+/* X_md is managed by the backend. */
+#define md_expr_init(exp) \
+ do memset ((exp), 0, offsetof (expressionS, X_md)); while (0)
+#define md_expr_init_rest(exp) \
+ do (exp)->X_md = 0; while (0)
+
/* This should just call either `number_to_chars_bigendian' or
`number_to_chars_littleendian', whichever is appropriate. On
targets like the MIPS which support options to change the
@@ -35,8 +35,6 @@
bool literal_prefix_dollar_hex = false;
-static void clean_up_expression (expressionS * expressionP);
-
/* We keep a mapping of expression symbols to file positions, so that
we can provide better error messages. */
@@ -801,14 +799,19 @@ operand (expressionS *expressionP, enum expr_mode mode)
segT segment;
operatorT op = O_absent; /* For unary operators. */
+#ifdef md_expr_init
+ md_expr_init (expressionP);
+#else
+ memset (expressionP, 0, sizeof (*expressionP));
+#endif
+
/* All integers are regarded as unsigned unless they are negated.
This is because the only thing which cares whether a number is
unsigned is the code in emit_expr which extends constants into
bignums. It should only sign extend negative numbers, so that
something like ``.quad 0x80000000'' is not sign extended even
though it appears negative if valueT is 32 bits. */
- expressionP->X_unsigned = 1;
- expressionP->X_extrabit = 0;
+ expressionP->X_unsigned = 1; \
/* Digits, assume it is a bignum. */
@@ -1451,9 +1454,6 @@ operand (expressionS *expressionP, enum expr_mode mode)
break;
}
- /* It is more 'efficient' to clean up the expressionS when they are
- created. Doing it here saves lines of code. */
- clean_up_expression (expressionP);
SKIP_ALL_WHITESPACE (); /* -> 1st char after operand. */
know (!is_whitespace (*input_line_pointer));
@@ -1480,39 +1480,6 @@ operand (expressionS *expressionP, enum expr_mode mode)
}
}
-/* Internal. Simplify a struct expression for use by expr (). */
-
-/* In: address of an expressionS.
- The X_op field of the expressionS may only take certain values.
- Elsewise we waste time special-case testing. Sigh. Ditto SEG_ABSENT.
-
- Out: expressionS may have been modified:
- Unused fields zeroed to help expr (). */
-
-static void
-clean_up_expression (expressionS *expressionP)
-{
- switch (expressionP->X_op)
- {
- case O_illegal:
- case O_absent:
- expressionP->X_add_number = 0;
- /* Fall through. */
- case O_big:
- case O_constant:
- case O_register:
- expressionP->X_add_symbol = NULL;
- /* Fall through. */
- case O_symbol:
- case O_uminus:
- case O_bit_not:
- expressionP->X_op_symbol = NULL;
- break;
- default:
- break;
- }
-}
-
/* Expression parser. */
/* We allow an empty expression, and just assume (absolute,0) silently.
@@ -1888,7 +1855,9 @@ expr (int rankarg, /* Larger # is higher rank. */
input_line_pointer += op_chars; /* -> after operator. */
- right.X_md = 0;
+#ifdef md_expr_init_rest
+ md_expr_init_rest (&right);
+#endif
rightseg = expr (op_rank[op_left], &right, mode);
if (right.X_op == O_absent)
{