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

via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 30 21:02:01 PDT 2023


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

>From f612b23990d64be2d0c6af98bc56c5e0c1c8566c 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  | 31 +++++++++++++++++++
 3 files changed, 55 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..94a170ec298508e
--- /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(_start == 0x8000000, "Error: _start 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..1aeffd629f6f374
--- /dev/null
+++ b/bolt/test/AArch64/long-jmp-offset-boundary.s
@@ -0,0 +1,31 @@
+# This test checks long call negative offset boundary(0x8000000) for aarch64.
+
+# REQUIRES: system-linux
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
+# RUN:   %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.exe -nostartfiles -fuse-ld=lld -Wl,-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 -j .text --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: [[#%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	_start
+	.type	_start, at function
+_start:
+	bl	foo
+	ret
+	.size	_start, .-_start



More information about the llvm-commits mailing list