aboutsummaryrefslogtreecommitdiff
path: root/bolt
diff options
context:
space:
mode:
authorMaksim Panchenko <maks@fb.com>2022-09-15 13:31:52 -0700
committerMaksim Panchenko <maks@fb.com>2022-09-16 13:38:32 -0700
commit9742c25b9894d4805e05369c50cc8e0562a3cb92 (patch)
tree0d75ada1c6854cb9677812f43f37f2fede02ed8f /bolt
parent1076b31da8da8854e1dfca8f1a9a03de9fd4f8f5 (diff)
downloadllvm-9742c25b9894d4805e05369c50cc8e0562a3cb92.zip
llvm-9742c25b9894d4805e05369c50cc8e0562a3cb92.tar.gz
llvm-9742c25b9894d4805e05369c50cc8e0562a3cb92.tar.bz2
[BOLT] Fix empty function emission in non-relocation mode
In non-relocation mode, every function is emitted in its own section. If a function is empty, RuntimeDyld will still allocate 1-byte section for the function and initialize it with zero. As a result, we will overwrite the first byte of the original function contents with zero. Such scenario can happen when the input function had only NOP instructions which BOLT removes by default. Even though such functions likely cause undefined behavior, it's better to preserve their contents. Reviewed By: yota9 Differential Revision: https://reviews.llvm.org/D133978
Diffstat (limited to 'bolt')
-rw-r--r--bolt/include/bolt/Core/BinaryFunction.h8
-rw-r--r--bolt/lib/Core/BinaryEmitter.cpp5
-rw-r--r--bolt/test/X86/nop-function.s30
3 files changed, 43 insertions, 0 deletions
diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h
index c2a21cb..96633f59 100644
--- a/bolt/include/bolt/Core/BinaryFunction.h
+++ b/bolt/include/bolt/Core/BinaryFunction.h
@@ -1074,6 +1074,14 @@ public:
return N;
}
+ /// Return true if function has instructions to emit.
+ bool hasNonPseudoInstructions() const {
+ for (const BinaryBasicBlock &BB : blocks())
+ if (BB.getNumNonPseudos() > 0)
+ return true;
+ return false;
+ }
+
/// Return MC symbol associated with the function.
/// All references to the function should use this symbol.
MCSymbol *getSymbol(const FragmentNum Fragment = FragmentNum::main()) {
diff --git a/bolt/lib/Core/BinaryEmitter.cpp b/bolt/lib/Core/BinaryEmitter.cpp
index bc5bcad..98c9943 100644
--- a/bolt/lib/Core/BinaryEmitter.cpp
+++ b/bolt/lib/Core/BinaryEmitter.cpp
@@ -287,6 +287,11 @@ bool BinaryEmitter::emitFunction(BinaryFunction &Function,
if (Function.getState() == BinaryFunction::State::Empty)
return false;
+ // Avoid emitting function without instructions when overwriting the original
+ // function in-place. Otherwise, emit the empty function to define the symbol.
+ if (!BC.HasRelocations && !Function.hasNonPseudoInstructions())
+ return false;
+
MCSection *Section =
BC.getCodeSection(Function.getCodeSectionName(FF.getFragmentNum()));
Streamer.switchSection(Section);
diff --git a/bolt/test/X86/nop-function.s b/bolt/test/X86/nop-function.s
new file mode 100644
index 0000000..44d997a
--- /dev/null
+++ b/bolt/test/X86/nop-function.s
@@ -0,0 +1,30 @@
+## Check that BOLT preserves nop instruction if it's the only instruction
+## in a function.
+
+# REQUIRES: system-linux
+
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe -q
+# RUN: llvm-bolt %t.exe -o %t.bolt.exe --relocs=0
+# RUN: llvm-objdump -d %t.bolt.exe | FileCheck %s
+
+ .text
+ .globl nop_function
+ .type nop_function,@function
+nop_function:
+ .cfi_startproc
+ nop
+# CHECK: <nop_function>:
+# CHECK-NEXT: nop
+
+ .size nop_function, .-nop_function
+ .cfi_endproc
+
+
+ .globl _start
+ .type _start,@function
+_start:
+ .cfi_startproc
+ call nop_function
+ .size _start, .-_start
+ .cfi_endproc