Skip to content

Commit f440b5c

Browse files
authored
[BOLT] Synchronize function and section order (#172419)
The order in which functions are emitted into the output file does not always reflect the order in which they will appear in the final file. This discrepancy occurs because code is emitted to different sections, such as `.text`, `.text.cold`, `.text.mover`, etc. To make passes that rely on the relative function order - such as `LongJmpPass` - more precise and functional, sort the output functions to reflect their final layout, and validate the layout after code sections are sorted. Note that, at this time, we only directly change the order of the main fragments of functions. The order of other fragments, such as cold and warm sections relative to other fragment types, is determined by the section order.
1 parent bc7b6b1 commit f440b5c

File tree

3 files changed

+53
-9
lines changed

3 files changed

+53
-9
lines changed

bolt/lib/Passes/BinaryPasses.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,19 @@ Error PopulateOutputFunctions::runOnFunctions(BinaryContext &BC) {
573573
llvm::copy(BC.getInjectedBinaryFunctions(),
574574
std::back_inserter(OutputFunctions));
575575

576+
// Place hot text movers in front.
577+
if (opts::HotText) {
578+
std::stable_partition(
579+
OutputFunctions.begin(), OutputFunctions.end(),
580+
[](const BinaryFunction *A) { return opts::isHotTextMover(*A); });
581+
}
582+
583+
if (opts::HotFunctionsAtEnd) {
584+
std::stable_partition(
585+
OutputFunctions.begin(), OutputFunctions.end(),
586+
[](const BinaryFunction *A) { return !A->hasValidIndex(); });
587+
}
588+
576589
return Error::success();
577590
}
578591

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4079,11 +4079,13 @@ std::vector<BinarySection *> RewriteInstance::getCodeSections() {
40794079
: (A->getName() < B->getName());
40804080
}
40814081

4082-
// Place movers before anything else.
4083-
if (A->getName() == BC->getHotTextMoverSectionName())
4084-
return true;
4085-
if (B->getName() == BC->getHotTextMoverSectionName())
4086-
return false;
4082+
// Place hot text movers before anything else.
4083+
if (opts::HotText) {
4084+
if (A->getName() == BC->getHotTextMoverSectionName())
4085+
return true;
4086+
if (B->getName() == BC->getHotTextMoverSectionName())
4087+
return false;
4088+
}
40874089

40884090
// Depending on opts::HotFunctionsAtEnd, place main and warm sections in
40894091
// order.
@@ -4105,6 +4107,28 @@ std::vector<BinarySection *> RewriteInstance::getCodeSections() {
41054107
// Determine the order of sections.
41064108
llvm::stable_sort(CodeSections, compareSections);
41074109

4110+
#ifndef NDEBUG
4111+
// Verify that the order of sections and functions is consistent.
4112+
uint32_t Index = 1;
4113+
for (BinarySection *Sec : CodeSections)
4114+
Sec->setIndex(Index++);
4115+
4116+
uint32_t LastIndex = 0;
4117+
for (const BinaryFunction *BF : BC->getOutputBinaryFunctions()) {
4118+
if (!BF->isEmitted() || BF->isPatch())
4119+
continue;
4120+
4121+
ErrorOr<BinarySection &> Sec = BF->getCodeSection();
4122+
if (!Sec)
4123+
continue;
4124+
4125+
assert(Sec->getIndex() >= LastIndex &&
4126+
"Section order does not match function order");
4127+
4128+
LastIndex = Sec->getIndex();
4129+
}
4130+
#endif
4131+
41084132
return CodeSections;
41094133
}
41104134

bolt/test/code-at-high-address.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55

66
// RUN: %clang %cflags -O0 %s -o %t -no-pie -Wl,-q -falign-functions=64 \
77
// RUN: -nostartfiles -nostdlib -ffreestanding
8-
// RUN: llvm-bolt %t -o %t.bolt --use-old-text --align-functions=1 \
9-
// RUN: --no-huge-pages --align-text=1 --use-gnu-stack --hot-functions-at-end \
10-
// RUN: | FileCheck %s --check-prefix=CHECK-BOLT
8+
// RUN: link_fdata %s %t %t.fdata
9+
// RUN: llvm-bolt %t -o %t.bolt --data %t.fdata --use-old-text \
10+
// RUN: --align-functions=1 --no-huge-pages --align-text=1 --use-gnu-stack \
11+
// RUN: --hot-functions-at-end | FileCheck %s --check-prefix=CHECK-BOLT
1112
// RUN: llvm-readelf --sections %t.bolt | FileCheck %s
1213

1314
// CHECK-BOLT: using original .text for new code with 0x1 alignment at {{.*}}
@@ -17,8 +18,14 @@
1718
// CHECK: .bolt.org.text PROGBITS
1819
// CHECK-NOT: {{ 000000 }}
1920
// CHECK-SAME: AX
21+
// CHECK-NEXT: .text.cold PROGBITS
2022
// CHECK-NEXT: .text PROGBITS
2123

24+
// FDATA: 0 [unknown] 0 1 foo 0 0 1
2225
int foo() { return 0; }
2326

24-
int main() { return foo(); }
27+
// Cold function.
28+
int bar() { return 42; }
29+
30+
// FDATA: 0 [unknown] 0 1 main 0 0 1
31+
int main(int argc, char **argv) { return argc ? foo() : bar(); }

0 commit comments

Comments
 (0)