Index: include/llvm/MC/MCDwarf.h =================================================================== --- include/llvm/MC/MCDwarf.h +++ include/llvm/MC/MCDwarf.h @@ -599,6 +599,7 @@ bool IsSignalFrame = false; bool IsSimple = false; unsigned RAReg = static_cast(INT_MAX); + bool IsBKeyFrame = false; }; class MCDwarfFrameEmitter { Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -806,6 +806,8 @@ Optional Source, unsigned CUID = 0); + virtual void EmitCFIBKeyFrame(); + /// This implements the DWARF2 '.loc fileno lineno ...' assembler /// directive. virtual void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, Index: lib/DebugInfo/DWARF/DWARFDebugFrame.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugFrame.cpp +++ lib/DebugInfo/DWARF/DWARFDebugFrame.cpp @@ -446,6 +446,11 @@ StartAugmentationOffset = Offset; EndAugmentationOffset = Offset + static_cast(*AugmentationLength); + break; + case 'B': + // B-Key is used for signing functions associated with this + // augmentation string + break; } } Index: lib/MC/MCAsmStreamer.cpp =================================================================== --- lib/MC/MCAsmStreamer.cpp +++ lib/MC/MCAsmStreamer.cpp @@ -266,6 +266,7 @@ void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc L) override; void EmitIdent(StringRef IdentString) override; + void EmitCFIBKeyFrame() override; void EmitCFISections(bool EH, bool Debug) override; void EmitCFIDefCfa(int64_t Register, int64_t Offset) override; void EmitCFIDefCfaOffset(int64_t Offset) override; @@ -1599,6 +1600,12 @@ EmitEOL(); } +void MCAsmStreamer::EmitCFIBKeyFrame() { + MCStreamer::EmitCFIBKeyFrame(); + OS << "\t.cfi_b_key_frame"; + EmitEOL(); +} + void MCAsmStreamer::EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) { MCStreamer::EmitWinCFIStartProc(Symbol, Loc); Index: lib/MC/MCDwarf.cpp =================================================================== --- lib/MC/MCDwarf.cpp +++ lib/MC/MCDwarf.cpp @@ -1565,9 +1565,8 @@ uint8_t CIEVersion = getCIEVersion(IsEH, context.getDwarfVersion()); Streamer.EmitIntValue(CIEVersion, 1); - // Augmentation String - SmallString<8> Augmentation; if (IsEH) { + SmallString<8> Augmentation; Augmentation += "z"; if (Frame.Personality) Augmentation += "P"; @@ -1576,6 +1575,8 @@ Augmentation += "R"; if (Frame.IsSignalFrame) Augmentation += "S"; + if (Frame.IsBKeyFrame) + Augmentation += "B"; Streamer.EmitBytes(Augmentation); } Streamer.EmitIntValue(0, 1); @@ -1730,25 +1731,28 @@ struct CIEKey { static const CIEKey getEmptyKey() { - return CIEKey(nullptr, 0, -1, false, false, static_cast(INT_MAX)); + return CIEKey(nullptr, 0, -1, false, false, static_cast(INT_MAX), + false); } static const CIEKey getTombstoneKey() { - return CIEKey(nullptr, -1, 0, false, false, static_cast(INT_MAX)); + return CIEKey(nullptr, -1, 0, false, false, static_cast(INT_MAX), + false); } CIEKey(const MCSymbol *Personality, unsigned PersonalityEncoding, unsigned LSDAEncoding, bool IsSignalFrame, bool IsSimple, - unsigned RAReg) + unsigned RAReg, bool IsBKeyFrame) : Personality(Personality), PersonalityEncoding(PersonalityEncoding), LsdaEncoding(LSDAEncoding), IsSignalFrame(IsSignalFrame), - IsSimple(IsSimple), RAReg(RAReg) {} + IsSimple(IsSimple), RAReg(RAReg), IsBKeyFrame(IsBKeyFrame) {} explicit CIEKey(const MCDwarfFrameInfo &Frame) : Personality(Frame.Personality), PersonalityEncoding(Frame.PersonalityEncoding), LsdaEncoding(Frame.LsdaEncoding), IsSignalFrame(Frame.IsSignalFrame), - IsSimple(Frame.IsSimple), RAReg(Frame.RAReg) {} + IsSimple(Frame.IsSimple), RAReg(Frame.RAReg), + IsBKeyFrame(Frame.IsBKeyFrame) {} const MCSymbol *Personality; unsigned PersonalityEncoding; @@ -1756,6 +1760,7 @@ bool IsSignalFrame; bool IsSimple; unsigned RAReg; + bool IsBKeyFrame; }; } // end anonymous namespace @@ -1767,9 +1772,9 @@ static CIEKey getTombstoneKey() { return CIEKey::getTombstoneKey(); } static unsigned getHashValue(const CIEKey &Key) { - return static_cast( - hash_combine(Key.Personality, Key.PersonalityEncoding, Key.LsdaEncoding, - Key.IsSignalFrame, Key.IsSimple, Key.RAReg)); + return static_cast(hash_combine( + Key.Personality, Key.PersonalityEncoding, Key.LsdaEncoding, + Key.IsSignalFrame, Key.IsSimple, Key.RAReg, Key.IsBKeyFrame)); } static bool isEqual(const CIEKey &LHS, const CIEKey &RHS) { @@ -1777,8 +1782,8 @@ LHS.PersonalityEncoding == RHS.PersonalityEncoding && LHS.LsdaEncoding == RHS.LsdaEncoding && LHS.IsSignalFrame == RHS.IsSignalFrame && - LHS.IsSimple == RHS.IsSimple && - LHS.RAReg == RHS.RAReg; + LHS.IsSimple == RHS.IsSimple && LHS.RAReg == RHS.RAReg && + LHS.IsBKeyFrame == RHS.IsBKeyFrame; } }; Index: lib/MC/MCParser/AsmParser.cpp =================================================================== --- lib/MC/MCParser/AsmParser.cpp +++ lib/MC/MCParser/AsmParser.cpp @@ -495,6 +495,7 @@ DK_CFI_UNDEFINED, DK_CFI_REGISTER, DK_CFI_WINDOW_SAVE, + DK_CFI_B_KEY_FRAME, DK_MACROS_ON, DK_MACROS_OFF, DK_ALTMACRO, @@ -5293,6 +5294,7 @@ DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED; DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER; DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE; + DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME; DirectiveKindMap[".macros_on"] = DK_MACROS_ON; DirectiveKindMap[".macros_off"] = DK_MACROS_OFF; DirectiveKindMap[".macro"] = DK_MACRO; Index: lib/MC/MCStreamer.cpp =================================================================== --- lib/MC/MCStreamer.cpp +++ lib/MC/MCStreamer.cpp @@ -221,6 +221,13 @@ Source); } +void MCStreamer::EmitCFIBKeyFrame() { + MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; + CurFrame->IsBKeyFrame = true; +} + void MCStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column, unsigned Flags, unsigned Isa, Index: lib/Target/AArch64/AArch64AsmPrinter.cpp =================================================================== --- lib/Target/AArch64/AArch64AsmPrinter.cpp +++ lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -716,6 +716,19 @@ OutStreamer->EmitRawText(StringRef(OS.str())); } return; + + case AArch64::EMITBKEY: { + ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType(); + if (ExceptionHandlingType != ExceptionHandling::DwarfCFI && + ExceptionHandlingType != ExceptionHandling::ARM) + return; + + if (needsCFIMoves() == CFI_M_None) + return; + + OutStreamer->EmitCFIBKeyFrame(); + return; + } } // Tail calls use pseudo instructions so they have the proper code-gen Index: lib/Target/AArch64/AArch64FrameLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64FrameLowering.cpp +++ lib/Target/AArch64/AArch64FrameLowering.cpp @@ -816,10 +816,15 @@ DebugLoc DL; if (ShouldSignReturnAddress(MF)) { - BuildMI( - MBB, MBBI, DL, - TII->get(ShouldSignWithAKey(MF) ? AArch64::PACIASP : AArch64::PACIBSP)) - .setMIFlag(MachineInstr::FrameSetup); + if (ShouldSignWithAKey(MF)) + BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIASP)) + .setMIFlag(MachineInstr::FrameSetup); + else { + BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITBKEY)) + .setMIFlag(MachineInstr::FrameSetup); + BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIBSP)) + .setMIFlag(MachineInstr::FrameSetup); + } unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr)); Index: lib/Target/AArch64/AArch64InstrInfo.td =================================================================== --- lib/Target/AArch64/AArch64InstrInfo.td +++ lib/Target/AArch64/AArch64InstrInfo.td @@ -1619,6 +1619,10 @@ let AsmString = ".tlsdesccall $sym"; } +// Pseudo instruction to tell the streamer to emit a 'B' character into the +// augmentation string. +def EMITBKEY : Pseudo<(outs), (ins), []>, Sched<[]> {} + // FIXME: maybe the scratch register used shouldn't be fixed to X1? // FIXME: can "hasSideEffects be dropped? let isCall = 1, Defs = [LR, X0, X1], hasSideEffects = 1, Index: lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp =================================================================== --- lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -176,6 +176,7 @@ bool parseDirectiveReq(StringRef Name, SMLoc L); bool parseDirectiveUnreq(SMLoc L); bool parseDirectiveCFINegateRAState(); + bool parseDirectiveCFIBKeyFrame(); bool validateInstruction(MCInst &Inst, SMLoc &IDLoc, SmallVectorImpl &Loc); @@ -5030,6 +5031,8 @@ parseDirectiveInst(Loc); else if (IDVal == ".cfi_negate_ra_state") parseDirectiveCFINegateRAState(); + else if (IDVal == ".cfi_b_key_frame") + parseDirectiveCFIBKeyFrame(); else if (IsMachO) { if (IDVal == MCLOHDirectiveName()) parseDirectiveLOH(IDVal, Loc); @@ -5410,6 +5413,16 @@ return false; } +/// parseDirectiveCFIBKeyFrame +/// ::= .cfi_b_key +bool AArch64AsmParser::parseDirectiveCFIBKeyFrame() { + if (parseToken(AsmToken::EndOfStatement, + "unexpected token in '.cfi_b_key_frame'")) + return true; + getStreamer().EmitCFIBKeyFrame(); + return false; +} + bool AArch64AsmParser::classifySymbolRef(const MCExpr *Expr, AArch64MCExpr::VariantKind &ELFRefKind, Index: test/CodeGen/MIR/AArch64/return-address-signing.mir =================================================================== --- /dev/null +++ test/CodeGen/MIR/AArch64/return-address-signing.mir @@ -0,0 +1,48 @@ +# RUN: llc -mtriple=aarch64-arm-none-eabi -run-pass=prologepilog -o - %s 2>&1 | FileCheck %s +--- | + target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" + target triple = "aarch64-arm-none-eabi" + + define dso_local i32 @foo() "sign-return-address"="all" "sign-return-address-key"="a_key" { + entry: + ret i32 2 + } + + define dso_local i32 @bar() "sign-return-address"="all" "sign-return-address-key"="b_key" { + entry: + ret i32 2 + } +... +--- +#CHECK: foo +name: foo +alignment: 2 +tracksRegLiveness: true +frameInfo: + maxCallFrameSize: 0 +#CHECK: frame-setup PACIASP implicit-def $lr, implicit $lr, implicit $sp +#CHECK: frame-setup CFI_INSTRUCTION negate_ra_sign_state +#CHECK: frame-destroy AUTIASP implicit-def $lr, implicit $lr, implicit $sp +body: | + bb.0.entry: + $w0 = MOVi32imm 2 + RET_ReallyLR implicit killed $w0 + +... +--- +#CHECK: bar +name: bar +alignment: 2 +tracksRegLiveness: true +frameInfo: + maxCallFrameSize: 0 +#CHECK: frame-setup EMITBKEY +#CHECK: frame-setup PACIBSP implicit-def $lr, implicit $lr, implicit $sp +#CHECK: frame-setup CFI_INSTRUCTION negate_ra_sign_state +#CHECK: frame-destroy AUTIBSP implicit-def $lr, implicit $lr, implicit $sp +body: | + bb.0.entry: + $w0 = MOVi32imm 2 + RET_ReallyLR implicit killed $w0 + +... Index: test/DebugInfo/AArch64/return-address-signing.ll =================================================================== --- /dev/null +++ test/DebugInfo/AArch64/return-address-signing.ll @@ -0,0 +1,27 @@ +; RUN: llc -mtriple=aarch64-arm-none-eabi < %s -filetype=obj -o - \ +; RUN: | llvm-dwarfdump -v - | FileCheck -check-prefix=CHECK %s + +;CHECK: CIE +;CHECK: Augmentation: "zR" +define i32 @foo() "sign-return-address"="all" { + ret i32 0 +} + +;CHECK: CIE +;CHECK: Augmentation: "zRB" + +define i32 @bar() "sign-return-address"="all" "sign-return-address-key"="b_key" { + ret i32 0 +} + +;CHECK-NOT: CIE + +define i32 @baz() "sign-return-address"="all" nounwind { + ret i32 0 +} + +;CHECK-NOT: CIE + +define i32 @qux() "sign-return-address"="all" "sign-return-address-key"="b_key" nounwind { + ret i32 0 +} Index: test/MC/ELF/cfi-b-key-frame.s =================================================================== --- /dev/null +++ test/MC/ELF/cfi-b-key-frame.s @@ -0,0 +1,6 @@ +// RUN: llvm-mc -filetype=obj -triple aarch64-arm-none-eabi %s -o - | llvm-dwarfdump - -v | FileCheck %s +#CHECK: Augmentation: "zRB" +f1: + .cfi_startproc + .cfi_b_key_frame + .cfi_endproc