diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 934768c244b31..462f8a582d73e 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -3918,15 +3918,40 @@ 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 (BinarySection *Section : llvm::reverse(CodeSections)) { + 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..fa33c1eb342d6 --- /dev/null +++ b/bolt/test/code-at-high-address.c @@ -0,0 +1,24 @@ +// 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(); }