Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[llvm][ARM] Add Addend Checks for MOVT and MOVW instructions. #111970

Merged
merged 6 commits into from
Oct 14, 2024

Conversation

Stylie777
Copy link
Contributor

Previously, any value could be used for the MOVT and MOVW instructions, however the ARM ABI dictates that the addend should be a signed 16 bit value. To ensure this is followed, the Assembler will now check that when using these instructions, the addend is a 16bit signed value, and throw an error if this is not the case.

@llvmbot llvmbot added backend:ARM mc Machine (object) code labels Oct 11, 2024
@llvmbot
Copy link
Member

llvmbot commented Oct 11, 2024

@llvm/pr-subscribers-backend-arm

Author: Jack Styles (Stylie777)

Changes

Previously, any value could be used for the MOVT and MOVW instructions, however the ARM ABI dictates that the addend should be a signed 16 bit value. To ensure this is followed, the Assembler will now check that when using these instructions, the addend is a 16bit signed value, and throw an error if this is not the case.


Full diff: https://github.com/llvm/llvm-project/pull/111970.diff

7 Files Affected:

  • (modified) llvm/docs/ReleaseNotes.md (+5)
  • (modified) llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp (+11)
  • (modified) llvm/test/MC/ARM/Windows/mov32t-range.s (+3-3)
  • (added) llvm/test/MC/ARM/arm-movt-movw-range-fail.s (+13)
  • (added) llvm/test/MC/ARM/arm-movt-movw-range-pass.s (+13)
  • (modified) llvm/test/MC/ARM/macho-movwt.s (+8-8)
  • (modified) llvm/test/MC/MachO/ARM/thumb2-movw-fixup.s (+5-5)
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 8ac5900a7e532e..e5b1e1a37a1b91 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -123,6 +123,11 @@ Changes to the ARM Backend
   the required alignment space with a sequence of `0x0` bytes (the requested
   fill value) rather than NOPs.
 
+* When using the `MOVT` or `MOVW` instructions, the Assembler will now check to
+  ensure that any addend that is used is within a 16bit Signed value range. If the
+  addend falls outside of this range, the LLVM backend will emit an error like so
+  `Relocation Not In Range`.
+
 Changes to the AVR Backend
 --------------------------
 
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
index 1223210a76f6e3..4d643d001d7541 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
@@ -34,6 +34,7 @@
 #include "llvm/Support/EndianStream.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Format.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace llvm;
 
@@ -446,6 +447,16 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
                                          const MCSubtargetInfo* STI) const {
   unsigned Kind = Fixup.getKind();
 
+  // For MOVW/MOVT Instructions, the Fixup Value needs to be 16 bit aligned.
+  // If this is not the case, we should reject compilation.
+  if((Kind == ARM::fixup_arm_movw_lo16 || Kind == ARM::fixup_arm_movt_hi16 ||
+      Kind == ARM::fixup_t2_movw_lo16 || Kind == ARM::fixup_t2_movt_hi16) &&
+      (!(minIntN(16) <= static_cast<int64_t>(Value) &&
+    static_cast<int64_t>(Value) <= maxIntN(16)))) {
+    Ctx.reportError(Fixup.getLoc(), "Relocation Not In Range");
+    return 0;
+  }
+
   // MachO tries to make .o files that look vaguely pre-linked, so for MOVW/MOVT
   // and .word relocations they put the Thumb bit into the addend if possible.
   // Other relocation types don't want this bit though (branches couldn't encode
diff --git a/llvm/test/MC/ARM/Windows/mov32t-range.s b/llvm/test/MC/ARM/Windows/mov32t-range.s
index 7e16105cddc6f3..386893a078de40 100644
--- a/llvm/test/MC/ARM/Windows/mov32t-range.s
+++ b/llvm/test/MC/ARM/Windows/mov32t-range.s
@@ -21,7 +21,7 @@ truncation:
 
 	.section .rdata,"rd"
 .Lbuffer:
-	.zero 65536
+	.zero 32767
 .Lerange:
 	.asciz "-erange"
 
@@ -32,6 +32,6 @@ truncation:
 @ CHECK-RELOCATIONS:   }
 @ CHECK-RELOCATIONS: ]
 
-@ CHECK-ENCODING:      0: f240 0000
-@ CHECK-ENCODING-NEXT: 4: f2c0 0001
+@ CHECK-ENCODING:      0: f647 70ff
+@ CHECK-ENCODING-NEXT: 4: f2c0 0000
 
diff --git a/llvm/test/MC/ARM/arm-movt-movw-range-fail.s b/llvm/test/MC/ARM/arm-movt-movw-range-fail.s
new file mode 100644
index 00000000000000..2961b9bfcb64d2
--- /dev/null
+++ b/llvm/test/MC/ARM/arm-movt-movw-range-fail.s
@@ -0,0 +1,13 @@
+@RUN: not llvm-mc -triple armv7-eabi -filetype obj -o - %s 2>&1 | FileCheck %s
+
+    .global v
+    .text
+    movw    r1, #:lower16:v + -65536
+    movt    r1, #:upper16:v + 65536
+
+@CHECK: error: Relocation Not In Range
+@CHECK: movw    r1, #:lower16:v + -65536
+@CHECK: ^
+@CHECK: error: Relocation Not In Range
+@CHECK: movt    r1, #:upper16:v + 65536
+@CHECK: ^
diff --git a/llvm/test/MC/ARM/arm-movt-movw-range-pass.s b/llvm/test/MC/ARM/arm-movt-movw-range-pass.s
new file mode 100644
index 00000000000000..41f19565a46c4a
--- /dev/null
+++ b/llvm/test/MC/ARM/arm-movt-movw-range-pass.s
@@ -0,0 +1,13 @@
+@RUN: llvm-mc -triple armv7-eabi -filetype obj -o - %s 2>&1 | FileCheck %s
+
+    .global v
+    .text
+    movw    r1, #:lower16:v + -20000
+    movt    r1, #:upper16:v + 20000
+
+@CHECK-NOT: error: Relocation Not In Range
+@CHECK-NOT: movw    r1, #:lower16:v + -20000
+@CHECK-NOT: ^
+@CHECK-NOT: error: Relocation Not In Range
+@CHECK-NOT: movt    r1, #:upper16:v + 20000
+@CHECK-NOT: ^
diff --git a/llvm/test/MC/ARM/macho-movwt.s b/llvm/test/MC/ARM/macho-movwt.s
index 6f067cd86dc15d..b2c0587ca7fe59 100644
--- a/llvm/test/MC/ARM/macho-movwt.s
+++ b/llvm/test/MC/ARM/macho-movwt.s
@@ -8,8 +8,8 @@
         movw r0, :lower16:_x+4
         movt r0, :upper16:_x+4
 
-        movw r0, :lower16:_x+0x10000
-        movt r0, :upper16:_x+0x10000
+        movw r0, :lower16:_x+0x1000
+        movt r0, :upper16:_x+0x1000
 
         .arm
         movw r0, :lower16:_x
@@ -18,8 +18,8 @@
         movw r0, :lower16:_x+4
         movt r0, :upper16:_x+4
 
-        movw r0, :lower16:_x+0x10000
-        movt r0, :upper16:_x+0x10000
+        movw r0, :lower16:_x+0x1000
+        movt r0, :upper16:_x+0x1000
 
 @ Enter the bizarre world of MachO relocations. First, they're in reverse order
 @ to the actual instructions
@@ -30,10 +30,10 @@
 @ Third column identifies ARM/Thumb & HI/LO.
 
 @ CHECK: 0x2C 0 1 1 ARM_RELOC_HALF 0 _x
-@ CHECK: 0x0 0 1 0 ARM_RELOC_PAIR 0 -
+@ CHECK: 0x1000 0 1 0 ARM_RELOC_PAIR 0 -
 
 @ CHECK: 0x28 0 0 1 ARM_RELOC_HALF 0 _x
-@ CHECK: 0x1 0 0 0 ARM_RELOC_PAIR 0 -
+@ CHECK: 0x0 0 0 0 ARM_RELOC_PAIR 0 -
 
 @ CHECK: 0x24 0 1 1 ARM_RELOC_HALF 0 _x
 @ CHECK: 0x4 0 1 0 ARM_RELOC_PAIR 0 -
@@ -48,10 +48,10 @@
 @ CHECK: 0x0 0 0 0 ARM_RELOC_PAIR 0 -
 
 @ CHECK: 0x14 0 3 1 ARM_RELOC_HALF 0 _x
-@ CHECK: 0x0 0 3 0 ARM_RELOC_PAIR 0 -
+@ CHECK: 0x1000 0 3 0 ARM_RELOC_PAIR 0 -
 
 @ CHECK: 0x10 0 2 1 ARM_RELOC_HALF 0 _x
-@ CHECK: 0x1 0 2 0 ARM_RELOC_PAIR 0 -
+@ CHECK: 0x0 0 2 0 ARM_RELOC_PAIR 0 -
 
 @ CHECK: 0xC 0 3 1 ARM_RELOC_HALF 0 _x
 @ CHECK: 0x4 0 3 0 ARM_RELOC_PAIR 0 -
diff --git a/llvm/test/MC/MachO/ARM/thumb2-movw-fixup.s b/llvm/test/MC/MachO/ARM/thumb2-movw-fixup.s
index 18182d1affb063..0d6f38325b1d3c 100644
--- a/llvm/test/MC/MachO/ARM/thumb2-movw-fixup.s
+++ b/llvm/test/MC/MachO/ARM/thumb2-movw-fixup.s
@@ -11,7 +11,7 @@
 	movt	r2, :upper16:L1
   movw	r12, :lower16:L2
 	movt	r12, :upper16:L2
-  .space 70000
+  .space 16382
   
   .data
 L1: .long 0
@@ -30,7 +30,7 @@ L2: .long 0
 @ CHECK:       Section: __data (2)
 @ CHECK:     }
 @ CHECK:     Relocation {
-@ CHECK:       Offset: 0x1184
+@ CHECK:       Offset: 0x4012
 @ CHECK:       PCRel: 0
 @ CHECK:       Length: 3
 @ CHECK:       Type: ARM_RELOC_PAIR (1)
@@ -44,7 +44,7 @@ L2: .long 0
 @ CHECK:       Section: __data (2)
 @ CHECK:     }
 @ CHECK:     Relocation {
-@ CHECK:       Offset: 0x1
+@ CHECK:       Offset: 0x0
 @ CHECK:       PCRel: 0
 @ CHECK:       Length: 2
 @ CHECK:       Type: ARM_RELOC_PAIR (1)
@@ -58,7 +58,7 @@ L2: .long 0
 @ CHECK:       Section: __data (2)
 @ CHECK:     }
 @ CHECK:     Relocation {
-@ CHECK:       Offset: 0x1180
+@ CHECK:       Offset: 0x400E
 @ CHECK:       PCRel: 0
 @ CHECK:       Length: 3
 @ CHECK:       Type: ARM_RELOC_PAIR (1)
@@ -72,7 +72,7 @@ L2: .long 0
 @ CHECK:       Section: __data (2)
 @ CHECK:     }
 @ CHECK:     Relocation {
-@ CHECK:       Offset: 0x1
+@ CHECK:       Offset: 0x0
 @ CHECK:       PCRel: 0
 @ CHECK:       Length: 2
 @ CHECK:       Type: ARM_RELOC_PAIR (1)

@llvmbot
Copy link
Member

llvmbot commented Oct 11, 2024

@llvm/pr-subscribers-mc

Author: Jack Styles (Stylie777)

Changes

Previously, any value could be used for the MOVT and MOVW instructions, however the ARM ABI dictates that the addend should be a signed 16 bit value. To ensure this is followed, the Assembler will now check that when using these instructions, the addend is a 16bit signed value, and throw an error if this is not the case.


Full diff: https://github.com/llvm/llvm-project/pull/111970.diff

7 Files Affected:

  • (modified) llvm/docs/ReleaseNotes.md (+5)
  • (modified) llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp (+11)
  • (modified) llvm/test/MC/ARM/Windows/mov32t-range.s (+3-3)
  • (added) llvm/test/MC/ARM/arm-movt-movw-range-fail.s (+13)
  • (added) llvm/test/MC/ARM/arm-movt-movw-range-pass.s (+13)
  • (modified) llvm/test/MC/ARM/macho-movwt.s (+8-8)
  • (modified) llvm/test/MC/MachO/ARM/thumb2-movw-fixup.s (+5-5)
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 8ac5900a7e532e..e5b1e1a37a1b91 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -123,6 +123,11 @@ Changes to the ARM Backend
   the required alignment space with a sequence of `0x0` bytes (the requested
   fill value) rather than NOPs.
 
+* When using the `MOVT` or `MOVW` instructions, the Assembler will now check to
+  ensure that any addend that is used is within a 16bit Signed value range. If the
+  addend falls outside of this range, the LLVM backend will emit an error like so
+  `Relocation Not In Range`.
+
 Changes to the AVR Backend
 --------------------------
 
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
index 1223210a76f6e3..4d643d001d7541 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
@@ -34,6 +34,7 @@
 #include "llvm/Support/EndianStream.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Format.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace llvm;
 
@@ -446,6 +447,16 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
                                          const MCSubtargetInfo* STI) const {
   unsigned Kind = Fixup.getKind();
 
+  // For MOVW/MOVT Instructions, the Fixup Value needs to be 16 bit aligned.
+  // If this is not the case, we should reject compilation.
+  if((Kind == ARM::fixup_arm_movw_lo16 || Kind == ARM::fixup_arm_movt_hi16 ||
+      Kind == ARM::fixup_t2_movw_lo16 || Kind == ARM::fixup_t2_movt_hi16) &&
+      (!(minIntN(16) <= static_cast<int64_t>(Value) &&
+    static_cast<int64_t>(Value) <= maxIntN(16)))) {
+    Ctx.reportError(Fixup.getLoc(), "Relocation Not In Range");
+    return 0;
+  }
+
   // MachO tries to make .o files that look vaguely pre-linked, so for MOVW/MOVT
   // and .word relocations they put the Thumb bit into the addend if possible.
   // Other relocation types don't want this bit though (branches couldn't encode
diff --git a/llvm/test/MC/ARM/Windows/mov32t-range.s b/llvm/test/MC/ARM/Windows/mov32t-range.s
index 7e16105cddc6f3..386893a078de40 100644
--- a/llvm/test/MC/ARM/Windows/mov32t-range.s
+++ b/llvm/test/MC/ARM/Windows/mov32t-range.s
@@ -21,7 +21,7 @@ truncation:
 
 	.section .rdata,"rd"
 .Lbuffer:
-	.zero 65536
+	.zero 32767
 .Lerange:
 	.asciz "-erange"
 
@@ -32,6 +32,6 @@ truncation:
 @ CHECK-RELOCATIONS:   }
 @ CHECK-RELOCATIONS: ]
 
-@ CHECK-ENCODING:      0: f240 0000
-@ CHECK-ENCODING-NEXT: 4: f2c0 0001
+@ CHECK-ENCODING:      0: f647 70ff
+@ CHECK-ENCODING-NEXT: 4: f2c0 0000
 
diff --git a/llvm/test/MC/ARM/arm-movt-movw-range-fail.s b/llvm/test/MC/ARM/arm-movt-movw-range-fail.s
new file mode 100644
index 00000000000000..2961b9bfcb64d2
--- /dev/null
+++ b/llvm/test/MC/ARM/arm-movt-movw-range-fail.s
@@ -0,0 +1,13 @@
+@RUN: not llvm-mc -triple armv7-eabi -filetype obj -o - %s 2>&1 | FileCheck %s
+
+    .global v
+    .text
+    movw    r1, #:lower16:v + -65536
+    movt    r1, #:upper16:v + 65536
+
+@CHECK: error: Relocation Not In Range
+@CHECK: movw    r1, #:lower16:v + -65536
+@CHECK: ^
+@CHECK: error: Relocation Not In Range
+@CHECK: movt    r1, #:upper16:v + 65536
+@CHECK: ^
diff --git a/llvm/test/MC/ARM/arm-movt-movw-range-pass.s b/llvm/test/MC/ARM/arm-movt-movw-range-pass.s
new file mode 100644
index 00000000000000..41f19565a46c4a
--- /dev/null
+++ b/llvm/test/MC/ARM/arm-movt-movw-range-pass.s
@@ -0,0 +1,13 @@
+@RUN: llvm-mc -triple armv7-eabi -filetype obj -o - %s 2>&1 | FileCheck %s
+
+    .global v
+    .text
+    movw    r1, #:lower16:v + -20000
+    movt    r1, #:upper16:v + 20000
+
+@CHECK-NOT: error: Relocation Not In Range
+@CHECK-NOT: movw    r1, #:lower16:v + -20000
+@CHECK-NOT: ^
+@CHECK-NOT: error: Relocation Not In Range
+@CHECK-NOT: movt    r1, #:upper16:v + 20000
+@CHECK-NOT: ^
diff --git a/llvm/test/MC/ARM/macho-movwt.s b/llvm/test/MC/ARM/macho-movwt.s
index 6f067cd86dc15d..b2c0587ca7fe59 100644
--- a/llvm/test/MC/ARM/macho-movwt.s
+++ b/llvm/test/MC/ARM/macho-movwt.s
@@ -8,8 +8,8 @@
         movw r0, :lower16:_x+4
         movt r0, :upper16:_x+4
 
-        movw r0, :lower16:_x+0x10000
-        movt r0, :upper16:_x+0x10000
+        movw r0, :lower16:_x+0x1000
+        movt r0, :upper16:_x+0x1000
 
         .arm
         movw r0, :lower16:_x
@@ -18,8 +18,8 @@
         movw r0, :lower16:_x+4
         movt r0, :upper16:_x+4
 
-        movw r0, :lower16:_x+0x10000
-        movt r0, :upper16:_x+0x10000
+        movw r0, :lower16:_x+0x1000
+        movt r0, :upper16:_x+0x1000
 
 @ Enter the bizarre world of MachO relocations. First, they're in reverse order
 @ to the actual instructions
@@ -30,10 +30,10 @@
 @ Third column identifies ARM/Thumb & HI/LO.
 
 @ CHECK: 0x2C 0 1 1 ARM_RELOC_HALF 0 _x
-@ CHECK: 0x0 0 1 0 ARM_RELOC_PAIR 0 -
+@ CHECK: 0x1000 0 1 0 ARM_RELOC_PAIR 0 -
 
 @ CHECK: 0x28 0 0 1 ARM_RELOC_HALF 0 _x
-@ CHECK: 0x1 0 0 0 ARM_RELOC_PAIR 0 -
+@ CHECK: 0x0 0 0 0 ARM_RELOC_PAIR 0 -
 
 @ CHECK: 0x24 0 1 1 ARM_RELOC_HALF 0 _x
 @ CHECK: 0x4 0 1 0 ARM_RELOC_PAIR 0 -
@@ -48,10 +48,10 @@
 @ CHECK: 0x0 0 0 0 ARM_RELOC_PAIR 0 -
 
 @ CHECK: 0x14 0 3 1 ARM_RELOC_HALF 0 _x
-@ CHECK: 0x0 0 3 0 ARM_RELOC_PAIR 0 -
+@ CHECK: 0x1000 0 3 0 ARM_RELOC_PAIR 0 -
 
 @ CHECK: 0x10 0 2 1 ARM_RELOC_HALF 0 _x
-@ CHECK: 0x1 0 2 0 ARM_RELOC_PAIR 0 -
+@ CHECK: 0x0 0 2 0 ARM_RELOC_PAIR 0 -
 
 @ CHECK: 0xC 0 3 1 ARM_RELOC_HALF 0 _x
 @ CHECK: 0x4 0 3 0 ARM_RELOC_PAIR 0 -
diff --git a/llvm/test/MC/MachO/ARM/thumb2-movw-fixup.s b/llvm/test/MC/MachO/ARM/thumb2-movw-fixup.s
index 18182d1affb063..0d6f38325b1d3c 100644
--- a/llvm/test/MC/MachO/ARM/thumb2-movw-fixup.s
+++ b/llvm/test/MC/MachO/ARM/thumb2-movw-fixup.s
@@ -11,7 +11,7 @@
 	movt	r2, :upper16:L1
   movw	r12, :lower16:L2
 	movt	r12, :upper16:L2
-  .space 70000
+  .space 16382
   
   .data
 L1: .long 0
@@ -30,7 +30,7 @@ L2: .long 0
 @ CHECK:       Section: __data (2)
 @ CHECK:     }
 @ CHECK:     Relocation {
-@ CHECK:       Offset: 0x1184
+@ CHECK:       Offset: 0x4012
 @ CHECK:       PCRel: 0
 @ CHECK:       Length: 3
 @ CHECK:       Type: ARM_RELOC_PAIR (1)
@@ -44,7 +44,7 @@ L2: .long 0
 @ CHECK:       Section: __data (2)
 @ CHECK:     }
 @ CHECK:     Relocation {
-@ CHECK:       Offset: 0x1
+@ CHECK:       Offset: 0x0
 @ CHECK:       PCRel: 0
 @ CHECK:       Length: 2
 @ CHECK:       Type: ARM_RELOC_PAIR (1)
@@ -58,7 +58,7 @@ L2: .long 0
 @ CHECK:       Section: __data (2)
 @ CHECK:     }
 @ CHECK:     Relocation {
-@ CHECK:       Offset: 0x1180
+@ CHECK:       Offset: 0x400E
 @ CHECK:       PCRel: 0
 @ CHECK:       Length: 3
 @ CHECK:       Type: ARM_RELOC_PAIR (1)
@@ -72,7 +72,7 @@ L2: .long 0
 @ CHECK:       Section: __data (2)
 @ CHECK:     }
 @ CHECK:     Relocation {
-@ CHECK:       Offset: 0x1
+@ CHECK:       Offset: 0x0
 @ CHECK:       PCRel: 0
 @ CHECK:       Length: 2
 @ CHECK:       Type: ARM_RELOC_PAIR (1)

As per the ARM ABI, the MOVT and MOVW instructions should have
addends that fall within a 16bit signed range. LLVM does not check
this so it is possible to use addends that are beyond the accepted
range. These addends are silently truncated.

A new check is added to ensure the addend falls within the expected
range, rejecting an addend that falls outside with an error.

Information relating to the ABI requirements can be found here:
https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst#addends-and-pc-bias-compensation
As part of the checks, in some cases the Value is changed according
to if the Thumb bit is needed. This changes the value and can cause
the calcuation to check the range to falsely fail.

Moving the check before the Value is changed to ensure this cannot
occur.

Previously, tests existed that exploited the truncation of the
addend into a 16bit signed value, so these tests have been updated
to reflect the fact this is no longer allowed. It still tests the
instruction, but the expected outcome has been updated with new
values.
@Stylie777 Stylie777 force-pushed the clang_addend_checks_movt_movw branch from 29f5126 to 81eec5f Compare October 11, 2024 09:31
Copy link

github-actions bot commented Oct 11, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@@ -125,6 +125,11 @@ Changes to the ARM Backend
the required alignment space with a sequence of `0x0` bytes (the requested
fill value) rather than NOPs.

* When using the `MOVT` or `MOVW` instructions, the Assembler will now check to
ensure that any addend that is used is within a 16bit Signed value range. If the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"16-bit signed value range"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

@@ -446,6 +447,16 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
const MCSubtargetInfo* STI) const {
unsigned Kind = Fixup.getKind();

// For MOVW/MOVT Instructions, the Fixup Value needs to be 16 bit aligned.
// If this is not the case, we should reject compilation.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second sentence seems redundant especially if you rephrase the first to:

// For MOVW/MOVT instructions, the fixup value must already be be 16-bit aligned.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the comment as per your suggestion

if((Kind == ARM::fixup_arm_movw_lo16 || Kind == ARM::fixup_arm_movt_hi16 ||
Kind == ARM::fixup_t2_movw_lo16 || Kind == ARM::fixup_t2_movt_hi16) &&
(!(minIntN(16) <= static_cast<int64_t>(Value) &&
static_cast<int64_t>(Value) <= maxIntN(16)))) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition could do with re-ordering. Put the fixup value first each time and remove the need for !. This if is "if something produce an error", so write it in terms of when you will error not when you won't.

&& (static_cast<int64_t>(Value) < minIntN(16) || static_cast<int64_t>(Value) > maxIntN(16))

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day we'll be able to do Python's x < y < z 🦄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I long for the day. I have updated with your suggestion so it reads better.

@DavidSpickett
Copy link
Collaborator

[llvm][ARM] tags at the start of the PR title please :)

@Stylie777 Stylie777 changed the title Add Addend Checks for MOVT and MOVW instructions. [llvm][ARM] Add Addend Checks for MOVT and MOVW instructions. Oct 11, 2024
@Stylie777 Stylie777 self-assigned this Oct 11, 2024
@Stylie777
Copy link
Contributor Author

Thanks for the comments @DavidSpickett, I have responded and updated the PR name.

Copy link
Collaborator

@DavidSpickett DavidSpickett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@jthackray jthackray self-requested a review October 14, 2024 08:49
Copy link
Contributor

@jthackray jthackray left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good stuff :)

@Stylie777 Stylie777 merged commit f3aebe6 into llvm:main Oct 14, 2024
9 checks passed
@mstorsjo
Copy link
Member

This breaks code generation for Windows/ARM - we hit the Relocation Not In Range when compiling regular C/C++ code.

This is reproducible with https://martin.st/temp/outofrange.cpp, like this:

$ clang -target armv7-w64-mingw32 outofrange.cpp -O3 -c
error: Relocation Not In Range
error: Relocation Not In Range
2 errors generated.

When looking at the output of the same compilation like this:

$ clang -target armv7-w64-mingw32 outofrange.cpp -O3 -S -o - | grep -E 'upper16|lower16'

There's no single case of a lower16/upper16 relocation that has any offset at all - yet compilation fails.

Please revert while figuring out what's going wrong here.

Stylie777 added a commit to Stylie777/llvm-project that referenced this pull request Oct 14, 2024
Stylie777 added a commit that referenced this pull request Oct 14, 2024
#112184)

… (#111970)"

I was made aware of breakages in Windows/ARM, so reverting while I
investigate.

This reverts commit f3aebe6.
@Stylie777
Copy link
Contributor Author

#112184 Revert has been merged due to breakages seen in Windows/ARM. I will investigate and recommit when I have found the issue.

@Stylie777
Copy link
Contributor Author

Stylie777 commented Oct 14, 2024 via email

@mstorsjo
Copy link
Member

Thanks for the prompt response!

DanielCChen pushed a commit to DanielCChen/llvm-project that referenced this pull request Oct 16, 2024
…11970)

Previously, any value could be used for the MOVT and MOVW instructions,
however the ARM ABI dictates that the addend should be a signed 16 bit
value. To ensure this is followed, the Assembler will now check that
when using these instructions, the addend is a 16bit signed value, and
throw an error if this is not the case.

Information relating to the ABI requirements can be found here:
https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst#addends-and-pc-bias-compensation
DanielCChen pushed a commit to DanielCChen/llvm-project that referenced this pull request Oct 16, 2024
llvm#112184)

… (llvm#111970)"

I was made aware of breakages in Windows/ARM, so reverting while I
investigate.

This reverts commit f3aebe6.
bricknerb pushed a commit to bricknerb/llvm-project that referenced this pull request Oct 17, 2024
…11970)

Previously, any value could be used for the MOVT and MOVW instructions,
however the ARM ABI dictates that the addend should be a signed 16 bit
value. To ensure this is followed, the Assembler will now check that
when using these instructions, the addend is a 16bit signed value, and
throw an error if this is not the case.

Information relating to the ABI requirements can be found here:
https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst#addends-and-pc-bias-compensation
bricknerb pushed a commit to bricknerb/llvm-project that referenced this pull request Oct 17, 2024
llvm#112184)

… (llvm#111970)"

I was made aware of breakages in Windows/ARM, so reverting while I
investigate.

This reverts commit f3aebe6.
Stylie777 added a commit that referenced this pull request Oct 22, 2024
… (PR #111970)" (#112877)

**Change relanded after feedback on failures and improvements to the
check of the addend. Original PR #111970**
Changes from original patch:
- The value that is being checked has changed, it is now correctly
checking any Addend for the instruction, rather than the Value. The
addend is kept within the Target data structure from my investigation.
- Removed changes to the following tests due to the original behaviour
being correct, and my original patch causing unexpected errors
    - llvm/test/MC/ARM/Windows/mov32t-range.s
    - llvm/test/MC/MachO/ARM/thumb2-movw-fixup.s

As per the ARM ABI, the MOVT and MOVW instructions should have addends
that fall within a 16bit signed range. LLVM does not check this so it is
possible to use addends that are beyond the accepted range. These
addends are silently truncated.

A new check is added to ensure the addend falls within the expected
range, rejecting an addend that falls outside with an error.

Information relating to the ABI requirements can be found here:
https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst#addends-and-pc-bias-compensation
EricWF pushed a commit to efcs/llvm-project that referenced this pull request Oct 22, 2024
…11970)

Previously, any value could be used for the MOVT and MOVW instructions,
however the ARM ABI dictates that the addend should be a signed 16 bit
value. To ensure this is followed, the Assembler will now check that
when using these instructions, the addend is a 16bit signed value, and
throw an error if this is not the case.

Information relating to the ABI requirements can be found here:
https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst#addends-and-pc-bias-compensation
EricWF pushed a commit to efcs/llvm-project that referenced this pull request Oct 22, 2024
llvm#112184)

… (llvm#111970)"

I was made aware of breakages in Windows/ARM, so reverting while I
investigate.

This reverts commit f3aebe6.
EricWF pushed a commit to efcs/llvm-project that referenced this pull request Oct 22, 2024
… (PR llvm#111970)" (llvm#112877)

**Change relanded after feedback on failures and improvements to the
check of the addend. Original PR llvm#111970**
Changes from original patch:
- The value that is being checked has changed, it is now correctly
checking any Addend for the instruction, rather than the Value. The
addend is kept within the Target data structure from my investigation.
- Removed changes to the following tests due to the original behaviour
being correct, and my original patch causing unexpected errors
    - llvm/test/MC/ARM/Windows/mov32t-range.s
    - llvm/test/MC/MachO/ARM/thumb2-movw-fixup.s

As per the ARM ABI, the MOVT and MOVW instructions should have addends
that fall within a 16bit signed range. LLVM does not check this so it is
possible to use addends that are beyond the accepted range. These
addends are silently truncated.

A new check is added to ensure the addend falls within the expected
range, rejecting an addend that falls outside with an error.

Information relating to the ABI requirements can be found here:
https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst#addends-and-pc-bias-compensation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:ARM mc Machine (object) code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants