Skip to content

Commit 7565c12

Browse files
committed
[Bolt] Solving pie support issue
Now PIE is default supported. It cause parsing error when using perf2bolt. The reason is the base address can not get correctly. Fix the method of geting base address. If SegInfo.Alignment is not equal to pagesize, alignDown(SegInfo.FileOffset, SegInfo.Alignment) can not equal to FileOffset. So the SegInfo.FileOffset and FileOffset should be aligned by SegInfo.Alignment first and then judge whether they are equal. The .text segment's offset from base address in VAS is aligned by pagesize. So MMapAddress's offset from base address is alignDown(SegInfo.Address, pagesize) instead of alignDown(SegInfo.Address, SegInfo.Alignment). So the base address calculate way should be changed.
1 parent 8569465 commit 7565c12

File tree

6 files changed

+102
-4
lines changed

6 files changed

+102
-4
lines changed

bolt/lib/Core/BinaryContext.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,10 +1924,27 @@ BinaryContext::getBaseAddressForMapping(uint64_t MMapAddress,
19241924
// Find a segment with a matching file offset.
19251925
for (auto &KV : SegmentMapInfo) {
19261926
const SegmentInfo &SegInfo = KV.second;
1927-
if (alignDown(SegInfo.FileOffset, SegInfo.Alignment) == FileOffset) {
1928-
// Use segment's aligned memory offset to calculate the base address.
1929-
const uint64_t MemOffset = alignDown(SegInfo.Address, SegInfo.Alignment);
1930-
return MMapAddress - MemOffset;
1927+
// FileOffset is got from perf event,
1928+
// and it is equal to alignDown(SegInfo.FileOffset, pagesize).
1929+
// If the pagesize is not equal to SegInfo.Alignment.
1930+
// FileOffset and SegInfo.FileOffset should be aligned first,
1931+
// and then judge whether they are equal.
1932+
if (alignDown(SegInfo.FileOffset, SegInfo.Alignment) ==
1933+
alignDown(FileOffset, SegInfo.Alignment)) {
1934+
// The function's offset from base address in VAS is aligned by pagesize
1935+
// instead of SegInfo.Alignment. Pagesize can't be got from perf events.
1936+
// However, The ELF document says that SegInfo.FileOffset should equal
1937+
// to SegInfo.Address, modulo the pagesize.
1938+
// Reference: https://refspecs.linuxfoundation.org/elf/elf.pdf
1939+
1940+
// So alignDown(SegInfo.Address, pagesize) can be calculated by:
1941+
// alignDown(SegInfo.Address, pagesize)
1942+
// = SegInfo.Address - (SegInfo.Address % pagesize)
1943+
// = SegInfo.Address - (SegInfo.FileOffset % pagesize)
1944+
// = SegInfo.Address - SegInfo.FileOffset +
1945+
// alignDown(SegInfo.FileOffset, pagesize)
1946+
// = SegInfo.Address - SegInfo.FileOffset + FileOffset
1947+
return MMapAddress - (SegInfo.Address - SegInfo.FileOffset + FileOffset);
19311948
}
19321949
}
19331950

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <unistd.h>
4+
5+
int add(int a, int b) { return a + b; }
6+
int minus(int a, int b) { return a - b; }
7+
int multiple(int a, int b) { return a * b; }
8+
int divide(int a, int b) {
9+
if (b == 0)
10+
return 0;
11+
return a / b;
12+
}
13+
14+
int main() {
15+
int a = 16;
16+
int b = 8;
17+
18+
for (int i = 1; i < 100000; i++) {
19+
add(a, b);
20+
minus(a, b);
21+
multiple(a, b);
22+
divide(a, b);
23+
}
24+
25+
return 0;
26+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
SECTIONS {
2+
. = SIZEOF_HEADERS;
3+
.interp : { *(.interp) }
4+
.note.gnu.build-id : { *(.note.gnu.build-id) }
5+
. = 0x212e8;
6+
.dynsym : { *(.dynsym) }
7+
. = 0x31860;
8+
.text : { *(.text*) }
9+
. = 0x41c20;
10+
.fini_array : { *(.fini_array) }
11+
. = 0x54e18;
12+
.data : { *(.data) }
13+
}

bolt/test/perf2bolt/lit.local.cfg

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import shutil
2+
3+
if shutil.which("perf") != None:
4+
config.available_features.add("perf")

bolt/test/perf2bolt/perf_test.test

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Check perf2bolt binary function which was compiled with pie
2+
3+
REQUIRES: system-linux, perf
4+
5+
RUN: %clang %S/Inputs/perf_test.c -fuse-ld=lld -Wl,--script=%S/Inputs/perf_test.lds -o %t
6+
RUN: perf record -e cycles:u -o %t2 -- %t
7+
RUN: perf2bolt %t -p=%t2 -o %t3 -nl -ignore-build-id 2>&1 | FileCheck %s
8+
9+
CHECK-NOT: PERF2BOLT-ERROR
10+
CHECK-NOT: !! WARNING !! This high mismatch ratio indicates the input binary is probably not the same binary used during profiling collection.
11+
12+
RUN: %clang %S/Inputs/perf_test.c -no-pie -fuse-ld=lld -o %t4
13+
RUN: perf record -e cycles:u -o %t5 -- %t4
14+
RUN: perf2bolt %t4 -p=%t5 -o %t6 -nl -ignore-build-id 2>&1 | FileCheck %s --check-prefix=CHECK-NO-PIE
15+
16+
CHECK-NO-PIE-NOT: PERF2BOLT-ERROR
17+
CHECK-NO-PIE-NOT: !! WARNING !! This high mismatch ratio indicates the input binary is probably not the same binary used during profiling collection.

bolt/unittests/Core/BinaryContext.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,24 @@ TEST_P(BinaryContextTester, BaseAddress) {
123123
BaseAddress = BC->getBaseAddressForMapping(0x7f13f5556000, 0x137a000);
124124
ASSERT_FALSE(BaseAddress.has_value());
125125
}
126+
127+
TEST_P(BinaryContextTester, BaseAddress2) {
128+
// Check that base address calculation is correct for a binary if the
129+
// alignment in ELF file are different from pagesize.
130+
// The segment layout is as follows:
131+
BC->SegmentMapInfo[0] = SegmentInfo{0, 0x2177c, 0, 0x2177c, 0x10000};
132+
BC->SegmentMapInfo[0x31860] =
133+
SegmentInfo{0x31860, 0x370, 0x21860, 0x370, 0x10000};
134+
BC->SegmentMapInfo[0x41c20] =
135+
SegmentInfo{0x41c20, 0x1f8, 0x21c20, 0x1f8, 0x10000};
136+
BC->SegmentMapInfo[0x54e18] =
137+
SegmentInfo{0x54e18, 0x51, 0x24e18, 0x51, 0x10000};
138+
139+
std::optional<uint64_t> BaseAddress =
140+
BC->getBaseAddressForMapping(0xaaaaea444000, 0x21000);
141+
ASSERT_TRUE(BaseAddress.has_value());
142+
ASSERT_EQ(*BaseAddress, 0xaaaaea413000ULL);
143+
144+
BaseAddress = BC->getBaseAddressForMapping(0xaaaaea444000, 0x11000);
145+
ASSERT_FALSE(BaseAddress.has_value());
146+
}

0 commit comments

Comments
 (0)