aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-i386.c
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2021-06-07 08:49:33 +0200
committerJan Beulich <jbeulich@suse.com>2021-06-07 08:49:33 +0200
commita442cac5084e97d47223bac61cfc4d168c568ba4 (patch)
treea4c81ccccf7d2bb5a3582d462dfc063f0585a642 /gas/config/tc-i386.c
parent6bee34a1dc94dcfbf84b6318a731e6b059b39977 (diff)
downloadgdb-a442cac5084e97d47223bac61cfc4d168c568ba4.zip
gdb-a442cac5084e97d47223bac61cfc4d168c568ba4.tar.gz
gdb-a442cac5084e97d47223bac61cfc4d168c568ba4.tar.bz2
ix86: wrap constants
Non-64-bit code should get handled the same with or without BFD64. This wasn't the case though in a number of situations (and quite likely there are more that I haven't spotted yet). It's not very nice to tie the check in md_apply_fix() to object_64bit, but afaict at that time we have no record anymore of the mode an insn was assembled in (it might also have been data). This doesn't look to be the first inconsistency of this kind, though. In x86_cons() it's even less clear what the right approach would be: flag_code shouldn't matter for data emission, but instead we'd need to know from which mode(s) the data actually gets accessed. On this basis, signed_cons() also gets adjusted.
Diffstat (limited to 'gas/config/tc-i386.c')
-rw-r--r--gas/config/tc-i386.c34
1 files changed, 28 insertions, 6 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index d344198..a6bc597 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -2457,6 +2457,19 @@ fits_in_unsigned_long (addressT num ATTRIBUTE_UNUSED)
#endif
} /* fits_in_unsigned_long() */
+static INLINE valueT extend_to_32bit_address (addressT num)
+{
+#ifdef BFD64
+ if (fits_in_unsigned_long(num))
+ return (num ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31);
+
+ if (!fits_in_signed_long (num))
+ return num & 0xffffffff;
+#endif
+
+ return num;
+}
+
static INLINE int
fits_in_disp8 (offsetT num)
{
@@ -10457,13 +10470,17 @@ x86_cons (expressionS *exp, int size)
if (intel_syntax)
i386_intel_simplify (exp);
+ /* If not 64bit, massage value, to account for wraparound when !BFD64. */
+ if (size == 4 && exp->X_op == O_constant && !object_64bit)
+ exp->X_add_number = extend_to_32bit_address (exp->X_add_number);
+
return got_reloc;
}
static void
signed_cons (int size)
{
- if (flag_code == CODE_64BIT)
+ if (object_64bit)
cons_sign = 1;
cons (size);
cons_sign = -1;
@@ -10718,11 +10735,11 @@ i386_finalize_immediate (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp,
{
/* Size it properly later. */
i.types[this_operand].bitfield.imm64 = 1;
- /* If not 64bit, sign extend val. */
- if (flag_code != CODE_64BIT
- && (exp->X_add_number & ~(((addressT) 2 << 31) - 1)) == 0)
- exp->X_add_number
- = (exp->X_add_number ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31);
+
+ /* If not 64bit, sign/zero extend val, to account for wraparound
+ when !BFD64. */
+ if (flag_code != CODE_64BIT)
+ exp->X_add_number = extend_to_32bit_address (exp->X_add_number);
}
#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
else if (OUTPUT_FLAVOR == bfd_target_aout_flavour
@@ -12640,6 +12657,11 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
break;
}
#endif /* defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) */
+
+ /* If not 64bit, massage value, to account for wraparound when !BFD64. */
+ if (!object_64bit)
+ value = extend_to_32bit_address (value);
+
*valP = value;
#endif /* !defined (TE_Mach) */