[llvm] [BOLT] Add rewriting support for Linux kernel __bug_table (PR #86908)
Maksim Panchenko via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 27 22:10:18 PDT 2024
https://github.com/maksfb created https://github.com/llvm/llvm-project/pull/86908
Update instruction locations in the __bug_table section after new code is emitted. If an instruction with associated bug ID was deleted, overwrite its location with zero.
>From 5633be89c007e4f02c86085e05870b105645f1bd Mon Sep 17 00:00:00 2001
From: Maksim Panchenko <maks at fb.com>
Date: Wed, 27 Mar 2024 22:03:24 -0700
Subject: [PATCH] [BOLT] Add rewriting support for Linux kernel __bug_table
Update instruction locations in the __bug_table section after new code
is emitted. If an instruction with associated bug ID was deleted,
overwrite its location with zero.
---
bolt/lib/Rewrite/LinuxKernelRewriter.cpp | 61 ++++++++++++++++++++++--
bolt/test/X86/linux-bug-table.s | 21 ++++++--
2 files changed, 74 insertions(+), 8 deletions(-)
diff --git a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp
index 42df9681727590..81ffa0542cb187 100644
--- a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp
+++ b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp
@@ -212,6 +212,11 @@ class LinuxKernelRewriter final : public MetadataRewriter {
/// Size of bug_entry struct.
static constexpr size_t BUG_TABLE_ENTRY_SIZE = 12;
+ /// List of bug entries per function.
+ using FunctionBugListType =
+ DenseMap<BinaryFunction *, SmallVector<uint32_t, 2>>;
+ FunctionBugListType FunctionBugList;
+
/// .pci_fixup section.
ErrorOr<BinarySection &> PCIFixupSection = std::errc::bad_address;
static constexpr size_t PCI_FIXUP_ENTRY_SIZE = 16;
@@ -254,7 +259,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
Error readParaInstructions();
Error rewriteParaInstructions();
+ /// __bug_table section handling.
Error readBugTable();
+ Error rewriteBugTable();
/// Do no process functions containing instruction annotated with
/// \p Annotation.
@@ -339,6 +346,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
if (Error E = rewriteStaticKeysJumpTable())
return E;
+ if (Error E = rewriteBugTable())
+ return E;
+
return Error::success();
}
@@ -1170,9 +1180,6 @@ Error LinuxKernelRewriter::rewriteParaInstructions() {
/// pointers use PC relative offset addressing), line number, and flags.
/// The definition of the struct bug_entry can be found in
/// `include/asm-generic/bug.h`
-///
-/// NB: find_bug() uses linear search to match an address to an entry in the bug
-/// table. Hence there is no need to sort entries when rewriting the table.
Error LinuxKernelRewriter::readBugTable() {
BugTableSection = BC.getUniqueSectionByName("__bug_table");
if (!BugTableSection)
@@ -1215,6 +1222,8 @@ Error LinuxKernelRewriter::readBugTable() {
" referenced by bug table entry %d",
InstAddress, EntryID);
BC.MIB->addAnnotation(*Inst, "BugEntry", EntryID);
+
+ FunctionBugList[BF].push_back(EntryID);
}
}
@@ -1223,6 +1232,52 @@ Error LinuxKernelRewriter::readBugTable() {
return Error::success();
}
+/// find_bug() uses linear search to match an address to an entry in the bug
+/// table. Hence, there is no need to sort entries when rewriting the table.
+/// When we need to erase an entry, we set its instruction address to zero.
+Error LinuxKernelRewriter::rewriteBugTable() {
+ if (!BugTableSection)
+ return Error::success();
+
+ for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) {
+ if (!BC.shouldEmit(BF))
+ continue;
+
+ if (!FunctionBugList.count(&BF))
+ continue;
+
+ // Bugs that will be emitted for this function.
+ DenseSet<uint32_t> EmittedIDs;
+ for (BinaryBasicBlock &BB : BF) {
+ for (MCInst &Inst : BB) {
+ if (!BC.MIB->hasAnnotation(Inst, "BugEntry"))
+ continue;
+ const uint32_t ID = BC.MIB->getAnnotationAs<uint32_t>(Inst, "BugEntry");
+ EmittedIDs.insert(ID);
+
+ // Create a relocation entry for this bug entry;
+ MCSymbol *Label =
+ BC.MIB->getOrCreateInstLabel(Inst, "__BUG_", BC.Ctx.get());
+ const uint64_t EntryOffset = (ID - 1) * BUG_TABLE_ENTRY_SIZE;
+ BugTableSection->addRelocation(EntryOffset, Label, ELF::R_X86_64_PC32,
+ /*Addend*/ 0);
+ }
+ }
+
+ // Clear bug entries that were not emitted for this function, e.g. as a
+ // result of DCE, but setting their instruction address to zero.
+ for (const uint32_t ID : FunctionBugList[&BF]) {
+ if (!EmittedIDs.count(ID)) {
+ const uint64_t EntryOffset = (ID - 1) * BUG_TABLE_ENTRY_SIZE;
+ BugTableSection->addRelocation(EntryOffset, nullptr, ELF::R_X86_64_PC32,
+ /*Addend*/ 0);
+ }
+ }
+ }
+
+ return Error::success();
+}
+
/// The kernel can replace certain instruction sequences depending on hardware
/// it is running on and features specified during boot time. The information
/// about alternative instruction sequences is stored in .altinstructions
diff --git a/bolt/test/X86/linux-bug-table.s b/bolt/test/X86/linux-bug-table.s
index e8de2fb6cba79d..f688a60c977191 100644
--- a/bolt/test/X86/linux-bug-table.s
+++ b/bolt/test/X86/linux-bug-table.s
@@ -1,6 +1,7 @@
# REQUIRES: system-linux
-## Check that BOLT correctly parses the Linux kernel __bug_table section.
+## Check that BOLT correctly parses and updates the Linux kernel __bug_table
+## section.
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
@@ -8,7 +9,13 @@
## Verify bug entry bindings to instructions.
-# RUN: llvm-bolt %t.exe --print-normalized -o %t.out | FileCheck %s
+# RUN: llvm-bolt %t.exe --print-normalized --print-only=_start -o %t.out \
+# RUN: --eliminate-unreachable=1 --bolt-info=0 | FileCheck %s
+
+## Verify bug entry bindings again after unreachable code elimination.
+
+# RUN: llvm-bolt %t.out -o %t.out.1 --print-only=_start --print-normalized \
+# RUN: |& FileCheck --check-prefix=CHECK-REOPT %s
# CHECK: BOLT-INFO: Linux kernel binary detected
# CHECK: BOLT-INFO: parsed 2 bug table entries
@@ -17,17 +24,21 @@
.globl _start
.type _start, %function
_start:
-# CHECK: Binary Function "_start"
- nop
+ jmp .L1
.L0:
ud2
# CHECK: ud2
# CHECK-SAME: BugEntry: 1
- nop
.L1:
ud2
# CHECK: ud2
# CHECK-SAME: BugEntry: 2
+
+## Only the second entry should remain after the first pass.
+
+# CHECK-REOPT: ud2
+# CHECK-REOPT-SAME: BugEntry: 2
+
ret
.size _start, .-_start
More information about the llvm-commits
mailing list