[X86] Emit .cfi_escape GNU_ARGS_SIZE when adjusting the stack before calls
When outgoing function arguments are passed using push instructions, and EH
is enabled, we may need to indicate to the stack unwinder that the stack
pointer was adjusted before the call.
This should fix the exception handling issues in PR24792.
Differential Revision: http://reviews.llvm.org/D13132
llvm-svn: 249522
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index f9dbd5a..a6c4e28 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -29,6 +29,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include <cctype>
@@ -210,6 +211,8 @@
void EmitCFISameValue(int64_t Register) override;
void EmitCFIRelOffset(int64_t Register, int64_t Offset) override;
void EmitCFIAdjustCfaOffset(int64_t Adjustment) override;
+ void EmitCFIEscape(StringRef Values) override;
+ void EmitCFIGnuArgsSize(int64_t Size) override;
void EmitCFISignalFrame() override;
void EmitCFIUndefined(int64_t Register) override;
void EmitCFIRegister(int64_t Register1, int64_t Register2) override;
@@ -1010,6 +1013,32 @@
EmitEOL();
}
+static void PrintCFIEscape(llvm::formatted_raw_ostream &OS, StringRef Values) {
+ OS << "\t.cfi_escape ";
+ if (!Values.empty()) {
+ size_t e = Values.size() - 1;
+ for (size_t i = 0; i < e; ++i)
+ OS << format("0x%02x", uint8_t(Values[i])) << ", ";
+ OS << format("0x%02x", uint8_t(Values[e]));
+ }
+}
+
+void MCAsmStreamer::EmitCFIEscape(StringRef Values) {
+ MCStreamer::EmitCFIEscape(Values);
+ PrintCFIEscape(OS, Values);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIGnuArgsSize(int64_t Size) {
+ MCStreamer::EmitCFIGnuArgsSize(Size);
+
+ uint8_t Buffer[16] = { dwarf::DW_CFA_GNU_args_size };
+ unsigned Len = encodeULEB128(Size, Buffer + 1) + 1;
+
+ PrintCFIEscape(OS, StringRef((const char *)&Buffer[0], Len));
+ EmitEOL();
+}
+
void MCAsmStreamer::EmitCFIDefCfaRegister(int64_t Register) {
MCStreamer::EmitCFIDefCfaRegister(Register);
OS << "\t.cfi_def_cfa_register ";
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index 58cf652..e964032 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -1147,6 +1147,11 @@
Streamer.EmitIntValue(dwarf::DW_CFA_restore | Reg, 1);
return;
}
+ case MCCFIInstruction::OpGnuArgsSize: {
+ Streamer.EmitIntValue(dwarf::DW_CFA_GNU_args_size, 1);
+ Streamer.EmitULEB128IntValue(Instr.getOffset());
+ return;
+ }
case MCCFIInstruction::OpEscape:
Streamer.EmitBytes(Instr.getValues());
return;
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index 5d76851..1ae1d51 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -359,6 +359,14 @@
CurFrame->Instructions.push_back(Instruction);
}
+void MCStreamer::EmitCFIGnuArgsSize(int64_t Size) {
+ MCSymbol *Label = EmitCFICommon();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createGnuArgsSize(Label, Size);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ CurFrame->Instructions.push_back(Instruction);
+}
+
void MCStreamer::EmitCFISignalFrame() {
EnsureValidDwarfFrame();
MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();