Skip to content

Commit f612b23

Browse files
author
qijitao
committed
[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.
1 parent 1d0b7b6 commit f612b23

File tree

3 files changed

+55
-8
lines changed

3 files changed

+55
-8
lines changed

bolt/lib/Passes/LongJmp.cpp

+13-8
Original file line numberDiff line numberDiff line change
@@ -138,18 +138,21 @@ BinaryBasicBlock *LongJmpPass::lookupStubFromGroup(
138138
Cand = LeftCand;
139139
}
140140
int BitsAvail = BC.MIB->getPCRelEncodingSize(Inst) - 1;
141-
uint64_t Mask = ~((1ULL << BitsAvail) - 1);
141+
assert(BitsAvail < 63 && "PCRelEncodingSize is too large to use int64_t to"
142+
"check for out-of-bounds.");
143+
int64_t MaxVal = (1ULL << BitsAvail) - 1;
144+
int64_t MinVal = -(1ULL << BitsAvail);
142145
uint64_t PCRelTgtAddress = Cand->first;
143-
PCRelTgtAddress = DotAddress > PCRelTgtAddress ? DotAddress - PCRelTgtAddress
144-
: PCRelTgtAddress - DotAddress;
146+
int64_t PCOffset = (int64_t)(PCRelTgtAddress - DotAddress);
147+
145148
LLVM_DEBUG({
146149
if (Candidates.size() > 1)
147150
dbgs() << "Considering stub group with " << Candidates.size()
148151
<< " candidates. DotAddress is " << Twine::utohexstr(DotAddress)
149152
<< ", chosen candidate address is "
150153
<< Twine::utohexstr(Cand->first) << "\n";
151154
});
152-
return PCRelTgtAddress & Mask ? nullptr : Cand->second;
155+
return (PCOffset < MinVal || PCOffset > MaxVal) ? nullptr : Cand->second;
153156
}
154157

155158
BinaryBasicBlock *
@@ -512,13 +515,15 @@ bool LongJmpPass::needsStub(const BinaryBasicBlock &BB, const MCInst &Inst,
512515
}
513516

514517
int BitsAvail = BC.MIB->getPCRelEncodingSize(Inst) - 1;
515-
uint64_t Mask = ~((1ULL << BitsAvail) - 1);
518+
assert(BitsAvail < 63 && "PCRelEncodingSize is too large to use int64_t to"
519+
"check for out-of-bounds.");
520+
int64_t MaxVal = (1ULL << BitsAvail) - 1;
521+
int64_t MinVal = -(1ULL << BitsAvail);
516522

517523
uint64_t PCRelTgtAddress = getSymbolAddress(BC, TgtSym, TgtBB);
518-
PCRelTgtAddress = DotAddress > PCRelTgtAddress ? DotAddress - PCRelTgtAddress
519-
: PCRelTgtAddress - DotAddress;
524+
int64_t PCOffset = (int64_t)(PCRelTgtAddress - DotAddress);
520525

521-
return PCRelTgtAddress & Mask;
526+
return PCOffset < MinVal || PCOffset > MaxVal;
522527
}
523528

524529
bool LongJmpPass::relax(BinaryFunction &Func) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
SECTIONS {
2+
. = 0;
3+
. = ALIGN(0x400000);
4+
.text : {
5+
*(foo_section)
6+
. += 0x7BFFFFC;
7+
*(main_section)
8+
ASSERT(foo == 0x400000, "Error: foo address is not 0x400000.");
9+
ASSERT(_start == 0x8000000, "Error: _start address is not 0x8000000.");
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# This test checks long call negative offset boundary(0x8000000) for aarch64.
2+
3+
# REQUIRES: system-linux
4+
5+
# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
6+
# RUN: %s -o %t.o
7+
# RUN: %clang %cflags %t.o -o %t.exe -nostartfiles -fuse-ld=lld -Wl,-q \
8+
# RUN: -Wl,--script=%p/Inputs/long-jmp-offset-boundary.ld
9+
# RUN: llvm-bolt %t.exe -o %t.bolt.exe -skip-funcs="foo.*"
10+
# RUN: llvm-objdump -d -j .text --print-imm-hex %t.bolt.exe | FileCheck %s
11+
12+
# The default alignment of the new program header table and the new text is
13+
# HugePageSize(2MB).
14+
# CHECK: [[#%x,ADDR:]]: [[#]] bl
15+
# CHECK-SAME: 0x[[#ADDR-0x8000000]] <foo>
16+
17+
.text
18+
.section foo_section,"ax",@progbits
19+
.globl foo
20+
.type foo,@function
21+
foo:
22+
ret
23+
.size foo, .-foo
24+
25+
.section main_section,"ax",@progbits
26+
.globl _start
27+
.type _start,@function
28+
_start:
29+
bl foo
30+
ret
31+
.size _start, .-_start

0 commit comments

Comments
 (0)