diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h --- a/bolt/include/bolt/Core/BinaryFunction.h +++ b/bolt/include/bolt/Core/BinaryFunction.h @@ -1074,6 +1074,14 @@ 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 --- a/bolt/lib/Core/BinaryEmitter.cpp +++ b/bolt/lib/Core/BinaryEmitter.cpp @@ -287,6 +287,11 @@ 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 --- /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: : +# 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