From: Jan Beulich Date: Fri, 13 Jun 2025 06:39:44 +0000 (+0200) Subject: gas: also maintain signed-ness for O_big expressions X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=023b7811d644a8e3d60b802731a8987232ebb1a0;p=thirdparty%2Fbinutils-gdb.git gas: also maintain signed-ness for O_big expressions Interestingly emit_leb128_expr() already assumes X_unsigned is properly set for O_big. Adjust its conversion-to-bignum to respect the incoming flag, and have convert_to_bignum() correctly set it on output. It further can't be quite right that convert_to_bignum() depends on anything other than the incoming expression. Therefore adjust emit_expr_with_reloc() to be in line with the other invocation. This also requires an adjustment for SH, which really should have been part of 762acf217c40 ("gas: maintain O_constant signedness in more cases"). --- diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c index 9620eef9e93..c37306f2f58 100644 --- a/gas/config/tc-sh.c +++ b/gas/config/tc-sh.c @@ -544,6 +544,7 @@ sh_optimize_expr (expressionS *l, operatorT op, expressionS *r) add_to_result (l, symval_diff, symval_diff < 0); l->X_op = O_constant; l->X_add_symbol = 0; + l->X_unsigned = 0; return 1; } return 0; diff --git a/gas/expr.c b/gas/expr.c index bf58fc3a768..78a247cde09 100644 --- a/gas/expr.c +++ b/gas/expr.c @@ -632,6 +632,7 @@ integer_constant (int radix, expressionS *expressionP) /* Not a small number. */ expressionP->X_op = O_big; expressionP->X_add_number = number; /* Number of littlenums. */ + expressionP->X_unsigned = 1; input_line_pointer--; /* -> char following number. */ } } @@ -707,6 +708,7 @@ mri_char_constant (expressionS *expressionP) { expressionP->X_op = O_big; expressionP->X_add_number = i; + expressionP->X_unsigned = 1; } else { @@ -1164,6 +1166,8 @@ operand (expressionS *expressionP, enum expr_mode mode) if (generic_bignum[i]) break; } + + expressionP->X_unsigned = 0; } else if (op == O_logical_not) { diff --git a/gas/expr.h b/gas/expr.h index 14787c41343..2be3d69683c 100644 --- a/gas/expr.h +++ b/gas/expr.h @@ -131,10 +131,12 @@ typedef struct expressionS unsigned char X_op; #endif - /* Non-zero if X_add_number should be regarded as unsigned. This is - only valid for O_constant expressions. It is only used when an - O_constant must be extended into a bignum (i.e., it is not used - when performing arithmetic on these values). + /* Non-zero if the expression value should be regarded as unsigned. This is + only valid for + - O_constant expressions, where it is only used when an O_constant must be + extended into a bignum (i.e., it is not used when performing arithmetic + on these values), + - O_big integer expressions, i.e. when X_add_number is positive. FIXME: This field is not set very reliably. */ unsigned int X_unsigned : 1; /* This is used to implement "word size + 1 bit" arithmetic, so that e.g. diff --git a/gas/read.c b/gas/read.c index c9cbd224a7d..1b483d683d5 100644 --- a/gas/read.c +++ b/gas/read.c @@ -1458,6 +1458,7 @@ convert_to_bignum (expressionS *exp, int sign) generic_bignum[i++] = sign ? LITTLENUM_MASK : 0; exp->X_op = O_big; exp->X_add_number = i; + exp->X_unsigned = !sign; } /* For most MRI pseudo-ops, the line actually ends at the first @@ -4651,8 +4652,8 @@ emit_expr_with_reloc (expressionS *exp, pass to md_number_to_chars, handle it as a bignum. */ if (op == O_constant && nbytes > sizeof (valueT)) { - extra_digit = exp->X_unsigned ? 0 : -1; - convert_to_bignum (exp, !exp->X_unsigned); + extra_digit = exp->X_unsigned ? 0 : -exp->X_extrabit; + convert_to_bignum (exp, -extra_digit); op = O_big; } @@ -5371,12 +5372,14 @@ emit_leb128_expr (expressionS *exp, int sign) } else if (op == O_constant && sign - && (exp->X_add_number < 0) == !exp->X_extrabit) + && (exp->X_unsigned + ? exp->X_add_number < 0 + : (exp->X_add_number < 0) != exp->X_extrabit)) { /* We're outputting a signed leb128 and the sign of X_add_number doesn't reflect the sign of the original value. Convert EXP to a correctly-extended bignum instead. */ - convert_to_bignum (exp, exp->X_extrabit); + convert_to_bignum (exp, !exp->X_unsigned && exp->X_extrabit); op = O_big; } diff --git a/gas/testsuite/gas/all/octa.d b/gas/testsuite/gas/all/octa.d index e8eff2ce828..9c9120605d7 100644 --- a/gas/testsuite/gas/all/octa.d +++ b/gas/testsuite/gas/all/octa.d @@ -14,3 +14,11 @@ Contents of section .data: [^ ]* (00000000 ffffffff ffffffff ffffffff|ffffffff ffffffff ffffffff 00000000) .* [^ ]* (00000080 ffffffff ffffffff ffffffff|ffffffff ffffffff ffffffff 80000000) .* [^ ]* (01000000 ffffffff ffffffff ffffffff|ffffffff ffffffff ffffffff 00000001) .* + [^ ]* (00000000 000000f0 ffffffff ffffffff|ffffffff ffffffff f0000000 00000000) .* + [^ ]* (00000000 00000010 00000000 00000000|00000000 00000000 10000000 00000000) .* + [^ ]* (ffffffff ffffffef ffffffff ffffffff|ffffffff ffffffff efffffff ffffffff) .* + [^ ]* (01000000 00000010 00000000 00000000|00000000 00000000 10000000 00000001) .* + [^ ]* (01000000 000000f0 ffffffff ffffffff|ffffffff ffffffff f0000000 00000001) .* + [^ ]* (feffffff ffffff0f 00000000 00000000|00000000 00000000 0fffffff fffffffe) .* + [^ ]* (02000000 000000f0 ffffffff ffffffff|ffffffff ffffffff f0000000 00000002) .* + [^ ]* (fdffffff ffffff0f 00000000 00000000|00000000 00000000 0fffffff fffffffd) .* diff --git a/gas/testsuite/gas/all/octa.s b/gas/testsuite/gas/all/octa.s index faa21fa7ba0..037941f2e6d 100644 --- a/gas/testsuite/gas/all/octa.s +++ b/gas/testsuite/gas/all/octa.s @@ -9,3 +9,13 @@ .octa ~0xffffffff .octa 0 - 0x80000000 .octa 0 - 0xffffffff + + .octa ~0xfffffffffffffff + .octa -~0xfffffffffffffff + .octa ~-~0xfffffffffffffff + .octa -~-~0xfffffffffffffff + + .octa -0xfffffffffffffff + .octa ~-0xfffffffffffffff + .octa -~-0xfffffffffffffff + .octa ~-~-0xfffffffffffffff