diff --git a/bolt/lib/Passes/LongJmp.cpp b/bolt/lib/Passes/LongJmp.cpp index 31bb8000dda00..6f4d1170dbe2a 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 0000000000000..94a170ec29850 --- /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 0000000000000..1aeffd629f6f3 --- /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]] + + .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