Skip to content

[BOLT] Fix long jump negative offset issue. #67132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions bolt/lib/Passes/LongJmp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,21 @@ 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()
<< " candidates. DotAddress is " << Twine::utohexstr(DotAddress)
<< ", chosen candidate address is "
<< Twine::utohexstr(Cand->first) << "\n";
});
return PCRelTgtAddress & Mask ? nullptr : Cand->second;
return (PCOffset < MinVal || PCOffset > MaxVal) ? nullptr : Cand->second;
}

BinaryBasicBlock *
Expand Down Expand Up @@ -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) {
Expand Down
11 changes: 11 additions & 0 deletions bolt/test/AArch64/Inputs/long-jmp-offset-boundary.ld
Original file line number Diff line number Diff line change
@@ -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.");
}
}
31 changes: 31 additions & 0 deletions bolt/test/AArch64/long-jmp-offset-boundary.s
Original file line number Diff line number Diff line change
@@ -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",@progbits
.globl foo
.type foo,@function
foo:
ret
.size foo, .-foo

.section main_section,"ax",@progbits
.globl _start
.type _start,@function
_start:
bl foo
ret
.size _start, .-_start