-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[BOLT] Push code to higher addresses under options #146180
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-bolt Author: Maksim Panchenko (maksfb) ChangesWhen --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:
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.
You can test this locally with the following command:git-clang-format --diff HEAD~1 HEAD --extensions cpp,c -- bolt/test/code-at-high-address.c bolt/lib/Rewrite/RewriteInstance.cpp View the diff from clang-format here.diff --git a/bolt/test/code-at-high-address.c b/bolt/test/code-at-high-address.c
index 9954e2c02..fa33c1eb3 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(); }
|
There was a problem hiding this 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?
for (auto SI = CodeSections.rbegin(), SE = CodeSections.rend(); SI != SE; | ||
++SI) { | ||
BinarySection *Section = *SI; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (auto SI = CodeSections.rbegin(), SE = CodeSections.rend(); SI != SE; | |
++SI) { | |
BinarySection *Section = *SI; | |
for (BinarySection *Section : llvm::reverse(CodeSections)) { |
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.