[llvm] [BOLT] Fix long jump negative offset issue. (PR #67132)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 22 06:14:55 PDT 2023


https://github.com/qijitao created https://github.com/llvm/llvm-project/pull/67132

In instruction encoding, the relative offset address of the PC is signed, that is, the number of positive offset bits and the number of negative offset bits is asymmetric. Therefore, the maximum and minimum values are used to replace Mask to determine the boundary.

>From 29aaa68d04b6bc38452de38979f417d4e0a80780 Mon Sep 17 00:00:00 2001
From: qijitao <qijitao at hisilicon.com>
Date: Fri, 22 Sep 2023 16:30:27 +0800
Subject: [PATCH] [BOLT] Fix long jump negative offset issue.

In instruction encoding, the relative offset address of the PC is signed,
that is, the number of positive offset bits and the number of negative
offset bits is asymmetric. Therefore, the maximum and minimum values
are used to replace Mask to determine the boundary.
---
 bolt/lib/Passes/LongJmp.cpp                   |  21 ++--
 .../Inputs/long-jmp-offset-boundary.ld        |  11 ++
 bolt/test/AArch64/long-jmp-offset-boundary.s  | 111 ++++++++++++++++++
 3 files changed, 135 insertions(+), 8 deletions(-)
 create mode 100644 bolt/test/AArch64/Inputs/long-jmp-offset-boundary.ld
 create mode 100644 bolt/test/AArch64/long-jmp-offset-boundary.s

diff --git a/bolt/lib/Passes/LongJmp.cpp b/bolt/lib/Passes/LongJmp.cpp
index 31bb8000dda00c3..6f4d1170dbe2a4a 100644
--- a/bolt/lib/Passes/LongJmp.cpp
+++ b/bolt/lib/Passes/LongJmp.cpp
@@ -138,10 +138,13 @@ BinaryBasicBlock *LongJmpPass::lookupStubFromGroup(
       Cand = LeftCand;
   }
   int BitsAvail = BC.MIB->getPCRelEncodingSize(Inst) - 1;
-  uint64_t Mask = ~((1ULL << BitsAvail) - 1);
+  assert(BitsAvail < 63 && "PCRelEncodingSize is too large to use int64_t to"
+                           "check for out-of-bounds.");
+  int64_t MaxVal = (1ULL << BitsAvail) - 1;
+  int64_t MinVal = -(1ULL << BitsAvail);
   uint64_t PCRelTgtAddress = Cand->first;
-  PCRelTgtAddress = DotAddress > PCRelTgtAddress ? DotAddress - PCRelTgtAddress
-                                                 : PCRelTgtAddress - DotAddress;
+  int64_t PCOffset = (int64_t)(PCRelTgtAddress - DotAddress);
+
   LLVM_DEBUG({
     if (Candidates.size() > 1)
       dbgs() << "Considering stub group with " << Candidates.size()
@@ -149,7 +152,7 @@ BinaryBasicBlock *LongJmpPass::lookupStubFromGroup(
              << ", chosen candidate address is "
              << Twine::utohexstr(Cand->first) << "\n";
   });
-  return PCRelTgtAddress & Mask ? nullptr : Cand->second;
+  return (PCOffset < MinVal || PCOffset > MaxVal) ? nullptr : Cand->second;
 }
 
 BinaryBasicBlock *
@@ -512,13 +515,15 @@ bool LongJmpPass::needsStub(const BinaryBasicBlock &BB, const MCInst &Inst,
   }
 
   int BitsAvail = BC.MIB->getPCRelEncodingSize(Inst) - 1;
-  uint64_t Mask = ~((1ULL << BitsAvail) - 1);
+  assert(BitsAvail < 63 && "PCRelEncodingSize is too large to use int64_t to"
+                           "check for out-of-bounds.");
+  int64_t MaxVal = (1ULL << BitsAvail) - 1;
+  int64_t MinVal = -(1ULL << BitsAvail);
 
   uint64_t PCRelTgtAddress = getSymbolAddress(BC, TgtSym, TgtBB);
-  PCRelTgtAddress = DotAddress > PCRelTgtAddress ? DotAddress - PCRelTgtAddress
-                                                 : PCRelTgtAddress - DotAddress;
+  int64_t PCOffset = (int64_t)(PCRelTgtAddress - DotAddress);
 
-  return PCRelTgtAddress & Mask;
+  return PCOffset < MinVal || PCOffset > MaxVal;
 }
 
 bool LongJmpPass::relax(BinaryFunction &Func) {
diff --git a/bolt/test/AArch64/Inputs/long-jmp-offset-boundary.ld b/bolt/test/AArch64/Inputs/long-jmp-offset-boundary.ld
new file mode 100644
index 000000000000000..2560c6570d6ff0a
--- /dev/null
+++ b/bolt/test/AArch64/Inputs/long-jmp-offset-boundary.ld
@@ -0,0 +1,11 @@
+SECTIONS {
+    . = 0;
+    . = ALIGN(0x100);
+    .text : {
+        *(foo_section)
+        . += 0x7BFFEFC;
+        *(main_section)
+        ASSERT(foo == 0x100, "Error: foo address is not 0x100.");
+        ASSERT(main == 0x7C00000, "Error: main address is not 0x7C00000.");
+    }
+}
diff --git a/bolt/test/AArch64/long-jmp-offset-boundary.s b/bolt/test/AArch64/long-jmp-offset-boundary.s
new file mode 100644
index 000000000000000..bee61c23cd453a7
--- /dev/null
+++ b/bolt/test/AArch64/long-jmp-offset-boundary.s
@@ -0,0 +1,111 @@
+# This test checks long call negative offset boundary(0x8000000) for aarch64.
+
+# REQUIRES: system-linux
+
+# RUN: %clang %s -o %t.exe -nostartfiles -fuse-ld=lld -Wl,-z,now,-q \
+# RUN:   -Wl,--script=%p/Inputs/long-jmp-offset-boundary.ld
+# RUN: llvm-bolt %t.exe -o %t.bolt.exe -skip-funcs="foo.*"
+# RUN: llvm-objdump -d %t.bolt.exe | FileCheck %s
+# CHECK: 0000000000000100 <foo>:
+# CHECK: 8000100: {{.*}}	bl	0x100 <foo>
+
+	.text
+	.section	foo_section,"ax", at progbits
+	.globl	foo
+	.p2align	2
+	.type	foo, at function
+foo:
+	.cfi_startproc
+// %bb.0:
+	ret
+.Lfunc_end0:
+	.size	foo, .Lfunc_end0-foo
+	.cfi_endproc
+
+	.section	main_section,"ax", at progbits
+	.globl	main                            // -- Begin function main
+	.p2align	2
+	.type	main, at function
+main:
+	.cfi_startproc
+// %bb.0:
+	mov	w8, #100
+	str	w8, [sp, #8]
+	mov	w8, #200
+	str	w8, [sp, #4]
+	ldr	w0, [sp, #8]
+	ldr	w1, [sp, #4]
+
+	mov	w8, #100
+	str	w8, [sp, #8]
+	mov	w8, #200
+	str	w8, [sp, #4]
+	ldr	w0, [sp, #8]
+	ldr	w1, [sp, #4]
+
+	mov	w8, #100
+	str	w8, [sp, #8]
+	mov	w8, #200
+	str	w8, [sp, #4]
+	ldr	w0, [sp, #8]
+	ldr	w1, [sp, #4]
+
+	mov	w8, #100
+	str	w8, [sp, #8]
+	mov	w8, #200
+	str	w8, [sp, #4]
+	ldr	w0, [sp, #8]
+	ldr	w1, [sp, #4]
+
+	mov	w8, #100
+	str	w8, [sp, #8]
+	mov	w8, #200
+	str	w8, [sp, #4]
+	ldr	w0, [sp, #8]
+	ldr	w1, [sp, #4]
+
+	mov	w8, #100
+	str	w8, [sp, #8]
+	mov	w8, #200
+	str	w8, [sp, #4]
+	ldr	w0, [sp, #8]
+	ldr	w1, [sp, #4]
+
+	mov	w8, #100
+	str	w8, [sp, #8]
+	mov	w8, #200
+	str	w8, [sp, #4]
+	ldr	w0, [sp, #8]
+	ldr	w1, [sp, #4]
+
+	mov	w8, #100
+	str	w8, [sp, #8]
+	mov	w8, #200
+	str	w8, [sp, #4]
+	ldr	w0, [sp, #8]
+	ldr	w1, [sp, #4]
+
+	mov	w8, #100
+	str	w8, [sp, #8]
+	mov	w8, #200
+	str	w8, [sp, #4]
+	ldr	w0, [sp, #8]
+	ldr	w1, [sp, #4]
+
+	mov	w8, #100
+	str	w8, [sp, #8]
+	mov	w8, #200
+	str	w8, [sp, #4]
+	ldr	w0, [sp, #8]
+	ldr	w1, [sp, #4]
+
+	mov	w8, #100
+	str	w8, [sp, #8]
+	mov	w8, #200
+	str	w8, [sp, #4]
+
+	bl	foo
+	ret
+.Lfunc_end1:
+	.size	main, .Lfunc_end1-main
+	.cfi_endproc
\ No newline at end of file



More information about the llvm-commits mailing list