[llvm] [BOLT] Detect Linux kernel version if the binary is a Linux kernel (PR #119088)

via llvm-commits llvm-commits at lists.llvm.org
Sun Dec 8 09:04:28 PST 2024


https://github.com/FLZ101 updated https://github.com/llvm/llvm-project/pull/119088

>From 69554a819ef782199d1b25039e484b174a48cdaf Mon Sep 17 00:00:00 2001
From: fengleizZZ <zhangfenglei at huawei.com>
Date: Sun, 8 Dec 2024 02:37:49 +0800
Subject: [PATCH 1/2] [BOLT] Detect Linux kernel version if the binary is a
 Linux kernel

This makes it easier to handle differences (e.g. of exception table
entry size) between versions of Linux kernel
---
 bolt/include/bolt/Core/BinaryContext.h |  3 +++
 bolt/lib/Rewrite/RewriteInstance.cpp   | 23 ++++++++++++++++++++
 bolt/test/X86/linux-version.s          | 30 ++++++++++++++++++++++++++
 3 files changed, 56 insertions(+)
 create mode 100644 bolt/test/X86/linux-version.s

diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h
index 115e59ca0697e5..052a145efe4a4b 100644
--- a/bolt/include/bolt/Core/BinaryContext.h
+++ b/bolt/include/bolt/Core/BinaryContext.h
@@ -670,6 +670,9 @@ class BinaryContext {
   /// Indicates if the binary is Linux kernel.
   bool IsLinuxKernel{false};
 
+  /// Linux kernel version (major, minor, reversion)
+  std::tuple<unsigned, unsigned, unsigned> LinuxKernelVersion;
+
   /// Indicates if relocations are available for usage.
   bool HasRelocations{false};
 
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 76e1f0156f828d..48617dc8ea5946 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -61,6 +61,7 @@
 #include <fstream>
 #include <memory>
 #include <optional>
+#include <regex>
 #include <system_error>
 
 #undef  DEBUG_TYPE
@@ -1030,6 +1031,25 @@ void RewriteInstance::discoverFileObjects() {
       continue;
     }
 
+    if (BC->IsLinuxKernel && SymName == "linux_banner") {
+      const StringRef SectionContents =
+          cantFail(Section->getContents(), "can not get section contents");
+      const std::string S =
+          SectionContents
+              .substr(SymbolAddress - Section->getAddress(), SymbolSize)
+              .str();
+
+      const std::regex Re(R"---(Linux version ((\d+)\.(\d+)(\.(\d+))?))---");
+      std::smatch Match;
+      if (std::regex_search(S, Match, Re)) {
+        unsigned Major = std::stoi(Match[2].str());
+        unsigned Minor = std::stoi(Match[3].str());
+        unsigned Rev = Match.size() > 5 ? std::stoi(Match[5].str()) : 0;
+        BC->LinuxKernelVersion = std::make_tuple(Major, Minor, Rev);
+        BC->outs() << "BOLT-INFO: Linux kernel version is " << Match[1].str();
+      }
+    }
+
     if (!Section->isText()) {
       assert(SymbolType != SymbolRef::ST_Function &&
              "unexpected function inside non-code section");
@@ -1205,6 +1225,9 @@ void RewriteInstance::discoverFileObjects() {
     PreviousFunction = BF;
   }
 
+  if (BC->IsLinuxKernel && !std::get<0>(BC->LinuxKernelVersion))
+    BC->errs() << "BOLT-WARNING: Linux kernel version is unknown\n";
+
   // Read dynamic relocation first as their presence affects the way we process
   // static relocations. E.g. we will ignore a static relocation at an address
   // that is a subject to dynamic relocation processing.
diff --git a/bolt/test/X86/linux-version.s b/bolt/test/X86/linux-version.s
new file mode 100644
index 00000000000000..079910be931cdb
--- /dev/null
+++ b/bolt/test/X86/linux-version.s
@@ -0,0 +1,30 @@
+# REQUIRES: system-linux
+
+## Check that BOLT correctly detects the Linux kernel version
+
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
+# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
+# RUN:   -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr
+
+# RUN: llvm-bolt %t.exe -o %t.out | FileCheck %s
+
+# CHECK: BOLT-INFO: Linux kernel version is 6.6.61
+
+	.text
+	.globl	f
+	.type	f, @function
+f:
+	ret
+	.size	f, .-f
+
+	.globl	linux_banner
+	.section	.rodata
+	.align 16
+	.type	linux_banner, @object
+	.size	linux_banner, 22
+linux_banner:
+	.string	"Linux version 6.6.61\n"
+
+## Fake Linux Kernel sections.
+  .section __ksymtab,"a", at progbits
+  .section __ksymtab_gpl,"a", at progbits

>From 6b931b37b0a0b40828c018f2e095b25d778c4b9d Mon Sep 17 00:00:00 2001
From: fengleizZZ <zhangfenglei at huawei.com>
Date: Mon, 9 Dec 2024 00:27:31 +0800
Subject: [PATCH 2/2] [BOLT] Detect Linux kernel version if the binary is a
 Linux kernel

Use struct instead of tuple to represent Linux kernel version
---
 bolt/include/bolt/Core/BinaryContext.h | 31 ++++++++++++++++++++++++--
 bolt/lib/Rewrite/RewriteInstance.cpp   |  4 ++--
 bolt/unittests/Core/BinaryContext.cpp  | 14 ++++++++++++
 3 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h
index 052a145efe4a4b..7d49dd003ca02a 100644
--- a/bolt/include/bolt/Core/BinaryContext.h
+++ b/bolt/include/bolt/Core/BinaryContext.h
@@ -180,6 +180,34 @@ struct JournalingStreams {
 Error createNonFatalBOLTError(const Twine &S);
 Error createFatalBOLTError(const Twine &S);
 
+/// Linux kernel version
+struct LKVersion {
+  LKVersion() {}
+  LKVersion(unsigned Major, unsigned Minor, unsigned Rev)
+      : Major(Major), Minor(Minor), Rev(Rev) {}
+
+  bool operator<(const LKVersion &Other) const {
+    return std::make_tuple(Major, Minor, Rev) <
+           std::make_tuple(Other.Major, Other.Minor, Other.Rev);
+  }
+
+  bool operator>(const LKVersion &Other) const { return Other < *this; }
+
+  bool operator<=(const LKVersion &Other) const { return !(*this > Other); }
+
+  bool operator>=(const LKVersion &Other) const { return !(*this < Other); }
+
+  bool operator==(const LKVersion &Other) const {
+    return Major == Other.Major && Minor == Other.Minor && Rev == Other.Rev;
+  }
+
+  bool operator!=(const LKVersion &Other) const { return !(*this == Other); }
+
+  unsigned Major{0};
+  unsigned Minor{0};
+  unsigned Rev{0};
+};
+
 class BinaryContext {
   BinaryContext() = delete;
 
@@ -670,8 +698,7 @@ class BinaryContext {
   /// Indicates if the binary is Linux kernel.
   bool IsLinuxKernel{false};
 
-  /// Linux kernel version (major, minor, reversion)
-  std::tuple<unsigned, unsigned, unsigned> LinuxKernelVersion;
+  LKVersion LinuxKernelVersion;
 
   /// Indicates if relocations are available for usage.
   bool HasRelocations{false};
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 48617dc8ea5946..85a753b3cb0554 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -1045,7 +1045,7 @@ void RewriteInstance::discoverFileObjects() {
         unsigned Major = std::stoi(Match[2].str());
         unsigned Minor = std::stoi(Match[3].str());
         unsigned Rev = Match.size() > 5 ? std::stoi(Match[5].str()) : 0;
-        BC->LinuxKernelVersion = std::make_tuple(Major, Minor, Rev);
+        BC->LinuxKernelVersion = LKVersion(Major, Minor, Rev);
         BC->outs() << "BOLT-INFO: Linux kernel version is " << Match[1].str();
       }
     }
@@ -1225,7 +1225,7 @@ void RewriteInstance::discoverFileObjects() {
     PreviousFunction = BF;
   }
 
-  if (BC->IsLinuxKernel && !std::get<0>(BC->LinuxKernelVersion))
+  if (BC->IsLinuxKernel && !BC->LinuxKernelVersion.Major)
     BC->errs() << "BOLT-WARNING: Linux kernel version is unknown\n";
 
   // Read dynamic relocation first as their presence affects the way we process
diff --git a/bolt/unittests/Core/BinaryContext.cpp b/bolt/unittests/Core/BinaryContext.cpp
index 9819a8c2b777b7..d8400d9b18174f 100644
--- a/bolt/unittests/Core/BinaryContext.cpp
+++ b/bolt/unittests/Core/BinaryContext.cpp
@@ -218,3 +218,17 @@ TEST_P(BinaryContextTester, BaseAddressSegmentsSmallerThanAlignment) {
   ASSERT_TRUE(BaseAddress.has_value());
   ASSERT_EQ(*BaseAddress, 0xaaaaaaaa0000ULL);
 }
+
+TEST(BinaryContextTester, LKVersion) {
+  LKVersion V1;
+  LKVersion V2(5, 9, 15);
+  LKVersion V3(6, 12, 1);
+
+  V1 = V3;
+  ASSERT_TRUE(V1 == V3);
+  ASSERT_TRUE(V2 != V3);
+  ASSERT_TRUE(V2 < V3);
+  ASSERT_TRUE(V2 <= V3);
+  ASSERT_TRUE(V3 > V2);
+  ASSERT_TRUE(V3 >= V2);
+}



More information about the llvm-commits mailing list