From 11749964c7de7611cd107ca6b93d101ccead3945 Mon Sep 17 00:00:00 2001 From: Maksim Panchenko Date: Fri, 13 Sep 2024 21:33:37 -0700 Subject: [PATCH 1/2] [BOLT] Push code to higher addresses under options When --hot-functions-at-end is used in combination with --use-old-text, allocate code at the highest possible addresses withing old .text. This feature is mostly useful for HHVM, where it is beneficial to have hot static code placed as close as possible to jitted code. --- bolt/lib/Rewrite/RewriteInstance.cpp | 33 +++++++++++++++++++++++++--- bolt/test/code-at-high-address.c | 28 +++++++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 bolt/test/code-at-high-address.c diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 934768c244b31..241b50b0bf793 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -3918,15 +3918,42 @@ void RewriteInstance::mapCodeSections(BOLTLinker::SectionMapper MapSection) { return Address; }; + // Try to allocate sections before the \p Address and return an address for + // the allocation of the first section, or 0 if [0, Address) range is not + // big enough to fit all sections. + auto allocateBefore = [&](uint64_t Address) -> uint64_t { + for (auto SI = CodeSections.rbegin(), SE = CodeSections.rend(); SI != SE; + ++SI) { + BinarySection *Section = *SI; + if (Section->getOutputSize() > Address) + return 0; + Address -= Section->getOutputSize(); + Address = alignDown(Address, Section->getAlignment()); + Section->setOutputAddress(Address); + } + return Address; + }; + // Check if we can fit code in the original .text bool AllocationDone = false; if (opts::UseOldText) { - const uint64_t CodeSize = - allocateAt(BC->OldTextSectionAddress) - BC->OldTextSectionAddress; + uint64_t StartAddress; + uint64_t EndAddress; + if (opts::HotFunctionsAtEnd) { + EndAddress = BC->OldTextSectionAddress + BC->OldTextSectionSize; + StartAddress = allocateBefore(EndAddress); + } else { + StartAddress = BC->OldTextSectionAddress; + EndAddress = allocateAt(BC->OldTextSectionAddress); + } + const uint64_t CodeSize = EndAddress - StartAddress; if (CodeSize <= BC->OldTextSectionSize) { BC->outs() << "BOLT-INFO: using original .text for new code with 0x" - << Twine::utohexstr(opts::AlignText) << " alignment\n"; + << Twine::utohexstr(opts::AlignText) << " alignment"; + if (StartAddress != BC->OldTextSectionAddress) + BC->outs() << " at 0x" << Twine::utohexstr(StartAddress); + BC->outs() << '\n'; AllocationDone = true; } else { BC->errs() diff --git a/bolt/test/code-at-high-address.c b/bolt/test/code-at-high-address.c new file mode 100644 index 0000000000000..9954e2c02e007 --- /dev/null +++ b/bolt/test/code-at-high-address.c @@ -0,0 +1,28 @@ +// Check that llvm-bolt pushes code to higher addresses under +// --hot-functions-at-end when rewriting code in-place. + +// REQUIRES: system-linux + +// RUN: %clang %cflags -O0 %s -o %t -no-pie -Wl,-q -falign-functions=64 \ +// RUN: -nostartfiles -nostdlib -ffreestanding +// RUN: llvm-bolt %t -o %t.bolt --use-old-text --align-functions=1 \ +// RUN: --no-huge-pages --align-text=1 --use-gnu-stack --hot-functions-at-end \ +// RUN: | FileCheck %s --check-prefix=CHECK-BOLT +// RUN: llvm-readelf --sections %t.bolt | FileCheck %s + +// CHECK-BOLT: using original .text for new code with 0x1 alignment at {{.*}} + +// As .text is pushed higher, preceding .bolt.org.text should have non-zero +// size. +// CHECK: .bolt.org.text PROGBITS +// CHECK-NOT: {{ 000000 }} +// CHECK-SAME: AX +// CHECK-NEXT: .text PROGBITS + +int foo() { + return 0; +} + +int main() { + return foo(); +} From 61f18ebcf7859d8daf6cad43f8cd69cea6ce49ed Mon Sep 17 00:00:00 2001 From: Maksim Panchenko Date: Sat, 28 Jun 2025 12:31:13 -0700 Subject: [PATCH 2/2] Fix format and address suggestion. --- bolt/lib/Rewrite/RewriteInstance.cpp | 4 +--- bolt/test/code-at-high-address.c | 8 ++------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 241b50b0bf793..462f8a582d73e 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -3922,9 +3922,7 @@ void RewriteInstance::mapCodeSections(BOLTLinker::SectionMapper MapSection) { // the allocation of the first section, or 0 if [0, Address) range is not // big enough to fit all sections. auto allocateBefore = [&](uint64_t Address) -> uint64_t { - for (auto SI = CodeSections.rbegin(), SE = CodeSections.rend(); SI != SE; - ++SI) { - BinarySection *Section = *SI; + for (BinarySection *Section : llvm::reverse(CodeSections)) { if (Section->getOutputSize() > Address) return 0; Address -= Section->getOutputSize(); diff --git a/bolt/test/code-at-high-address.c b/bolt/test/code-at-high-address.c index 9954e2c02e007..fa33c1eb342d6 100644 --- a/bolt/test/code-at-high-address.c +++ b/bolt/test/code-at-high-address.c @@ -19,10 +19,6 @@ // CHECK-SAME: AX // CHECK-NEXT: .text PROGBITS -int foo() { - return 0; -} +int foo() { return 0; } -int main() { - return foo(); -} +int main() { return foo(); }