[llvm] [clang-tools-extra] [Bolt] Solving pie support issue (PR #65494)

via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 13 06:29:43 PST 2023


https://github.com/JohnLee1243 updated https://github.com/llvm/llvm-project/pull/65494

>From 8d0b2089e00d3cae74f4ba30a0e8c5464678ead0 Mon Sep 17 00:00:00 2001
From: JohnLee1243 <lizhuohang911 at 126.com>
Date: Wed, 6 Sep 2023 23:27:18 +0800
Subject: [PATCH] [Bolt] Solving pie support issue

Offering: BiSheng

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.
---
 bolt/lib/Core/BinaryContext.cpp | 25 +++++++++++++++++++++----
 bolt/test/Inputs/perf_test.c    | 26 ++++++++++++++++++++++++++
 bolt/test/Inputs/perf_test.lds  | 13 +++++++++++++
 bolt/test/lit.cfg.py            |  4 ++++
 bolt/test/perf_test.test        | 17 +++++++++++++++++
 5 files changed, 81 insertions(+), 4 deletions(-)
 create mode 100644 bolt/test/Inputs/perf_test.c
 create mode 100644 bolt/test/Inputs/perf_test.lds
 create mode 100644 bolt/test/perf_test.test

diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp
index ffecc5209804351a..ed36dbced99beaa0 100644
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -1888,10 +1888,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/Inputs/perf_test.c b/bolt/test/Inputs/perf_test.c
new file mode 100644
index 0000000000000000..456f9567c5551de2
--- /dev/null
+++ b/bolt/test/Inputs/perf_test.c
@@ -0,0 +1,26 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+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 < 10000000; i++) {
+    add(a, b);
+    minus(a, b);
+    multiple(a, b);
+    divide(a, b);
+  }
+
+  return 0;
+}
\ No newline at end of file
diff --git a/bolt/test/Inputs/perf_test.lds b/bolt/test/Inputs/perf_test.lds
new file mode 100644
index 0000000000000000..9cb4ebbf1e9f83bc
--- /dev/null
+++ b/bolt/test/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/lit.cfg.py b/bolt/test/lit.cfg.py
index 3a6da210e01f080e..427e13b7e561d91a 100644
--- a/bolt/test/lit.cfg.py
+++ b/bolt/test/lit.cfg.py
@@ -3,6 +3,7 @@
 import os
 import platform
 import re
+import shutil
 import subprocess
 import tempfile
 
@@ -75,6 +76,9 @@
 if lit.util.which("fuser"):
     config.available_features.add("fuser")
 
+if shutil.which('perf') != None:
+    config.available_features.add('perf')
+
 llvm_config.use_default_substitutions()
 
 llvm_config.config.environment["CLANG"] = config.bolt_clang
diff --git a/bolt/test/perf_test.test b/bolt/test/perf_test.test
new file mode 100644
index 0000000000000000..44db899ab30de564
--- /dev/null
+++ b/bolt/test/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.
\ No newline at end of file



More information about the cfe-commits mailing list