[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