Skip to content

Commit 2abcbbd

Browse files
authored
[BOLT] Detect Linux kernel based on ELF program headers (#80086)
Check if program header addresses fall into the kernel space to detect a Linux kernel binary on x86-64. Delete opts::LinuxKernelMode and use BinaryContext::IsLinuxKernel instead.
1 parent d783933 commit 2abcbbd

File tree

7 files changed

+25
-24
lines changed

7 files changed

+25
-24
lines changed

bolt/include/bolt/Core/BinaryContext.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,9 @@ class BinaryContext {
554554
/// Huge page size to use.
555555
static constexpr unsigned HugePageSize = 0x200000;
556556

557+
/// Addresses reserved for kernel on x86_64 start at this location.
558+
static constexpr uint64_t KernelStartX86_64 = 0xFFFF'FFFF'8000'0000;
559+
557560
/// Map address to a constant island owner (constant data in code section)
558561
std::map<uint64_t, BinaryFunction *> AddressToConstantIslandMap;
559562

@@ -602,6 +605,9 @@ class BinaryContext {
602605

603606
std::unique_ptr<MCAsmBackend> MAB;
604607

608+
/// Indicates if the binary is Linux kernel.
609+
bool IsLinuxKernel{false};
610+
605611
/// Indicates if relocations are available for usage.
606612
bool HasRelocations{false};
607613

bolt/include/bolt/Utils/CommandLineOpts.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
namespace opts {
1919

2020
extern bool HeatmapMode;
21-
extern bool LinuxKernelMode;
2221

2322
extern llvm::cl::OptionCategory BoltCategory;
2423
extern llvm::cl::OptionCategory BoltDiffCategory;

bolt/lib/Profile/DataAggregator.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ Error DataAggregator::preprocessProfile(BinaryContext &BC) {
524524
ErrorCallback(ReturnCode, ErrBuf);
525525
};
526526

527-
if (opts::LinuxKernelMode) {
527+
if (BC.IsLinuxKernel) {
528528
// Current MMap parsing logic does not work with linux kernel.
529529
// MMap entries for linux kernel uses PERF_RECORD_MMAP
530530
// format instead of typical PERF_RECORD_MMAP2 format.
@@ -1056,7 +1056,7 @@ ErrorOr<DataAggregator::PerfBranchSample> DataAggregator::parseBranchSample() {
10561056
if (std::error_code EC = PIDRes.getError())
10571057
return EC;
10581058
auto MMapInfoIter = BinaryMMapInfo.find(*PIDRes);
1059-
if (!opts::LinuxKernelMode && MMapInfoIter == BinaryMMapInfo.end()) {
1059+
if (!BC->IsLinuxKernel && MMapInfoIter == BinaryMMapInfo.end()) {
10601060
consumeRestOfLine();
10611061
return make_error_code(errc::no_such_process);
10621062
}
@@ -1277,7 +1277,7 @@ std::error_code DataAggregator::printLBRHeatMap() {
12771277
NamedRegionTimer T("parseBranch", "Parsing branch events", TimerGroupName,
12781278
TimerGroupDesc, opts::TimeAggregator);
12791279

1280-
if (opts::LinuxKernelMode) {
1280+
if (BC->IsLinuxKernel) {
12811281
opts::HeatmapMaxAddress = 0xffffffffffffffff;
12821282
opts::HeatmapMinAddress = KernelBaseAddr;
12831283
}

bolt/lib/Rewrite/LinuxKernelRewriter.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,7 @@ void LinuxKernelRewriter::insertLKMarker(uint64_t PC, uint64_t SectionOffset,
207207
}
208208

209209
void LinuxKernelRewriter::processLKSections() {
210-
assert(opts::LinuxKernelMode &&
211-
"process Linux Kernel special sections and their relocations only in "
212-
"linux kernel mode.\n");
210+
assert(BC.IsLinuxKernel && "Linux kernel binary expected.");
213211

214212
processLKExTable();
215213
processLKPCIFixup();
@@ -290,8 +288,9 @@ void LinuxKernelRewriter::processLKExTable() {
290288
void LinuxKernelRewriter::processLKPCIFixup() {
291289
ErrorOr<BinarySection &> SectionOrError =
292290
BC.getUniqueSectionByName(".pci_fixup");
293-
assert(SectionOrError &&
294-
".pci_fixup section not found in Linux Kernel binary");
291+
if (!SectionOrError)
292+
return;
293+
295294
const uint64_t SectionSize = SectionOrError->getSize();
296295
const uint64_t SectionAddress = SectionOrError->getAddress();
297296
assert((SectionSize % 16) == 0 && ".pci_fixup size is not a multiple of 16");

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -512,13 +512,19 @@ Error RewriteInstance::discoverStorage() {
512512
Phdr.p_offset,
513513
Phdr.p_filesz,
514514
Phdr.p_align};
515+
if (BC->TheTriple->getArch() == llvm::Triple::x86_64 &&
516+
Phdr.p_vaddr >= BinaryContext::KernelStartX86_64)
517+
BC->IsLinuxKernel = true;
515518
break;
516519
case ELF::PT_INTERP:
517520
BC->HasInterpHeader = true;
518521
break;
519522
}
520523
}
521524

525+
if (BC->IsLinuxKernel)
526+
outs() << "BOLT-INFO: Linux kernel binary detected\n";
527+
522528
for (const SectionRef &Section : InputFile->sections()) {
523529
Expected<StringRef> SectionNameOrErr = Section.getName();
524530
if (Error E = SectionNameOrErr.takeError())
@@ -562,7 +568,7 @@ Error RewriteInstance::discoverStorage() {
562568
if (opts::Hugify && !BC->HasFixedLoadAddress)
563569
NextAvailableAddress += BC->PageAlign;
564570

565-
if (!opts::UseGnuStack) {
571+
if (!opts::UseGnuStack && !BC->IsLinuxKernel) {
566572
// This is where the black magic happens. Creating PHDR table in a segment
567573
// other than that containing ELF header is tricky. Some loaders and/or
568574
// parts of loaders will apply e_phoff from ELF header assuming both are in
@@ -751,7 +757,7 @@ Error RewriteInstance::run() {
751757
if (opts::Instrument && !BC->IsStaticExecutable)
752758
updateRtFiniReloc();
753759

754-
if (opts::LinuxKernelMode) {
760+
if (BC->IsLinuxKernel) {
755761
errs() << "BOLT-WARNING: not writing the output file for Linux Kernel\n";
756762
return Error::success();
757763
} else if (opts::OutputFilename == "/dev/null") {
@@ -1284,7 +1290,7 @@ void RewriteInstance::discoverFileObjects() {
12841290
}
12851291
}
12861292

1287-
if (!opts::LinuxKernelMode) {
1293+
if (!BC->IsLinuxKernel) {
12881294
// Read all relocations now that we have binary functions mapped.
12891295
processRelocations();
12901296
}
@@ -1813,8 +1819,6 @@ Error RewriteInstance::readSpecialSections() {
18131819
<< "\n");
18141820
if (isDebugSection(SectionName))
18151821
HasDebugInfo = true;
1816-
if (isKSymtabSection(SectionName))
1817-
opts::LinuxKernelMode = true;
18181822
}
18191823

18201824
// Set IsRelro section attribute based on PT_GNU_RELRO segment.
@@ -3037,7 +3041,7 @@ void RewriteInstance::preprocessProfileData() {
30373041
}
30383042

30393043
void RewriteInstance::initializeMetadataManager() {
3040-
if (opts::LinuxKernelMode)
3044+
if (BC->IsLinuxKernel)
30413045
MetadataManager.registerRewriter(createLinuxKernelRewriter(*BC));
30423046

30433047
MetadataManager.registerRewriter(createPseudoProbeRewriter(*BC));

bolt/lib/Utils/CommandLineOpts.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ const char *BoltRevision =
2929
namespace opts {
3030

3131
bool HeatmapMode = false;
32-
bool LinuxKernelMode = false;
3332

3433
cl::OptionCategory BoltCategory("BOLT generic options");
3534
cl::OptionCategory BoltDiffCategory("BOLTDIFF generic options");

bolt/test/X86/linux-orc.s

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
## Check that BOLT correctly reads ORC unwind information used by Linux kernel.
44

55
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
6-
# RUN: %clang %cflags %t.o -o %t.exe
6+
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr
77

88
# RUN: llvm-bolt %t.exe --print-normalized --dump-orc --print-orc -o %t.out \
99
# RUN: |& FileCheck %s
1010

11+
# CHECK: BOLT-INFO: Linux kernel binary detected
1112
# CHECK: BOLT-INFO: ORC unwind information:
1213
# CHECK-NEXT: {sp: 8, bp: 0, info: 0x5}: _start
1314
# CHECK-NEXT: {sp: 0, bp: 0, info: 0x0}: _start
@@ -22,18 +23,15 @@
2223
.globl _start
2324
.type _start, %function
2425
_start:
25-
.cfi_startproc
2626

2727
call foo
2828
# CHECK: callq foo # ORC: {sp: 8, bp: 0, info: 0x5}
2929
ret
30-
.cfi_endproc
3130
.size _start, .-_start
3231

3332
.globl foo
3433
.type foo, %function
3534
foo:
36-
.cfi_startproc
3735
push %rbp
3836
# CHECK: pushq %rbp # ORC: {sp: 8, bp: 0, info: 0x5}
3937
.L1:
@@ -45,16 +43,13 @@ foo:
4543
.L3:
4644
ret
4745
# CHECK: retq # ORC: {sp: 8, bp: 0, info: 0x5}
48-
.cfi_endproc
4946
.size foo, .-foo
5047

5148
bar:
52-
.cfi_startproc
5349
ret
5450
## Same ORC info propagated from foo above.
5551
# CHECK: retq # ORC: {sp: 8, bp: 0, info: 0x5}
5652
.L4:
57-
.cfi_endproc
5853
.size bar, .-bar
5954

6055
.section .orc_unwind,"a",@progbits
@@ -131,4 +126,3 @@ bar:
131126
## Fake Linux Kernel sections.
132127
.section __ksymtab,"a",@progbits
133128
.section __ksymtab_gpl,"a",@progbits
134-
.section .pci_fixup,"a",@progbits

0 commit comments

Comments
 (0)