[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