From a28084a4adff2340dd02c2c0c42f4997f76b3ffa Mon Sep 17 00:00:00 2001 From: rfwang07 Date: Fri, 21 Jun 2024 11:16:44 +0800 Subject: [PATCH] [Bolt] Solving pie support issue --- bolt/lib/Core/BinaryContext.cpp | 25 +++++++++++++++++++---- bolt/test/perf2bolt/Inputs/perf_test.c | 26 ++++++++++++++++++++++++ bolt/test/perf2bolt/Inputs/perf_test.lds | 13 ++++++++++++ bolt/test/perf2bolt/lit.local.cfg | 4 ++++ bolt/test/perf2bolt/perf_test.test | 17 ++++++++++++++++ bolt/unittests/Core/BinaryContext.cpp | 21 +++++++++++++++++++ 6 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 bolt/test/perf2bolt/Inputs/perf_test.c create mode 100644 bolt/test/perf2bolt/Inputs/perf_test.lds create mode 100644 bolt/test/perf2bolt/lit.local.cfg create mode 100644 bolt/test/perf2bolt/perf_test.test diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp index 2d2b35ee2..ab9f0b844 100644 --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -1880,10 +1880,27 @@ BinaryContext::getBaseAddressForMapping(uint64_t MMapAddress, // Find a segment with a matching file offset. for (auto &KV : SegmentMapInfo) { const SegmentInfo &SegInfo = KV.second; - if (alignDown(SegInfo.FileOffset, SegInfo.Alignment) == FileOffset) { - // Use segment's aligned memory offset to calculate the base address. - const uint64_t MemOffset = alignDown(SegInfo.Address, SegInfo.Alignment); - return MMapAddress - MemOffset; + // FileOffset is got from perf event, + // and it is equal to alignDown(SegInfo.FileOffset, pagesize). + // If the pagesize is not equal to SegInfo.Alignment. + // FileOffset and SegInfo.FileOffset should be aligned first, + // and then judge whether they are equal. + if (alignDown(SegInfo.FileOffset, SegInfo.Alignment) == + alignDown(FileOffset, SegInfo.Alignment)) { + // The function's offset from base address in VAS is aligned by pagesize + // instead of SegInfo.Alignment. Pagesize can't be got from perf events. + // However, The ELF document says that SegInfo.FileOffset should equal + // to SegInfo.Address, modulo the pagesize. + // Reference: https://refspecs.linuxfoundation.org/elf/elf.pdf + + // So alignDown(SegInfo.Address, pagesize) can be calculated by: + // alignDown(SegInfo.Address, pagesize) + // = SegInfo.Address - (SegInfo.Address % pagesize) + // = SegInfo.Address - (SegInfo.FileOffset % pagesize) + // = SegInfo.Address - SegInfo.FileOffset + + // alignDown(SegInfo.FileOffset, pagesize) + // = SegInfo.Address - SegInfo.FileOffset + FileOffset + return MMapAddress - (SegInfo.Address - SegInfo.FileOffset + FileOffset); } } diff --git a/bolt/test/perf2bolt/Inputs/perf_test.c b/bolt/test/perf2bolt/Inputs/perf_test.c new file mode 100644 index 000000000..ff5ecf7a8 --- /dev/null +++ b/bolt/test/perf2bolt/Inputs/perf_test.c @@ -0,0 +1,26 @@ +#include +#include +#include + +int add(int a, int b) { return a + b; } +int minus(int a, int b) { return a - b; } +int multiple(int a, int b) { return a * b; } +int divide(int a, int b) { + if (b == 0) + return 0; + return a / b; +} + +int main() { + int a = 16; + int b = 8; + + for (int i = 1; i < 100000; i++) { + add(a, b); + minus(a, b); + multiple(a, b); + divide(a, b); + } + + return 0; +} diff --git a/bolt/test/perf2bolt/Inputs/perf_test.lds b/bolt/test/perf2bolt/Inputs/perf_test.lds new file mode 100644 index 000000000..9cb4ebbf1 --- /dev/null +++ b/bolt/test/perf2bolt/Inputs/perf_test.lds @@ -0,0 +1,13 @@ +SECTIONS { + . = SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + . = 0x212e8; + .dynsym : { *(.dynsym) } + . = 0x31860; + .text : { *(.text*) } + . = 0x41c20; + .fini_array : { *(.fini_array) } + . = 0x54e18; + .data : { *(.data) } +} diff --git a/bolt/test/perf2bolt/lit.local.cfg b/bolt/test/perf2bolt/lit.local.cfg new file mode 100644 index 000000000..87a96ec34 --- /dev/null +++ b/bolt/test/perf2bolt/lit.local.cfg @@ -0,0 +1,4 @@ +import shutil + +if shutil.which("perf") != None: + config.available_features.add("perf") diff --git a/bolt/test/perf2bolt/perf_test.test b/bolt/test/perf2bolt/perf_test.test new file mode 100644 index 000000000..fe6e015ab --- /dev/null +++ b/bolt/test/perf2bolt/perf_test.test @@ -0,0 +1,17 @@ +# Check perf2bolt binary function which was compiled with pie + +REQUIRES: system-linux, perf + +RUN: %clang %S/Inputs/perf_test.c -fuse-ld=lld -Wl,--script=%S/Inputs/perf_test.lds -o %t +RUN: perf record -e cycles:u -o %t2 -- %t +RUN: perf2bolt %t -p=%t2 -o %t3 -nl -ignore-build-id 2>&1 | FileCheck %s + +CHECK-NOT: PERF2BOLT-ERROR +CHECK-NOT: !! WARNING !! This high mismatch ratio indicates the input binary is probably not the same binary used during profiling collection. + +RUN: %clang %S/Inputs/perf_test.c -no-pie -fuse-ld=lld -o %t4 +RUN: perf record -e cycles:u -o %t5 -- %t4 +RUN: perf2bolt %t4 -p=%t5 -o %t6 -nl -ignore-build-id 2>&1 | FileCheck %s --check-prefix=CHECK-NO-PIE + +CHECK-NO-PIE-NOT: PERF2BOLT-ERROR +CHECK-NO-PIE-NOT: !! WARNING !! This high mismatch ratio indicates the input binary is probably not the same binary used during profiling collection. diff --git a/bolt/unittests/Core/BinaryContext.cpp b/bolt/unittests/Core/BinaryContext.cpp index bac264141..5a80cb4a2 100644 --- a/bolt/unittests/Core/BinaryContext.cpp +++ b/bolt/unittests/Core/BinaryContext.cpp @@ -83,3 +83,24 @@ TEST_P(BinaryContextTester, BaseAddress) { BaseAddress = BC->getBaseAddressForMapping(0x7f13f5556000, 0x137a000); ASSERT_FALSE(BaseAddress.has_value()); } + +TEST_P(BinaryContextTester, BaseAddress2) { + // Check that base address calculation is correct for a binary if the + // alignment in ELF file are different from pagesize. + // The segment layout is as follows: + BC->SegmentMapInfo[0] = SegmentInfo{0, 0x2177c, 0, 0x2177c, 0x10000}; + BC->SegmentMapInfo[0x31860] = + SegmentInfo{0x31860, 0x370, 0x21860, 0x370, 0x10000}; + BC->SegmentMapInfo[0x41c20] = + SegmentInfo{0x41c20, 0x1f8, 0x21c20, 0x1f8, 0x10000}; + BC->SegmentMapInfo[0x54e18] = + SegmentInfo{0x54e18, 0x51, 0x24e18, 0x51, 0x10000}; + + std::optional BaseAddress = + BC->getBaseAddressForMapping(0xaaaaea444000, 0x21000); + ASSERT_TRUE(BaseAddress.has_value()); + ASSERT_EQ(*BaseAddress, 0xaaaaea413000ULL); + + BaseAddress = BC->getBaseAddressForMapping(0xaaaaea444000, 0x11000); + ASSERT_FALSE(BaseAddress.has_value()); +} -- 2.39.2 (Apple Git-143)