diff --git a/llvm/include/llvm/MC/MCObjectStreamer.h b/llvm/include/llvm/MC/MCObjectStreamer.h index 2ceeba22abccd..aea93e9dc7e4f 100644 --- a/llvm/include/llvm/MC/MCObjectStreamer.h +++ b/llvm/include/llvm/MC/MCObjectStreamer.h @@ -40,6 +40,7 @@ class MCObjectStreamer : public MCStreamer { std::unique_ptr Assembler; bool EmitEHFrame; bool EmitDebugFrame; + bool EmitSFrame; struct PendingAssignment { MCSymbol *Symbol; @@ -70,7 +71,7 @@ class MCObjectStreamer : public MCStreamer { void emitFrames(MCAsmBackend *MAB); MCSymbol *emitCFILabel() override; - void emitCFISections(bool EH, bool Debug) override; + void emitCFISections(bool EH, bool Debug, bool SFrame) override; public: void visitUsedSymbol(const MCSymbol &Sym) override; diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h index 4bfc8f921ef11..dfaf3487e11a7 100644 --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -986,7 +986,7 @@ class LLVM_ABI MCStreamer { const MCSymbol *Lo); virtual MCSymbol *getDwarfLineTableSymbol(unsigned CUID); - virtual void emitCFISections(bool EH, bool Debug); + virtual void emitCFISections(bool EH, bool Debug, bool SFrame); void emitCFIStartProc(bool IsSimple, SMLoc Loc = SMLoc()); void emitCFIEndProc(); virtual void emitCFIDefCfa(int64_t Register, int64_t Offset, SMLoc Loc = {}); diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h index d95adf92b9a83..235d58d585b40 100644 --- a/llvm/include/llvm/MC/MCTargetOptions.h +++ b/llvm/include/llvm/MC/MCTargetOptions.h @@ -102,6 +102,9 @@ class MCTargetOptions { // functions on Darwins. bool EmitCompactUnwindNonCanonical : 1; + // Whether to emit SFrame unwind sections. + bool EmitSFrameUnwind : 1; + // Whether or not to use full register names on PowerPC. bool PPCUseFullRegisterNames : 1; diff --git a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h index b057effd88128..adfdccdb5ab77 100644 --- a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h +++ b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h @@ -40,6 +40,8 @@ LLVM_ABI EmitDwarfUnwindType getEmitDwarfUnwind(); LLVM_ABI bool getEmitCompactUnwindNonCanonical(); +LLVM_ABI bool getEmitSFrameUnwind(); + LLVM_ABI bool getShowMCInst(); LLVM_ABI bool getFatalWarnings(); diff --git a/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp b/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp index de6ebcf0c3419..51342c6b91345 100644 --- a/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp @@ -39,7 +39,7 @@ void ARMException::beginFunction(const MachineFunction *MF) { if (CFISecType == AsmPrinter::CFISection::Debug) { if (!hasEmittedCFISections) { if (Asm->getModuleCFISectionType() == AsmPrinter::CFISection::Debug) - Asm->OutStreamer->emitCFISections(false, true); + Asm->OutStreamer->emitCFISections(false, true, false); hasEmittedCFISections = true; } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp index 4fac4bbc98477..6b8d08cb201d6 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp @@ -109,9 +109,11 @@ void DwarfCFIException::beginBasicBlockSection(const MachineBasicBlock &MBB) { // chose not to be verbose in that case. And with `ForceDwarfFrameSection`, // we should always emit .debug_frame. if (CFISecType == AsmPrinter::CFISection::Debug || - Asm->TM.Options.ForceDwarfFrameSection) + Asm->TM.Options.ForceDwarfFrameSection || + Asm->TM.Options.MCOptions.EmitSFrameUnwind) Asm->OutStreamer->emitCFISections( - CFISecType == AsmPrinter::CFISection::EH, true); + CFISecType == AsmPrinter::CFISection::EH, true, + Asm->TM.Options.MCOptions.EmitSFrameUnwind); hasEmittedCFISections = true; } diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index 67c53e01a6111..7119ef4a2bbcd 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -345,7 +345,7 @@ class MCAsmStreamer final : public MCStreamer { void emitIdent(StringRef IdentString) override; void emitCFIBKeyFrame() override; void emitCFIMTETaggedFrame() override; - void emitCFISections(bool EH, bool Debug) override; + void emitCFISections(bool EH, bool Debug, bool SFrame) override; void emitCFIDefCfa(int64_t Register, int64_t Offset, SMLoc Loc) override; void emitCFIDefCfaOffset(int64_t Offset, SMLoc Loc) override; void emitCFIDefCfaRegister(int64_t Register, SMLoc Loc) override; @@ -1906,15 +1906,24 @@ void MCAsmStreamer::emitIdent(StringRef IdentString) { EmitEOL(); } -void MCAsmStreamer::emitCFISections(bool EH, bool Debug) { - MCStreamer::emitCFISections(EH, Debug); +void MCAsmStreamer::emitCFISections(bool EH, bool Debug, bool SFrame) { + MCStreamer::emitCFISections(EH, Debug, SFrame); OS << "\t.cfi_sections "; + bool C = false; if (EH) { OS << ".eh_frame"; - if (Debug) - OS << ", .debug_frame"; - } else if (Debug) { + C = true; + } + if (Debug) { + if (C) + OS << ", "; OS << ".debug_frame"; + C = true; + } + if (SFrame) { + if (C) + OS << ", "; + OS << ".sframe"; } EmitEOL(); diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp index 42f4cf49d7f38..d7f4be1bfb573 100644 --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -130,10 +130,11 @@ void MCObjectStreamer::visitUsedSymbol(const MCSymbol &Sym) { Assembler->registerSymbol(Sym); } -void MCObjectStreamer::emitCFISections(bool EH, bool Debug) { - MCStreamer::emitCFISections(EH, Debug); +void MCObjectStreamer::emitCFISections(bool EH, bool Debug, bool SFrame) { + MCStreamer::emitCFISections(EH, Debug, SFrame); EmitEHFrame = EH; EmitDebugFrame = Debug; + EmitSFrame = SFrame; } void MCObjectStreamer::emitValueImpl(const MCExpr *Value, unsigned Size, diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index d0b6ea4cfd562..eda5e8c37f7b8 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -4093,27 +4093,30 @@ bool AsmParser::parseDirectiveCVFPOData() { } /// parseDirectiveCFISections -/// ::= .cfi_sections section [, section] +/// ::= .cfi_sections section [, section][, section] bool AsmParser::parseDirectiveCFISections() { StringRef Name; bool EH = false; bool Debug = false; + bool SFrame = false; if (!parseOptionalToken(AsmToken::EndOfStatement)) { for (;;) { if (parseIdentifier(Name)) - return TokError("expected .eh_frame or .debug_frame"); + return TokError("expected .eh_frame, .debug_frame, or .sframe"); if (Name == ".eh_frame") EH = true; else if (Name == ".debug_frame") Debug = true; + else if (Name == ".sframe") + SFrame = true; if (parseOptionalToken(AsmToken::EndOfStatement)) break; if (parseComma()) return true; } } - getStreamer().emitCFISections(EH, Debug); + getStreamer().emitCFISections(EH, Debug, SFrame); return false; } diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp index 30198c97d8ab9..e14a32f5dc0ce 100644 --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -415,7 +415,7 @@ void MCStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) { void MCStreamer::emitConditionalAssignment(MCSymbol *Symbol, const MCExpr *Value) {} -void MCStreamer::emitCFISections(bool EH, bool Debug) {} +void MCStreamer::emitCFISections(bool EH, bool Debug, bool SFrame) {} void MCStreamer::emitCFIStartProc(bool IsSimple, SMLoc Loc) { if (!FrameInfoStack.empty() && diff --git a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp index 2adc29172f9dd..ff95ff78fd53a 100644 --- a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp +++ b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp @@ -41,6 +41,7 @@ MCOPT(int, DwarfVersion) MCOPT(bool, Dwarf64) MCOPT(EmitDwarfUnwindType, EmitDwarfUnwind) MCOPT(bool, EmitCompactUnwindNonCanonical) +MCOPT(bool, EmitSFrameUnwind) MCOPT(bool, ShowMCInst) MCOPT(bool, FatalWarnings) MCOPT(bool, NoWarn) @@ -105,6 +106,11 @@ llvm::mc::RegisterMCTargetOptionsFlags::RegisterMCTargetOptionsFlags() { false)); // By default, use DWARF for non-canonical personalities. MCBINDOPT(EmitCompactUnwindNonCanonical); + static cl::opt EmitSFrameUnwind( + "gsframe", cl::desc("Whether to emit .sframe unwind sections."), + cl::init(false)); + MCBINDOPT(EmitSFrameUnwind); + static cl::opt ShowMCInst( "asm-show-inst", cl::desc("Emit internal instruction representation to assembly file")); @@ -188,6 +194,7 @@ MCTargetOptions llvm::mc::InitMCTargetOptionsFromFlags() { Options.X86Sse2Avx = getX86Sse2Avx(); Options.EmitDwarfUnwind = getEmitDwarfUnwind(); Options.EmitCompactUnwindNonCanonical = getEmitCompactUnwindNonCanonical(); + Options.EmitSFrameUnwind = getEmitSFrameUnwind(); Options.AsSecureLogFile = getAsSecureLogFile(); return Options; diff --git a/llvm/test/MC/ELF/AArch64/cfi.s b/llvm/test/MC/ELF/AArch64/cfi.s index 6bdf03cc7bb85..7047f92bab8fe 100644 --- a/llvm/test/MC/ELF/AArch64/cfi.s +++ b/llvm/test/MC/ELF/AArch64/cfi.s @@ -557,12 +557,14 @@ f37: // CHECK-NEXT: } .ifdef ERR -// ERR: [[#@LINE+1]]:15: error: expected .eh_frame or .debug_frame +// ERR: [[#@LINE+1]]:15: error: expected .eh_frame, .debug_frame, or .sframe .cfi_sections $ // ERR: [[#@LINE+1]]:28: error: expected comma .cfi_sections .debug_frame $ // ERR: [[#@LINE+1]]:39: error: expected comma .cfi_sections .debug_frame, .eh_frame $ +// ERR: [[#@LINE+1]]:48: error: expected comma +.cfi_sections .debug_frame, .eh_frame, .sframe $ // ERR: [[#@LINE+1]]:16: error: unexpected token .cfi_startproc $ diff --git a/llvm/test/MC/ELF/cfi.s b/llvm/test/MC/ELF/cfi.s index 3bd16aec4613e..b7f937104dbf2 100644 --- a/llvm/test/MC/ELF/cfi.s +++ b/llvm/test/MC/ELF/cfi.s @@ -445,12 +445,14 @@ f37: // CHECK: } .ifdef ERR -// ERR: [[#@LINE+1]]:15: error: expected .eh_frame or .debug_frame +// ERR: [[#@LINE+1]]:15: error: expected .eh_frame, .debug_frame, or .sframe .cfi_sections $ // ERR: [[#@LINE+1]]:28: error: expected comma .cfi_sections .debug_frame $ // ERR: [[#@LINE+1]]:39: error: expected comma .cfi_sections .debug_frame, .eh_frame $ +// ERR: [[#@LINE+1]]:48: error: expected comma +.cfi_sections .debug_frame, .eh_frame, .sframe $ // ERR: [[#@LINE+1]]:16: error: unexpected token .cfi_startproc $