aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorTamar Christina <tamar.christina@arm.com>2019-09-24 14:46:17 +0100
committerTamar Christina <tamar.christina@arm.com>2019-10-14 12:29:36 +0100
commit2948a47219b2000e389faaa3df6fa5eaf330b7ff (patch)
tree2e4d48f0b07daebe4dde99ef4419c9be22be33d3 /gas
parent9676be3aa9a712697fe61a72efff923487f0c06f (diff)
downloadgdb-2948a47219b2000e389faaa3df6fa5eaf330b7ff.zip
gdb-2948a47219b2000e389faaa3df6fa5eaf330b7ff.tar.gz
gdb-2948a47219b2000e389faaa3df6fa5eaf330b7ff.tar.bz2
Arm: Fix out of range conditional branch (PR/24991)
The fix for PR12848 introduced an off by one error in the mask, this corrected the negative overflows but not the positive overflows. As a result the conditional branch instructions accepted a too wide positive immediate which resulted in it corrupting the instruction during encoding. The relocation I believe has been incorrectly named, to be consistent with the other relocations it should have been named BRANCH21 which is why the masks for it are confusing. I've replaced the masks with a function out_of_range_p which should make it harder to make such mistakes. The mask for BL/BLX on Armv6t+ is also wrong, the extended range is 25-bits and so the mask should be checking for 24-bits for positive overflow. gas/ChangeLog: PR gas/24991 * config/tc-arm.c (out_of_range_p): New. (md_apply_fix): Use it in BFD_RELOC_THUMB_PCREL_BRANCH9, BFD_RELOC_THUMB_PCREL_BRANCH12, BFD_RELOC_THUMB_PCREL_BRANCH20, BFD_RELOC_THUMB_PCREL_BRANCH23, BFD_RELOC_THUMB_PCREL_BRANCH25 * testsuite/gas/arm/pr24991.d: New test. * testsuite/gas/arm/pr24991.l: New test. * testsuite/gas/arm/pr24991.s: New test. (cherry picked from commit e8f8842d90abe5eafa8c32f08fbc3a747a45747c)
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog14
-rw-r--r--gas/config/tc-arm.c23
-rw-r--r--gas/testsuite/gas/arm/pr24991.d4
-rw-r--r--gas/testsuite/gas/arm/pr24991.l2
-rw-r--r--gas/testsuite/gas/arm/pr24991.s5
5 files changed, 41 insertions, 7 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 75324bf..0955809 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,17 @@
+2019-10-14 Tamar Christina <tamar.christina@arm.com>
+
+ Backported from mainline.
+ 2019-09-24 Tamar Christina <tamar.christina@arm.com>
+
+ PR gas/24991
+ * config/tc-arm.c (out_of_range_p): New.
+ (md_apply_fix): Use it in BFD_RELOC_THUMB_PCREL_BRANCH9,
+ BFD_RELOC_THUMB_PCREL_BRANCH12, BFD_RELOC_THUMB_PCREL_BRANCH20,
+ BFD_RELOC_THUMB_PCREL_BRANCH23, BFD_RELOC_THUMB_PCREL_BRANCH25
+ * testsuite/gas/arm/pr24991.d: New test.
+ * testsuite/gas/arm/pr24991.l: New test.
+ * testsuite/gas/arm/pr24991.s: New test.
+
2019-10-12 Nick Clifton <nickc@redhat.com>
Release 2.33.1
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 9273bb5..caabdbb 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -106,6 +106,15 @@ enum arm_float_abi
should define CPU_DEFAULT here. */
#endif
+/* Perform range checks on positive and negative overflows by checking if the
+ VALUE given fits within the range of an BITS sized immediate. */
+static bfd_boolean out_of_range_p (offsetT value, offsetT bits)
+ {
+ gas_assert (bits < (offsetT)(sizeof (value) * 8));
+ return (value & ~((1 << bits)-1))
+ && ((value & ~((1 << bits)-1)) != ~((1 << bits)-1));
+}
+
#ifndef FPU_DEFAULT
# ifdef TE_LINUX
# define FPU_DEFAULT FPU_ARCH_FPA
@@ -28047,7 +28056,7 @@ md_apply_fix (fixS * fixP,
break;
case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch. */
- if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
+ if (out_of_range_p (value, 8))
as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
if (fixP->fx_done || !seg->use_rela_p)
@@ -28059,7 +28068,7 @@ md_apply_fix (fixS * fixP,
break;
case BFD_RELOC_THUMB_PCREL_BRANCH12: /* Unconditional branch. */
- if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
+ if (out_of_range_p (value, 11))
as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
if (fixP->fx_done || !seg->use_rela_p)
@@ -28070,6 +28079,7 @@ md_apply_fix (fixS * fixP,
}
break;
+ /* This relocation is misnamed, it should be BRANCH21. */
case BFD_RELOC_THUMB_PCREL_BRANCH20:
if (fixP->fx_addsy
&& (S_GET_SEGMENT (fixP->fx_addsy) == seg)
@@ -28080,7 +28090,7 @@ md_apply_fix (fixS * fixP,
/* Force a relocation for a branch 20 bits wide. */
fixP->fx_done = 0;
}
- if ((value & ~0x1fffff) && ((value & ~0x0fffff) != ~0x0fffff))
+ if (out_of_range_p (value, 20))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("conditional branch out of range"));
@@ -28159,12 +28169,11 @@ md_apply_fix (fixS * fixP,
fixP->fx_r_type = BFD_RELOC_THUMB_PCREL_BRANCH23;
#endif
- if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
+ if (out_of_range_p (value, 22))
{
if (!(ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6t2)))
as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
- else if ((value & ~0x1ffffff)
- && ((value & ~0x1ffffff) != ~0x1ffffff))
+ else if (out_of_range_p (value, 24))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("Thumb2 branch out of range"));
}
@@ -28175,7 +28184,7 @@ md_apply_fix (fixS * fixP,
break;
case BFD_RELOC_THUMB_PCREL_BRANCH25:
- if ((value & ~0x0ffffff) && ((value & ~0x0ffffff) != ~0x0ffffff))
+ if (out_of_range_p (value, 24))
as_bad_where (fixP->fx_file, fixP->fx_line, BAD_RANGE);
if (fixP->fx_done || !seg->use_rela_p)
diff --git a/gas/testsuite/gas/arm/pr24991.d b/gas/testsuite/gas/arm/pr24991.d
new file mode 100644
index 0000000..2acca2d
--- /dev/null
+++ b/gas/testsuite/gas/arm/pr24991.d
@@ -0,0 +1,4 @@
+#as: -march=armv7-a
+#source: pr24991.s
+#error_output: pr24991.l
+
diff --git a/gas/testsuite/gas/arm/pr24991.l b/gas/testsuite/gas/arm/pr24991.l
new file mode 100644
index 0000000..4fc5875
--- /dev/null
+++ b/gas/testsuite/gas/arm/pr24991.l
@@ -0,0 +1,2 @@
+[^:]*: Assembler messages:
+[^:]*:4: Error: conditional branch out of range
diff --git a/gas/testsuite/gas/arm/pr24991.s b/gas/testsuite/gas/arm/pr24991.s
new file mode 100644
index 0000000..27f8daf
--- /dev/null
+++ b/gas/testsuite/gas/arm/pr24991.s
@@ -0,0 +1,5 @@
+ .arch armv7-a
+ .syntax unified
+ .thumb
+ beq .+ 0x124f80
+