Skip to content

Commit 8233a8e

Browse files
FLZ101Flightor
authored andcommitted
[BOLT] Detect Linux kernel version if the binary is a Linux kernel (#119088)
This makes it easier to handle differences (e.g. of exception table entry size) between versions of Linux kernel
1 parent d53e313 commit 8233a8e

13 files changed

+205
-0
lines changed

bolt/include/bolt/Core/BinaryData.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ class BinaryData {
169169
return Parent && (Parent == BD || Parent->isAncestorOf(BD));
170170
}
171171

172+
void updateSize(uint64_t N) {
173+
if (N > Size)
174+
Size = N;
175+
}
176+
172177
void setIsMoveable(bool Flag) { IsMoveable = Flag; }
173178
void setSection(BinarySection &NewSection);
174179
void setOutputSection(BinarySection &NewSection) {

bolt/lib/Core/BinaryContext.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,7 @@ MCSymbol *BinaryContext::registerNameAtAddress(StringRef Name, uint64_t Address,
10731073
BD = GAI->second;
10741074
if (!BD->hasName(Name)) {
10751075
GlobalSymbols[Name] = BD;
1076+
BD->updateSize(Size);
10761077
BD->Symbols.push_back(Symbol);
10771078
}
10781079
}

bolt/lib/Rewrite/LinuxKernelRewriter.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include "llvm/Support/CommandLine.h"
2222
#include "llvm/Support/Debug.h"
2323
#include "llvm/Support/Errc.h"
24+
#include "llvm/Support/ErrorOr.h"
25+
#include <regex>
2426

2527
#define DEBUG_TYPE "bolt-linux"
2628

@@ -89,6 +91,34 @@ static cl::opt<bool>
8991

9092
} // namespace opts
9193

94+
/// Linux kernel version
95+
struct LKVersion {
96+
LKVersion() {}
97+
LKVersion(unsigned Major, unsigned Minor, unsigned Rev)
98+
: Major(Major), Minor(Minor), Rev(Rev) {}
99+
100+
bool operator<(const LKVersion &Other) const {
101+
return std::make_tuple(Major, Minor, Rev) <
102+
std::make_tuple(Other.Major, Other.Minor, Other.Rev);
103+
}
104+
105+
bool operator>(const LKVersion &Other) const { return Other < *this; }
106+
107+
bool operator<=(const LKVersion &Other) const { return !(*this > Other); }
108+
109+
bool operator>=(const LKVersion &Other) const { return !(*this < Other); }
110+
111+
bool operator==(const LKVersion &Other) const {
112+
return Major == Other.Major && Minor == Other.Minor && Rev == Other.Rev;
113+
}
114+
115+
bool operator!=(const LKVersion &Other) const { return !(*this == Other); }
116+
117+
unsigned Major{0};
118+
unsigned Minor{0};
119+
unsigned Rev{0};
120+
};
121+
92122
/// Linux Kernel supports stack unwinding using ORC (oops rewind capability).
93123
/// ORC state at every IP can be described by the following data structure.
94124
struct ORCState {
@@ -124,6 +154,8 @@ inline raw_ostream &operator<<(raw_ostream &OS, const ORCState &E) {
124154
namespace {
125155

126156
class LinuxKernelRewriter final : public MetadataRewriter {
157+
LKVersion LinuxKernelVersion;
158+
127159
/// Information required for updating metadata referencing an instruction.
128160
struct InstructionFixup {
129161
BinarySection &Section; // Section referencing the instruction.
@@ -225,6 +257,8 @@ class LinuxKernelRewriter final : public MetadataRewriter {
225257
ErrorOr<BinarySection &> PCIFixupSection = std::errc::bad_address;
226258
static constexpr size_t PCI_FIXUP_ENTRY_SIZE = 16;
227259

260+
Error detectLinuxKernelVersion();
261+
228262
/// Process linux kernel special sections and their relocations.
229263
void processLKSections();
230264

@@ -290,6 +324,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
290324
: MetadataRewriter("linux-kernel-rewriter", BC) {}
291325

292326
Error preCFGInitializer() override {
327+
if (Error E = detectLinuxKernelVersion())
328+
return E;
329+
293330
processLKSections();
294331

295332
if (Error E = processSMPLocks())
@@ -370,6 +407,28 @@ class LinuxKernelRewriter final : public MetadataRewriter {
370407
}
371408
};
372409

410+
Error LinuxKernelRewriter::detectLinuxKernelVersion() {
411+
if (BinaryData *BD = BC.getBinaryDataByName("linux_banner")) {
412+
const BinarySection &Section = BD->getSection();
413+
const std::string S =
414+
Section.getContents().substr(BD->getOffset(), BD->getSize()).str();
415+
416+
const std::regex Re(R"---(Linux version ((\d+)\.(\d+)(\.(\d+))?))---");
417+
std::smatch Match;
418+
if (std::regex_search(S, Match, Re)) {
419+
const unsigned Major = std::stoi(Match[2].str());
420+
const unsigned Minor = std::stoi(Match[3].str());
421+
const unsigned Rev = Match[5].matched ? std::stoi(Match[5].str()) : 0;
422+
LinuxKernelVersion = LKVersion(Major, Minor, Rev);
423+
BC.outs() << "BOLT-INFO: Linux kernel version is " << Match[1].str()
424+
<< "\n";
425+
return Error::success();
426+
}
427+
}
428+
return createStringError(errc::executable_format_error,
429+
"Linux kernel version is unknown");
430+
}
431+
373432
void LinuxKernelRewriter::processLKSections() {
374433
processLKKSymtab();
375434
processLKKSymtab(true);

bolt/test/X86/linux-alt-instruction.s

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,15 @@ _start:
142142
.section .orc_unwind_ip
143143
.long .L0 + 2 - .
144144

145+
## Linux kernel version
146+
.rodata
147+
.align 16
148+
.globl linux_banner
149+
.type linux_banner, @object
150+
linux_banner:
151+
.string "Linux version 6.6.61\n"
152+
.size linux_banner, . - linux_banner
153+
145154
## Fake Linux Kernel sections.
146155
.section __ksymtab,"a",@progbits
147156
.section __ksymtab_gpl,"a",@progbits

bolt/test/X86/linux-bug-table.s

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,15 @@ _start:
5656
.long .L1 - . # instruction
5757
.org 2b + 12
5858

59+
## Linux kernel version
60+
.rodata
61+
.align 16
62+
.globl linux_banner
63+
.type linux_banner, @object
64+
linux_banner:
65+
.string "Linux version 6.6.61\n"
66+
.size linux_banner, . - linux_banner
67+
5968
## Fake Linux Kernel sections.
6069
.section __ksymtab,"a",@progbits
6170
.section __ksymtab_gpl,"a",@progbits

bolt/test/X86/linux-exceptions.s

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ foo:
5959
.long .LF0 - . # fixup
6060
.long 0 # data
6161

62+
## Linux kernel version
63+
.rodata
64+
.align 16
65+
.globl linux_banner
66+
.type linux_banner, @object
67+
linux_banner:
68+
.string "Linux version 6.6.61\n"
69+
.size linux_banner, . - linux_banner
70+
6271
## Fake Linux Kernel sections.
6372
.section __ksymtab,"a",@progbits
6473
.section __ksymtab_gpl,"a",@progbits

bolt/test/X86/linux-orc.s

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,15 @@ bar:
157157
.section .orc_unwind_ip
158158
.long .L4 - .
159159

160+
## Linux kernel version
161+
.rodata
162+
.align 16
163+
.globl linux_banner
164+
.type linux_banner, @object
165+
linux_banner:
166+
.string "Linux version 6.6.61\n"
167+
.size linux_banner, . - linux_banner
168+
160169
## Fake Linux Kernel sections.
161170
.section __ksymtab,"a",@progbits
162171
.section __ksymtab_gpl,"a",@progbits

bolt/test/X86/linux-parainstructions.s

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ _start:
4949
.byte 1 # type
5050
.byte 7 # length
5151

52+
## Linux kernel version
53+
.rodata
54+
.align 16
55+
.globl linux_banner
56+
.type linux_banner, @object
57+
linux_banner:
58+
.string "Linux version 6.6.61\n"
59+
.size linux_banner, . - linux_banner
60+
5261
## Fake Linux Kernel sections.
5362
.section __ksymtab,"a",@progbits
5463
.section __ksymtab_gpl,"a",@progbits

bolt/test/X86/linux-pci-fixup.s

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ _start:
3636
.long 0x0 # class shift
3737
.long .L0 - . # fixup
3838

39+
## Linux kernel version
40+
.rodata
41+
.align 16
42+
.globl linux_banner
43+
.type linux_banner, @object
44+
linux_banner:
45+
.string "Linux version 6.6.61\n"
46+
.size linux_banner, . - linux_banner
47+
3948
## Fake Linux Kernel sections.
4049
.section __ksymtab,"a",@progbits
4150
.section __ksymtab_gpl,"a",@progbits

bolt/test/X86/linux-smp-locks.s

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ _start:
3535
.long .L0 - .
3636
.long .L1 - .
3737

38+
## Linux kernel version
39+
.rodata
40+
.align 16
41+
.globl linux_banner
42+
.type linux_banner, @object
43+
linux_banner:
44+
.string "Linux version 6.6.61\n"
45+
.size linux_banner, . - linux_banner
46+
3847
## Fake Linux Kernel sections.
3948
.section __ksymtab,"a",@progbits
4049
.section __ksymtab_gpl,"a",@progbits

bolt/test/X86/linux-static-calls.s

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,15 @@ __start_static_call_sites:
5454
.type __stop_static_call_sites, %object
5555
__stop_static_call_sites:
5656

57+
## Linux kernel version
58+
.rodata
59+
.align 16
60+
.globl linux_banner
61+
.type linux_banner, @object
62+
linux_banner:
63+
.string "Linux version 6.6.61\n"
64+
.size linux_banner, . - linux_banner
65+
5766
## Fake Linux Kernel sections.
5867
.section __ksymtab,"a",@progbits
5968
.section __ksymtab_gpl,"a",@progbits

bolt/test/X86/linux-static-keys.s

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,21 @@ __start___jump_table:
7979
.type __stop___jump_table, %object
8080
__stop___jump_table:
8181

82+
## Staic keys (we just use the label ignoring the format of the keys).
83+
.data
84+
.align 8
85+
fake_static_key:
86+
.quad 0
87+
88+
## Linux kernel version
89+
.rodata
90+
.align 16
91+
.globl linux_banner
92+
.type linux_banner, @object
93+
linux_banner:
94+
.string "Linux version 6.6.61\n"
95+
.size linux_banner, . - linux_banner
96+
8297
## Fake Linux Kernel sections.
8398
.section __ksymtab,"a",@progbits
8499
.section __ksymtab_gpl,"a",@progbits

bolt/test/X86/linux-version.S

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# REQUIRES: system-linux
2+
3+
## Check that BOLT correctly detects the Linux kernel version
4+
5+
# RUN: %clang -DA -target x86_64-unknown-unknown \
6+
# RUN: %cflags -nostdlib %s -o %t.exe \
7+
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr
8+
# RUN: llvm-bolt %t.exe -o %t.out 2>&1 | FileCheck --check-prefix=CHECK-A %s
9+
10+
# RUN: %clang -DB -target x86_64-unknown-unknown \
11+
# RUN: %cflags -nostdlib %s -o %t.exe \
12+
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr
13+
# RUN: llvm-bolt %t.exe -o %t.out 2>&1 | FileCheck --check-prefix=CHECK-B %s
14+
15+
# RUN: %clang -DC -target x86_64-unknown-unknown \
16+
# RUN: %cflags -nostdlib %s -o %t.exe \
17+
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr
18+
# RUN: llvm-bolt %t.exe -o %t.out 2>&1 | FileCheck --check-prefix=CHECK-C %s
19+
20+
.text
21+
.globl foo
22+
.type foo, %function
23+
foo:
24+
ret
25+
.size foo, .-foo
26+
27+
## Linux kernel version
28+
.rodata
29+
.align 16
30+
.globl linux_banner
31+
.type linux_banner, @object
32+
linux_banner:
33+
34+
#ifdef A
35+
.string "Linux version 6.6.61\n"
36+
#endif
37+
# CHECK-A: BOLT-INFO: Linux kernel version is 6.6.61
38+
39+
#ifdef B
40+
.string "Linux version 6.6.50-rc4\n"
41+
#endif
42+
# CHECK-B: BOLT-INFO: Linux kernel version is 6.6.50
43+
44+
#ifdef C
45+
.string "Linux version 6.6\n"
46+
#endif
47+
# CHECK-C: BOLT-INFO: Linux kernel version is 6.6
48+
49+
.size linux_banner, . - linux_banner
50+
51+
## Fake Linux Kernel sections.
52+
.section __ksymtab,"a",@progbits
53+
.section __ksymtab_gpl,"a",@progbits

0 commit comments

Comments
 (0)