Skip to content

[BOLT] Push code to higher addresses under options #146180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 28, 2025
Merged

Conversation

maksfb
Copy link
Contributor

@maksfb maksfb commented Jun 28, 2025

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.

@llvmbot
Copy link
Member

llvmbot commented Jun 28, 2025

@llvm/pr-subscribers-bolt

Author: Maksim Panchenko (maksfb)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/146180.diff

2 Files Affected:

  • (modified) bolt/lib/Rewrite/RewriteInstance.cpp (+30-3)
  • (added) bolt/test/code-at-high-address.test (+19)
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.test b/bolt/test/code-at-high-address.test
new file mode 100644
index 0000000000000..4181133c573ef
--- /dev/null
+++ b/bolt/test/code-at-high-address.test
@@ -0,0 +1,19 @@
+## 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 %p/Inputs/hello.c -o %t -no-pie -Wl,-q
+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

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.
Copy link

github-actions bot commented Jun 28, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Contributor

@aaupov aaupov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General question: with use-old-text and hot-functions-at-end, what's in the space that is not used? Is it the original code, or emitted padding/traps?

@maksfb
Copy link
Contributor Author

maksfb commented Jun 28, 2025

General question: with use-old-text and hot-functions-at-end, what's in the space that is not used? Is it the original code, or emitted padding/traps?

Remnants of the old code. It's the same as without --hot-functions-at-end, just on the other side.

@maksfb maksfb merged commit fb24b4d into llvm:main Jun 28, 2025
7 checks passed
rlavaee pushed a commit to rlavaee/llvm-project that referenced this pull request Jul 1, 2025
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.
rlavaee pushed a commit to rlavaee/llvm-project that referenced this pull request Jul 1, 2025
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants