[llvm] [BOLT] Zero alignment padding when reusing old text section (PR #202375)
YongKang Zhu via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 8 08:56:52 PDT 2026
https://github.com/yozhu created https://github.com/llvm/llvm-project/pull/202375
With --use-old-text, the output starts as a byte-for-byte copy of the input. Alignment padding between sections could retain stale data from the original binary. Zero the padding so the result matches writing sections to new file offsets.
>From 2c7179145dd744cf693318b40abcb5c7cef362ae Mon Sep 17 00:00:00 2001
From: YongKang Zhu <yongzhu at fb.com>
Date: Thu, 28 May 2026 16:21:20 -0700
Subject: [PATCH] [BOLT] Zero alignment padding when reusing old text section
Summary:
With --use-old-text, the output starts as a byte-for-byte copy of the
input. Alignment padding between sections could retain stale data from
the original binary. Zero the padding so the result matches writing
sections to new file offsets.
---
bolt/include/bolt/Rewrite/RewriteInstance.h | 5 +++
bolt/lib/Rewrite/RewriteInstance.cpp | 44 +++++++++++++++++++
bolt/test/AArch64/use-old-text-zero-padding.c | 43 ++++++++++++++++++
3 files changed, 92 insertions(+)
create mode 100644 bolt/test/AArch64/use-old-text-zero-padding.c
diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h
index 166336cbb8fcf..3873d944e01ba 100644
--- a/bolt/include/bolt/Rewrite/RewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/RewriteInstance.h
@@ -231,6 +231,11 @@ class RewriteInstance {
/// Used by non-relocation mode and for patched functions.
void rewriteFunctionsInPlace(raw_fd_ostream &OS);
+ /// When --use-old-text reuses input file regions, zero the alignment
+ /// padding after BOLT-written text sections so the output does not retain
+ /// stale bytes from the input binary.
+ void zeroPaddingForReusedSections(raw_fd_ostream &OS);
+
/// Return address of a function in the new binary corresponding to
/// \p OldAddress address in the original binary.
uint64_t getNewFunctionAddress(uint64_t OldAddress);
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 9364e32939982..dabbf04797314 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -6286,6 +6286,47 @@ void RewriteInstance::rewriteFunctionsInPlace(raw_fd_ostream &OS) {
}
}
+void RewriteInstance::zeroPaddingForReusedSections(raw_fd_ostream &OS) {
+ // The output starts as a byte-for-byte copy of the input, so alignment
+ // padding after BOLT-written sections could retain stale data from the
+ // original binary. Zero the padding as if we were writing sections onto
+ // new file offset (i.e., not reusing old existing sections).
+
+ // Collect file offsets of all sections (allocatable and non-allocatable)
+ // that occupy file bytes.
+ SmallVector<uint64_t, 16> SectionStarts;
+ for (BinarySection &Section : BC->sections()) {
+ if (Section.isVirtual())
+ continue;
+ uint64_t Offset = Section.getOutputFileOffset();
+ if (!Offset)
+ Offset = Section.getInputFileOffset();
+ if (Offset)
+ SectionStarts.push_back(Offset);
+ }
+ llvm::sort(SectionStarts);
+
+ uint64_t SavedPos = OS.tell();
+ for (BinarySection &Section : BC->allocatableSections()) {
+ if (!Section.isFinalized() || !Section.getOutputData())
+ continue;
+ if (Section.isLinkOnly() || !Section.getOutputSize())
+ continue;
+ if (!(Section.getELFFlags() & ELF::SHF_EXECINSTR))
+ continue;
+ uint64_t SecEnd = Section.getOutputFileOffset() + Section.getOutputSize();
+ auto It = llvm::upper_bound(SectionStarts, SecEnd - 1);
+ if (It != SectionStarts.end()) {
+ uint64_t NextStart = *It;
+ if (NextStart > SecEnd) {
+ OS.seek(SecEnd);
+ OS.write_zeros(NextStart - SecEnd);
+ }
+ }
+ }
+ OS.seek(SavedPos);
+}
+
void RewriteInstance::rewriteFile() {
std::error_code EC;
Out = std::make_unique<ToolOutputFile>(opts::OutputFilename, EC,
@@ -6375,6 +6416,9 @@ void RewriteInstance::rewriteFile() {
// Copy non-allocatable sections once allocatable part is finished.
rewriteNoteSections();
+ if (opts::UseOldText)
+ zeroPaddingForReusedSections(OS);
+
if (BC->HasRelocations) {
patchELFAllocatableRelaSections();
patchELFAllocatableRelrSection();
diff --git a/bolt/test/AArch64/use-old-text-zero-padding.c b/bolt/test/AArch64/use-old-text-zero-padding.c
new file mode 100644
index 0000000000000..9e1d4231c0c84
--- /dev/null
+++ b/bolt/test/AArch64/use-old-text-zero-padding.c
@@ -0,0 +1,43 @@
+// Verify that BOLT will zero pad section end when --use-old-text
+// is specified, such that there won't be stale instructions left
+// there from input library.
+
+// RUN: rm -rf %t && split-file %s %t
+
+// Use a linker script to force section ordering .text -> .rodata so
+// the test can locate the padding immediately after .text.
+
+// RUN: %clang %cflags -falign-functions=64 \
+// RUN: -Wl,--script=%t/script.ld %t/test.c -o %t/test -Wl,-q
+// RUN: llvm-bolt %t/test -o %t/test.bolt --use-old-text --align-text=4
+
+// RUN: llvm-objdump -s -j .rodata %t/test.bolt \
+// RUN: | FileCheck %s --check-prefix=RODATA
+
+// RODATA: 55555555 aaaaaaaa 33333333 cccccccc
+
+// Input was built with -falign-functions=64; BOLT writes a more compact
+// .text (--align-text=4) into the old region, leaving unused file space
+// between the new .text end and the next section. Verify those gap bytes
+// are zeroed. Padding starts at end-of-.text file offset = sh_offset +
+// sh_size (read from llvm-readelf section headers).
+
+// RUN: llvm-readelf -S %t/test.bolt | awk '$3==".text"{print $6, $7}' \
+// RUN: > %t/txt-loc
+// RUN: bash -c "read O S < %t/txt-loc; \
+// RUN: od -A x -t x1 -N 0x20 -j \$((0x\$O + 0x\$S)) %t/test.bolt" \
+// RUN: | FileCheck %s --check-prefix=PADDING
+
+// PADDING: {{[0-9a-f]+}} 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+//--- script.ld
+SECTIONS { .rodata : { *(.rodata) *(.rodata.*) } } INSERT AFTER .text;
+
+//--- test.c
+__attribute__((used))
+const unsigned data[] = {0x55555555, 0xaaaaaaaa, 0x33333333, 0xcccccccc};
+
+__attribute__((used, noinline)) int foo(int x, int y) { return x + y; }
+__attribute__((used, noinline)) int bar(int x, int y) { return x ^ y; }
+
+int _start(void) { return foo(1, 2) + bar(3, 4); }
More information about the llvm-commits
mailing list