-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[BOLT] Detect Linux kernel version if the binary is a Linux kernel #119088
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-bolt Author: Franklin (FLZ101) ChangesFull diff: https://github.com/llvm/llvm-project/pull/119088.diff 3 Files Affected:
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..b88da11701b354 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,27 @@ 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();
+ } else {
+ BC->errs() << "BOLT-WARNING: Linux kernel version is unknown\n";
+ }
+ }
+
if (!Section->isText()) {
assert(SymbolType != SymbolRef::ST_Function &&
"unexpected function inside non-code section");
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",@progbits
+ .section __ksymtab_gpl,"a",@progbits
|
4e99abe
to
782c464
Compare
This makes it easier to handle differences (e.g. of exception table entry size) between versions of Linux kernel
782c464
to
69554a8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't mind the direction in general, but if you can add a subsequent patch showing how you want to use the functionality, that would be great.
@@ -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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This maybe should be a struct instead of a tuple
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
bolt/lib/Rewrite/RewriteInstance.cpp
Outdated
@@ -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"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the version of the kernel is unknown, you just emit a warning instead of erroring out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If BOLT errors out here, then all Linux kernel related tests need to specify a proper version.
It would be better to do that later when functions like readAltInstructions()
and readStaticKeysJumpTable()
have been modified to utilize LinuxKernelVersion
to handle differences between Linux kernel versions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added a Linux kernel version for each related test and changed the behavior to erroring out.
Use struct instead of tuple to represent Linux kernel version
7dc58da
to
6b931b3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the PR.
@@ -670,6 +698,8 @@ class BinaryContext { | |||
/// Indicates if the binary is Linux kernel. | |||
bool IsLinuxKernel{false}; | |||
|
|||
LKVersion LinuxKernelVersion; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't expect to use the kernel version outside of the LinuxKernelRewriter
, I suggest we move it in there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
bolt/lib/Rewrite/RewriteInstance.cpp
Outdated
@@ -1030,6 +1031,25 @@ void RewriteInstance::discoverFileObjects() { | |||
continue; | |||
} | |||
|
|||
if (BC->IsLinuxKernel && SymName == "linux_banner") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reading part also should be in the LinuxKernelRewriter
. You can access symbols via BinaryData
objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
bolt/lib/Rewrite/RewriteInstance.cpp
Outdated
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: constify.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
816d1aa
to
bb683eb
Compare
Move LinuxKernelVersion to LinuxKernelRewriter
Multiple symbols with the same address but different sizes are mapped to the same So we usually can not be certain about the size of a Is it by design? |
|
Thank you for refactoring the code. Please add tests for the Linux version and include non-standard versions. |
There is a failed test case, which I have created a PR #119557 to fix. I'll add missing tests soon. |
Tests are added. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks! Please address the nit before committing.
linux_banner: | ||
|
||
#ifdef A | ||
.string "Linux version 6.6.61\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: could you please place CHECK
s next to the object you are checking against?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Fix evaluation order problem identified in llvm#119088.
Fix evaluation order problem identified in #119088.
@dcci An example usage of It will be used more in [BOLT][AArch64] Basic support for Linux kernel. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
…FCI (#120491) Fix evaluation order problem identified in llvm/llvm-project#119088.
This makes it easier to handle differences (e.g. of exception table
entry size) between versions of Linux kernel