This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH][Binutils][Arm] gas: fix out of range conditional branch (PR/24991)
- From: Tamar Christina <Tamar dot Christina at arm dot com>
- To: "binutils at sourceware dot org" <binutils at sourceware dot org>
- Cc: nd <nd at arm dot com>, Richard Earnshaw <Richard dot Earnshaw at arm dot com>, "nickc at redhat dot com" <nickc at redhat dot com>, Ramana Radhakrishnan <Ramana dot Radhakrishnan at arm dot com>
- Date: Thu, 19 Sep 2019 13:00:02 +0000
- Subject: [PATCH][Binutils][Arm] gas: fix out of range conditional branch (PR/24991)
- Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none
- Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=hbVOZ7fTlowrnVLK+TkHBvZWldR2wHdAcHOFVr0CmLw=; b=ZElYKEWQbEgwGOyNqYoMEP0gqK+KtkawO6PDT/uUXD8fVovlm7VtZinpeliGgQvANNcAuRAQY6pURWwvt3C0JolQ3f15glaNoZr3/OmKlG7ezApnsi/u3jHBJmeaYLNEW9CtJ74HEaeU3Zl5wNNjQ0FlaA/g3jAP67bYZHHc4Nwql1kh5gf9tBhUycuUuzvvoPmWxuYSF3i60EciEaQ6hB3f6bNgZf4L+trERUN/j5c/swOBJEnJ7axDzieHK3bjhSFueC1eC9Rl0PnV/wabcIbnqvt97S5mIiWIRaT8ZBqMd4eRgms8B3lIeaV6GZH/c0F7HH4mYLJK6TOFzoUlWQ==
- Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=CKZILiP66llN+hNYLTygwCtEGCL6mNyUISG7gDv6xxkcaXSw4u1jnpYS0U6VTyd66qhAAVeA523VObCCl4aVzeIt+9PLUPMzbznlzSn19YJRdr+XAEyPgnnpRkEtZHt+Spq5BHcoInWyPzVOzVcbI6+CE54mTanYoth58gyv/e3j9PHSDr4aIkwyh8R/7veC1CS2MxEo+dALOkkZyKINSvGb8Dw4dHpm+cfKTKwqwCWwheySqZkwcGTLz1+Tvi9duJlPPY5zPEL4Vs65iDh0RMAYtwIjYkOWqG9cMHHQC2WXMFwB54xiyf/xflgbeLL4MHO1Sbqud62ZNw4ehF/nxw==
- Original-authentication-results: spf=none (sender IP is ) smtp.mailfrom=Tamar dot Christina at arm dot com;
Hi All,
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.
build on native hardware and regtested on
arm-none-elf, arm-none-elf (32 bit host),
arm-none-linux-gnueabihf, arm-none-linux-gnueabihf (32 bit host)
Cross-compiled and regtested on
arm-none-linux-gnueabihf, armeb-none-elf, arm-wince-pe
and no issues.
Ok for master?
Thanks,
Tamar
gas/ChangeLog:
2019-09-19 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.
--
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 32a15f65ec852bae54184ab29447f17ab84d8fec..ee91c4627596a8895c306b5ac64b60d12774bc99 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -106,6 +106,14 @@ 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, bfd_vma bits)
+{
+ return (value & ~((1 << bits)-1))
+ && ((value & ~((1 << bits)-1)) != ~((1 << bits)-1));
+}
+
#ifndef FPU_DEFAULT
# ifdef TE_LINUX
# define FPU_DEFAULT FPU_ARCH_FPA
@@ -28088,7 +28096,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)
@@ -28100,7 +28108,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)
@@ -28111,6 +28119,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)
@@ -28121,7 +28130,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"));
@@ -28200,12 +28209,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"));
}
@@ -28216,7 +28224,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 0000000000000000000000000000000000000000..2acca2d656ccfa9233dcdf12a35633a642d41fbe
--- /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 0000000000000000000000000000000000000000..4fc58751c8dfd866f5dc6e361434b0210c807e85
--- /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 0000000000000000000000000000000000000000..27f8daff1c81bc31dd5630f9dcff5c664d8e845f
--- /dev/null
+++ b/gas/testsuite/gas/arm/pr24991.s
@@ -0,0 +1,5 @@
+ .arch armv7-a
+ .syntax unified
+ .thumb
+ beq .+ 0x124f80
+