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

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 25 07:04:49 PDT 2023


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

>From fc5c15f1b237f86666a45e37fedb512dcb54a959 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  | 30 +++++++++++++++++++
 3 files changed, 54 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..f7ba942a915fa9f
--- /dev/null
+++ b/bolt/test/AArch64/Inputs/long-jmp-offset-boundary.ld
@@ -0,0 +1,11 @@
+SECTIONS {
+    . = 0;
+    . = ALIGN(0x400000);
+    .text : {
+        *(foo_section)
+        . += 0x7BFFFFC;
+        *(main_section)
+        ASSERT(foo == 0x400000, "Error: foo address is not 0x400000.");
+        ASSERT(main == 0x8000000, "Error: main address is not 0x8000000.");
+    }
+}
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..f68b6156f83c69b
--- /dev/null
+++ b/bolt/test/AArch64/long-jmp-offset-boundary.s
@@ -0,0 +1,30 @@
+# This test checks long call negative offset boundary(0x8000000) for aarch64.
+
+# REQUIRES: system-linux
+
+# RUN: %clang %cflags %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 --print-imm-hex %t.bolt.exe | FileCheck %s
+
+# The default alignment of the new program header table and the new text is
+# HugePageSize(2MB). Check the second bl <foo> instruction.
+# CHECK: {{.*}}bl{{.*}}<foo>
+# CHECK: [[#%x,ADDR:]]: [[#]]     	bl
+# CHECK-SAME: 0x[[#ADDR-0x8000000]] <foo>
+
+	.text
+	.section	foo_section,"ax", at progbits
+	.globl	foo
+	.type	foo, at function
+foo:
+	ret
+	.size	foo, .-foo
+
+	.section	main_section,"ax", at progbits
+	.globl	main
+	.type	main, at function
+main:
+	bl	foo
+	ret
+	.size	main, .-main



More information about the llvm-commits mailing list