Skip to content

Commit 06f13f8

Browse files
authored
[BOLT] Fix references in ignored functions in CFG state (#140678)
When we call setIgnored() on functions that already have CFG built, these functions are not going to get emitted and we risk missing external function references being updated. To mitigate the potential issues, run scanExternalRefs() on such functions to create patches/relocations. Since scanExternalRefs() relies on function relocations, we have to preserve relocations until the function is emitted. As a result, the memory overhead without debug info update could reach up to 2%.
1 parent eb9ed93 commit 06f13f8

File tree

6 files changed

+102
-14
lines changed

6 files changed

+102
-14
lines changed

bolt/include/bolt/Core/BinaryFunction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,6 +2348,7 @@ class BinaryFunction {
23482348
releaseCFG();
23492349
CurrentState = State::Emitted;
23502350
}
2351+
clearList(Relocations);
23512352
}
23522353

23532354
/// Process LSDA information for the function.

bolt/lib/Core/BinaryContext.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,10 +1032,8 @@ void BinaryContext::adjustCodePadding() {
10321032

10331033
if (!hasValidCodePadding(BF)) {
10341034
if (HasRelocations) {
1035-
if (opts::Verbosity >= 1) {
1036-
this->outs() << "BOLT-INFO: function " << BF
1037-
<< " has invalid padding. Ignoring the function.\n";
1038-
}
1035+
this->errs() << "BOLT-WARNING: function " << BF
1036+
<< " has invalid padding. Ignoring the function\n";
10391037
BF.setIgnored();
10401038
} else {
10411039
BF.setMaxSize(BF.getSize());

bolt/lib/Core/BinaryFunction.cpp

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,8 +1526,6 @@ Error BinaryFunction::disassemble() {
15261526
if (uint64_t Offset = getFirstInstructionOffset())
15271527
Labels[Offset] = BC.Ctx->createNamedTempSymbol();
15281528

1529-
clearList(Relocations);
1530-
15311529
if (!IsSimple) {
15321530
clearList(Instructions);
15331531
return createNonFatalBOLTError("");
@@ -3244,16 +3242,26 @@ void BinaryFunction::setTrapOnEntry() {
32443242
}
32453243

32463244
void BinaryFunction::setIgnored() {
3245+
IsIgnored = true;
3246+
32473247
if (opts::processAllFunctions()) {
32483248
// We can accept ignored functions before they've been disassembled.
3249-
// In that case, they would still get disassembled and emited, but not
3249+
// In that case, they would still get disassembled and emitted, but not
32503250
// optimized.
3251-
assert(CurrentState == State::Empty &&
3252-
"cannot ignore non-empty functions in current mode");
3253-
IsIgnored = true;
3251+
if (CurrentState != State::Empty) {
3252+
BC.errs() << "BOLT-ERROR: cannot ignore non-empty function " << *this
3253+
<< " in current mode\n";
3254+
exit(1);
3255+
}
32543256
return;
32553257
}
32563258

3259+
IsSimple = false;
3260+
LLVM_DEBUG(dbgs() << "Ignoring " << getPrintName() << '\n');
3261+
3262+
if (CurrentState == State::Empty)
3263+
return;
3264+
32573265
clearDisasmState();
32583266

32593267
// Clear CFG state too.
@@ -3273,9 +3281,11 @@ void BinaryFunction::setIgnored() {
32733281

32743282
CurrentState = State::Empty;
32753283

3276-
IsIgnored = true;
3277-
IsSimple = false;
3278-
LLVM_DEBUG(dbgs() << "Ignoring " << getPrintName() << '\n');
3284+
// Fix external references in the original function body.
3285+
if (BC.HasRelocations) {
3286+
LLVM_DEBUG(dbgs() << "Scanning refs in " << *this << '\n');
3287+
scanExternalRefs();
3288+
}
32793289
}
32803290

32813291
void BinaryFunction::duplicateConstantIslands() {
@@ -3764,7 +3774,6 @@ void BinaryFunction::postProcessBranches() {
37643774

37653775
MCSymbol *BinaryFunction::addEntryPointAtOffset(uint64_t Offset) {
37663776
assert(Offset && "cannot add primary entry point");
3767-
assert(CurrentState == State::Empty || CurrentState == State::Disassembled);
37683777

37693778
const uint64_t EntryPointAddress = getAddress() + Offset;
37703779
MCSymbol *LocalSymbol = getOrCreateLocalLabel(EntryPointAddress);
@@ -3773,6 +3782,8 @@ MCSymbol *BinaryFunction::addEntryPointAtOffset(uint64_t Offset) {
37733782
if (EntrySymbol)
37743783
return EntrySymbol;
37753784

3785+
assert(CurrentState == State::Empty || CurrentState == State::Disassembled);
3786+
37763787
if (BinaryData *EntryBD = BC.getBinaryDataAtAddress(EntryPointAddress)) {
37773788
EntrySymbol = EntryBD->getSymbol();
37783789
} else {

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3446,6 +3446,7 @@ void RewriteInstance::disassembleFunctions() {
34463446
BC->outs() << "BOLT-INFO: could not disassemble function " << Function
34473447
<< ". Will ignore.\n";
34483448
// Forcefully ignore the function.
3449+
Function.scanExternalRefs();
34493450
Function.setIgnored();
34503451
});
34513452

bolt/test/AArch64/patch-ignored.s

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
## Check that llvm-bolt patches functions that are getting ignored after their
2+
## CFG was constructed.
3+
4+
# RUN: %clang %cflags %s -o %t.exe -Wl,-q
5+
# RUN: llvm-bolt %t.exe -o %t.bolt --force-patch 2>&1 | FileCheck %s
6+
# RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=CHECK-OBJDUMP
7+
8+
.text
9+
10+
## The function is too small to be patched and BOLT is forced to ignore it under
11+
## --force-patch. Check that the reference to _start is updated.
12+
# CHECK: BOLT-WARNING: failed to patch entries in unpatchable
13+
.globl unpatchable
14+
.type unpatchable, %function
15+
unpatchable:
16+
.cfi_startproc
17+
# CHECK-OBJDUMP: <unpatchable>:
18+
# CHECK-OBJDUMP-NEXT: bl {{.*}} <_start>
19+
bl _start
20+
ret
21+
.cfi_endproc
22+
.size unpatchable, .-unpatchable
23+
24+
.globl _start
25+
.type _start, %function
26+
_start:
27+
.cfi_startproc
28+
cmp x0, 1
29+
b.eq .L0
30+
.L0:
31+
ret x30
32+
.cfi_endproc
33+
.size _start, .-_start

bolt/test/X86/patch-ignored.s

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
## Check that llvm-bolt patches functions that are getting ignored after their
2+
## CFG was constructed.
3+
4+
# RUN: %clang %cflags %s -o %t.exe -Wl,-q
5+
# RUN: llvm-bolt %t.exe -o %t.bolt 2>&1 | FileCheck %s
6+
# RUN: llvm-objdump -d %t.bolt | FileCheck %s --check-prefix=CHECK-OBJDUMP
7+
8+
.text
9+
10+
## After the CFG is built, the following function will be marked as ignored
11+
## due to the presence of the internal call.
12+
# CHECK: BOLT-WARNING: will skip the following function
13+
# CHECK-NEXT: internal_call
14+
.globl internal_call
15+
.type internal_call, %function
16+
internal_call:
17+
.cfi_startproc
18+
# CHECK-OBJDUMP: <internal_call>:
19+
call .L1
20+
jmp .L2
21+
# CHECK-OBJDUMP: jmp
22+
.L1:
23+
jmp _start
24+
# CHECK-OBJDUMP: jmp
25+
# CHECK-OBJDUMP-SAME: <_start>
26+
ret
27+
.L2:
28+
jmp _start
29+
# CHECK-OBJDUMP: jmp
30+
# CHECK-OBJDUMP-SAME: <_start>
31+
.cfi_endproc
32+
.size internal_call, .-internal_call
33+
34+
.globl _start
35+
.type _start, %function
36+
_start:
37+
.cfi_startproc
38+
cmpq %rdi, 1
39+
jne .L0
40+
movq %rdi, %rax
41+
.L0:
42+
ret
43+
.cfi_endproc
44+
.size _start, .-_start

0 commit comments

Comments
 (0)