Skip to content

Commit 69554a8

Browse files
committed
[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
1 parent 342c8db commit 69554a8

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

bolt/include/bolt/Core/BinaryContext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,9 @@ class BinaryContext {
670670
/// Indicates if the binary is Linux kernel.
671671
bool IsLinuxKernel{false};
672672

673+
/// Linux kernel version (major, minor, reversion)
674+
std::tuple<unsigned, unsigned, unsigned> LinuxKernelVersion;
675+
673676
/// Indicates if relocations are available for usage.
674677
bool HasRelocations{false};
675678

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
#include <fstream>
6262
#include <memory>
6363
#include <optional>
64+
#include <regex>
6465
#include <system_error>
6566

6667
#undef DEBUG_TYPE
@@ -1030,6 +1031,25 @@ void RewriteInstance::discoverFileObjects() {
10301031
continue;
10311032
}
10321033

1034+
if (BC->IsLinuxKernel && SymName == "linux_banner") {
1035+
const StringRef SectionContents =
1036+
cantFail(Section->getContents(), "can not get section contents");
1037+
const std::string S =
1038+
SectionContents
1039+
.substr(SymbolAddress - Section->getAddress(), SymbolSize)
1040+
.str();
1041+
1042+
const std::regex Re(R"---(Linux version ((\d+)\.(\d+)(\.(\d+))?))---");
1043+
std::smatch Match;
1044+
if (std::regex_search(S, Match, Re)) {
1045+
unsigned Major = std::stoi(Match[2].str());
1046+
unsigned Minor = std::stoi(Match[3].str());
1047+
unsigned Rev = Match.size() > 5 ? std::stoi(Match[5].str()) : 0;
1048+
BC->LinuxKernelVersion = std::make_tuple(Major, Minor, Rev);
1049+
BC->outs() << "BOLT-INFO: Linux kernel version is " << Match[1].str();
1050+
}
1051+
}
1052+
10331053
if (!Section->isText()) {
10341054
assert(SymbolType != SymbolRef::ST_Function &&
10351055
"unexpected function inside non-code section");
@@ -1205,6 +1225,9 @@ void RewriteInstance::discoverFileObjects() {
12051225
PreviousFunction = BF;
12061226
}
12071227

1228+
if (BC->IsLinuxKernel && !std::get<0>(BC->LinuxKernelVersion))
1229+
BC->errs() << "BOLT-WARNING: Linux kernel version is unknown\n";
1230+
12081231
// Read dynamic relocation first as their presence affects the way we process
12091232
// static relocations. E.g. we will ignore a static relocation at an address
12101233
// that is a subject to dynamic relocation processing.

bolt/test/X86/linux-version.s

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# REQUIRES: system-linux
2+
3+
## Check that BOLT correctly detects the Linux kernel version
4+
5+
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
6+
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
7+
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr
8+
9+
# RUN: llvm-bolt %t.exe -o %t.out | FileCheck %s
10+
11+
# CHECK: BOLT-INFO: Linux kernel version is 6.6.61
12+
13+
.text
14+
.globl f
15+
.type f, @function
16+
f:
17+
ret
18+
.size f, .-f
19+
20+
.globl linux_banner
21+
.section .rodata
22+
.align 16
23+
.type linux_banner, @object
24+
.size linux_banner, 22
25+
linux_banner:
26+
.string "Linux version 6.6.61\n"
27+
28+
## Fake Linux Kernel sections.
29+
.section __ksymtab,"a",@progbits
30+
.section __ksymtab_gpl,"a",@progbits

0 commit comments

Comments
 (0)