diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 0ad59b2c153ae..af0e086540146 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2080,12 +2080,19 @@ def NotTailCalled : InheritableAttr { def : MutualExclusions<[AlwaysInline, NotTailCalled]>; def NoStackProtector : InheritableAttr { - let Spellings = [Clang<"no_stack_protector">]; + let Spellings = [Clang<"no_stack_protector">, Declspec<"safebuffers">]; let Subjects = SubjectList<[Function]>; let Documentation = [NoStackProtectorDocs]; let SimpleHandler = 1; } +def StrictGuardStackCheck : InheritableAttr { + let Spellings = [Declspec<"strict_gs_check">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [StrictGuardStackCheckDocs]; + let SimpleHandler = 1; +} + def NoThrow : InheritableAttr { let Spellings = [GCC<"nothrow">, Declspec<"nothrow">]; let Subjects = SubjectList<[FunctionLike]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 68f1268ed7da9..b6c15c92d5815 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -4453,7 +4453,8 @@ spelled "XYZ" in the `OpenMP 5.1 Standard`_). def NoStackProtectorDocs : Documentation { let Category = DocCatFunction; let Content = [{ -Clang supports the ``__attribute__((no_stack_protector))`` attribute which disables +Clang supports the ``__attribute__((no_stack_protector))`` and Microsoft style +``__declspec(safebuffers)`` attribute which disables the stack protector on the specified function. This attribute is useful for selectively disabling the stack protector on some functions when building with ``-fstack-protector`` compiler option. @@ -4472,6 +4473,27 @@ option. }]; } +def StrictGuardStackCheckDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the Microsoft style ``__declspec((strict_gs_check))`` attribute +which upgrades the stack protector check from ``-fstack-protector`` to +``-fstack-protector-strong``. + +For example, it upgrades the stack protector for the function ``foo`` to +``-fstack-protector-strong`` but function ``bar`` will still be built with the +stack protector with the ``-fstack-protector`` option. + +.. code-block:: c + + __declspec((strict_gs_check)) + int foo(int x); // stack protection will be upgraded for foo. + + int bar(int y); // bar can be built with the standard stack protector checks. + + }]; +} + def NotTailCalledDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index f9087cdd5d4dc..ad6eb32ccc649 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1957,14 +1957,17 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, if (!hasUnwindExceptions(LangOpts)) B.addAttribute(llvm::Attribute::NoUnwind); - if (!D || !D->hasAttr()) { - if (LangOpts.getStackProtector() == LangOptions::SSPOn) - B.addAttribute(llvm::Attribute::StackProtect); - else if (LangOpts.getStackProtector() == LangOptions::SSPStrong) - B.addAttribute(llvm::Attribute::StackProtectStrong); - else if (LangOpts.getStackProtector() == LangOptions::SSPReq) - B.addAttribute(llvm::Attribute::StackProtectReq); - } + if (D && D->hasAttr()) + ; // Do nothing. + else if (D && D->hasAttr() && + LangOpts.getStackProtector() == LangOptions::SSPOn) + B.addAttribute(llvm::Attribute::StackProtectStrong); + else if (LangOpts.getStackProtector() == LangOptions::SSPOn) + B.addAttribute(llvm::Attribute::StackProtect); + else if (LangOpts.getStackProtector() == LangOptions::SSPStrong) + B.addAttribute(llvm::Attribute::StackProtectStrong); + else if (LangOpts.getStackProtector() == LangOptions::SSPReq) + B.addAttribute(llvm::Attribute::StackProtectReq); if (!D) { // If we don't have a declaration to control inlining, the function isn't diff --git a/clang/test/Parser/MicrosoftExtensions.c b/clang/test/Parser/MicrosoftExtensions.c index 92cfb042ac22e..619f90990212c 100644 --- a/clang/test/Parser/MicrosoftExtensions.c +++ b/clang/test/Parser/MicrosoftExtensions.c @@ -5,7 +5,7 @@ typedef int (__cdecl *tptr)(void); void (*__fastcall fastpfunc)(void); extern __declspec(dllimport) void __stdcall VarR4FromDec(void); __declspec(deprecated) __declspec(deprecated) char * __cdecl ltoa( long _Val, char * _DstBuf, int _Radix); -__declspec(safebuffers) __declspec(noalias) __declspec(restrict) void * __cdecl xxx(void *_Memory); /* expected-warning{{__declspec attribute 'safebuffers' is not supported}} */ +__declspec(safebuffers) __declspec(noalias) __declspec(restrict) void * __cdecl xxx(void *_Memory); typedef __w64 unsigned long ULONG_PTR, *PULONG_PTR; void * __ptr64 PtrToPtr64(const void *p) { diff --git a/llvm/include/llvm/BinaryFormat/COFF.h b/llvm/include/llvm/BinaryFormat/COFF.h index 08a8b48bdcb81..c9b1174c9eaa2 100644 --- a/llvm/include/llvm/BinaryFormat/COFF.h +++ b/llvm/include/llvm/BinaryFormat/COFF.h @@ -772,6 +772,23 @@ enum CodeViewIdentifiers { DEBUG_HASHES_SECTION_MAGIC = 0x133C9C5 }; +// These flags show up in the @feat.00 symbol. They appear to be some kind of +// compiler features bitfield read by link.exe. +enum Feat00Flags : uint32_t { + // Object is compatible with /safeseh. + SafeSEH = 0x1, + // Object was compiled with /GS. + GuardStack = 0x100, + // Object was compiled with /sdl. + SDL = 0x200, + // Object was compiled with /guard:cf. + GuardCF = 0x800, + // Object was compiled with /guard:ehcont. + GuardEHCont = 0x4000, + // Object was compiled with /kernel. + Kernel = 0x40000000, +}; + inline bool isReservedSectionNumber(int32_t SectionNumber) { return SectionNumber <= 0; } diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 16213aff4788a..a97eb9f7847e1 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1498,8 +1498,16 @@ void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) { FPO |= FrameProcedureOptions::MarkedInline; if (GV.hasFnAttribute(Attribute::Naked)) FPO |= FrameProcedureOptions::Naked; - if (MFI.hasStackProtectorIndex()) + if (MFI.hasStackProtectorIndex()) { FPO |= FrameProcedureOptions::SecurityChecks; + if (GV.hasFnAttribute(Attribute::StackProtectStrong) || + GV.hasFnAttribute(Attribute::StackProtectReq)) { + FPO |= FrameProcedureOptions::StrictSecurityChecks; + } + } else if (!GV.hasStackProtectorFnAttr()) { + // __declspec(safebuffers) disables stack guards. + FPO |= FrameProcedureOptions::SafeBuffers; + } FPO |= FrameProcedureOptions(uint32_t(CurFn->EncodedLocalFramePtrReg) << 14U); FPO |= FrameProcedureOptions(uint32_t(CurFn->EncodedParamFramePtrReg) << 16U); if (Asm->TM.getOptLevel() != CodeGenOpt::None && diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 9d0b4e2539cc1..6a065871107ed 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -201,30 +201,32 @@ void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) { const Triple &TT = TM.getTargetTriple(); if (TT.isOSBinFormatCOFF()) { - // Emit an absolute @feat.00 symbol. This appears to be some kind of - // compiler features bitfield read by link.exe. + // Emit an absolute @feat.00 symbol MCSymbol *S = MMI->getContext().getOrCreateSymbol(StringRef("@feat.00")); OutStreamer->beginCOFFSymbolDef(S); OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC); OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_NULL); OutStreamer->endCOFFSymbolDef(); - int64_t Feat00Flags = 0; + int64_t Feat00Value = 0; if (M.getModuleFlag("cfguard")) { - Feat00Flags |= 0x800; // Object is CFG-aware. + // Object is CFG-aware. + Feat00Value |= COFF::Feat00Flags::GuardCF; } if (M.getModuleFlag("ehcontguard")) { - Feat00Flags |= 0x4000; // Object also has EHCont. + // Object also has EHCont. + Feat00Value |= COFF::Feat00Flags::GuardEHCont; } if (M.getModuleFlag("ms-kernel")) { - Feat00Flags |= 0x40000000; // Object is compiled with /kernel. + // Object is compiled with /kernel. + Feat00Value |= COFF::Feat00Flags::Kernel; } OutStreamer->emitSymbolAttribute(S, MCSA_Global); OutStreamer->emitAssignment( - S, MCConstantExpr::create(Feat00Flags, MMI->getContext())); + S, MCConstantExpr::create(Feat00Value, MMI->getContext())); } if (!TT.isOSBinFormatELF()) diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp index 968e68050a407..1c8375dcd1714 100644 --- a/llvm/lib/Target/X86/X86AsmPrinter.cpp +++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp @@ -792,14 +792,13 @@ void X86AsmPrinter::emitStartOfAsmFile(Module &M) { OutStreamer->switchSection(getObjFileLowering().getTextSection()); if (TT.isOSBinFormatCOFF()) { - // Emit an absolute @feat.00 symbol. This appears to be some kind of - // compiler features bitfield read by link.exe. + // Emit an absolute @feat.00 symbol. MCSymbol *S = MMI->getContext().getOrCreateSymbol(StringRef("@feat.00")); OutStreamer->beginCOFFSymbolDef(S); OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC); OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_NULL); OutStreamer->endCOFFSymbolDef(); - int64_t Feat00Flags = 0; + int64_t Feat00Value = 0; if (TT.getArch() == Triple::x86) { // According to the PE-COFF spec, the LSB of this value marks the object @@ -807,24 +806,27 @@ void X86AsmPrinter::emitStartOfAsmFile(Module &M) { // must be registered in .sxdata. Use of any unregistered handlers will // cause the process to terminate immediately. LLVM does not know how to // register any SEH handlers, so its object files should be safe. - Feat00Flags |= 1; + Feat00Value |= COFF::Feat00Flags::SafeSEH; } if (M.getModuleFlag("cfguard")) { - Feat00Flags |= 0x800; // Object is CFG-aware. + // Object is CFG-aware. + Feat00Value |= COFF::Feat00Flags::GuardCF; } if (M.getModuleFlag("ehcontguard")) { - Feat00Flags |= 0x4000; // Object also has EHCont. + // Object also has EHCont. + Feat00Value |= COFF::Feat00Flags::GuardEHCont; } if (M.getModuleFlag("ms-kernel")) { - Feat00Flags |= 0x40000000; // Object is compiled with /kernel. + // Object is compiled with /kernel. + Feat00Value |= COFF::Feat00Flags::Kernel; } OutStreamer->emitSymbolAttribute(S, MCSA_Global); OutStreamer->emitAssignment( - S, MCConstantExpr::create(Feat00Flags, MMI->getContext())); + S, MCConstantExpr::create(Feat00Value, MMI->getContext())); } OutStreamer->emitSyntaxDirective(); diff --git a/llvm/test/DebugInfo/COFF/frameproc-flags.ll b/llvm/test/DebugInfo/COFF/frameproc-flags.ll index 567000c24c9f2..145886dadd0d8 100644 --- a/llvm/test/DebugInfo/COFF/frameproc-flags.ll +++ b/llvm/test/DebugInfo/COFF/frameproc-flags.ll @@ -65,7 +65,7 @@ ; CHECK-LABEL: S_GPROC32_ID [size = 52] `use_alloca` ; CHECK: S_FRAMEPROC [size = 32] ; CHECK: local fp reg = VFRAME, param fp reg = EBP -; CHECK: flags = has alloca | secure checks | opt speed +; CHECK: flags = has alloca | secure checks | strict secure checks | opt speed ; CHECK-LABEL: S_GPROC32_ID [size = 52] `call_setjmp` ; CHECK: S_FRAMEPROC [size = 32] ; CHECK: local fp reg = NONE, param fp reg = NONE @@ -73,7 +73,7 @@ ; CHECK-LABEL: S_GPROC32_ID [size = 56] `use_inlineasm` ; CHECK: S_FRAMEPROC [size = 32] ; CHECK: local fp reg = NONE, param fp reg = NONE -; CHECK: flags = has inline asm | opt speed +; CHECK: flags = has inline asm | safe buffers | opt speed ; CHECK-LABEL: S_GPROC32_ID [size = 48] `cpp_eh` ; CHECK: S_FRAMEPROC [size = 32] ; CHECK: local fp reg = EBP, param fp reg = EBP @@ -81,11 +81,11 @@ ; CHECK-LABEL: S_GPROC32_ID [size = 52] `use_inline` ; CHECK: S_FRAMEPROC [size = 32] ; CHECK: local fp reg = NONE, param fp reg = NONE -; CHECK: flags = opt speed +; CHECK: flags = safe buffers | opt speed ; CHECK-LABEL: S_LPROC32_ID [size = 56] `is_marked_inline` ; CHECK: S_FRAMEPROC [size = 32] ; CHECK: local fp reg = NONE, param fp reg = NONE -; CHECK: flags = marked inline | opt speed +; CHECK: flags = marked inline | safe buffers | opt speed ; CHECK-LABEL: S_GPROC32_ID [size = 44] `seh` ; CHECK: S_FRAMEPROC [size = 32] ; CHECK: local fp reg = EBP, param fp reg = EBP @@ -93,15 +93,15 @@ ; CHECK-LABEL: S_LPROC32_ID [size = 56] `?filt$0@0@seh@@` ; CHECK: S_FRAMEPROC [size = 32] ; CHECK: local fp reg = EBP, param fp reg = EBP -; CHECK: flags = opt speed +; CHECK: flags = safe buffers | opt speed ; CHECK-LABEL: S_GPROC32_ID [size = 52] `use_naked` ; CHECK: S_FRAMEPROC [size = 32] ; CHECK: local fp reg = NONE, param fp reg = NONE -; CHECK: flags = has inline asm | naked | opt speed +; CHECK: flags = has inline asm | naked | safe buffers | opt speed ; CHECK-LABEL: S_GPROC32_ID [size = 52] `stack_guard` ; CHECK: S_FRAMEPROC [size = 32] ; CHECK: local fp reg = VFRAME, param fp reg = EBP -; CHECK: flags = secure checks | opt speed +; CHECK: flags = secure checks | strict secure checks | opt speed ; ModuleID = 'frameproc-flags.cpp' source_filename = "frameproc-flags.cpp" diff --git a/llvm/test/DebugInfo/COFF/multifunction.ll b/llvm/test/DebugInfo/COFF/multifunction.ll index fa93b13497563..98b0e4b2d8a05 100644 --- a/llvm/test/DebugInfo/COFF/multifunction.ll +++ b/llvm/test/DebugInfo/COFF/multifunction.ll @@ -91,7 +91,7 @@ ; X86-NEXT: .long 0 # Bytes of callee saved registers ; X86-NEXT: .long 0 # Exception handler offset ; X86-NEXT: .short 0 # Exception handler section -; X86-NEXT: .long 0 # Flags (defines frame register) +; X86-NEXT: .long 8192 # Flags (defines frame register) ; X86-NEXT: .p2align 2 ; X86-NEXT: [[FPROC_END]]: ; X86-NEXT: .short 2 @@ -130,7 +130,7 @@ ; X86-NEXT: .long 0 # Bytes of callee saved registers ; X86-NEXT: .long 0 # Exception handler offset ; X86-NEXT: .short 0 # Exception handler section -; X86-NEXT: .long 0 # Flags (defines frame register) +; X86-NEXT: .long 8192 # Flags (defines frame register) ; X86-NEXT: .p2align 2 ; X86-NEXT: [[FPROC_END]]: ; X86-NEXT: .short 2 @@ -169,7 +169,7 @@ ; X86-NEXT: .long 0 # Bytes of callee saved registers ; X86-NEXT: .long 0 # Exception handler offset ; X86-NEXT: .short 0 # Exception handler section -; X86-NEXT: .long 0 # Flags (defines frame register) +; X86-NEXT: .long 8192 # Flags (defines frame register) ; X86-NEXT: .p2align 2 ; X86-NEXT: [[FPROC_END]]: ; X86-NEXT: .short 2 @@ -403,7 +403,7 @@ ; X64-NEXT: .long 0 # Bytes of callee saved registers ; X64-NEXT: .long 0 # Exception handler offset ; X64-NEXT: .short 0 # Exception handler section -; X64-NEXT: .long 81920 # Flags (defines frame register) +; X64-NEXT: .long 90112 # Flags (defines frame register) ; X64-NEXT: .p2align 2 ; X64-NEXT: [[FPROC_END]]: ; X64-NEXT: .short 2 @@ -441,7 +441,7 @@ ; X64-NEXT: .long 0 # Bytes of callee saved registers ; X64-NEXT: .long 0 # Exception handler offset ; X64-NEXT: .short 0 # Exception handler section -; X64-NEXT: .long 81920 # Flags (defines frame register) +; X64-NEXT: .long 90112 # Flags (defines frame register) ; X64-NEXT: .p2align 2 ; X64-NEXT: [[FPROC_END]]: ; X64-NEXT: .short 2 @@ -479,7 +479,7 @@ ; X64-NEXT: .long 0 # Bytes of callee saved registers ; X64-NEXT: .long 0 # Exception handler offset ; X64-NEXT: .short 0 # Exception handler section -; X64-NEXT: .long 81920 # Flags (defines frame register) +; X64-NEXT: .long 90112 # Flags (defines frame register) ; X64-NEXT: .p2align 2 ; X64-NEXT: [[FPROC_END]]: ; X64-NEXT: .short 2 diff --git a/llvm/test/DebugInfo/COFF/simple.ll b/llvm/test/DebugInfo/COFF/simple.ll index 70878ac33ef1d..85819b0d990ee 100644 --- a/llvm/test/DebugInfo/COFF/simple.ll +++ b/llvm/test/DebugInfo/COFF/simple.ll @@ -71,7 +71,7 @@ ; X86-NEXT: .long 0 # Bytes of callee saved registers ; X86-NEXT: .long 0 # Exception handler offset ; X86-NEXT: .short 0 # Exception handler section -; X86-NEXT: .long 0 # Flags (defines frame register) +; X86-NEXT: .long 8192 # Flags (defines frame register) ; X86-NEXT: .p2align 2 ; X86-NEXT: [[FPROC_END]]: ; X86-NEXT: .short 2 @@ -201,7 +201,7 @@ ; X64-NEXT: .long 0 # Bytes of callee saved registers ; X64-NEXT: .long 0 # Exception handler offset ; X64-NEXT: .short 0 # Exception handler section -; X64-NEXT: .long 81920 # Flags (defines frame register) +; X64-NEXT: .long 90112 # Flags (defines frame register) ; X64-NEXT: .p2align 2 ; X64-NEXT: [[FPROC_END]]: ; X64-NEXT: .short 2 diff --git a/llvm/test/DebugInfo/COFF/vframe-fpo.ll b/llvm/test/DebugInfo/COFF/vframe-fpo.ll index 599d9f07f9d59..2e3d8754968ae 100644 --- a/llvm/test/DebugInfo/COFF/vframe-fpo.ll +++ b/llvm/test/DebugInfo/COFF/vframe-fpo.ll @@ -125,7 +125,8 @@ ; CODEVIEW-NEXT: BytesOfCalleeSavedRegisters: 0xC ; CODEVIEW-NEXT: OffsetOfExceptionHandler: 0x0 ; CODEVIEW-NEXT: SectionIdOfExceptionHandler: 0x0 -; CODEVIEW-NEXT: Flags [ (0x14000) +; CODEVIEW-NEXT: Flags [ (0x16000) +; CODEVIEW-NEXT: SafeBuffers (0x2000) ; CODEVIEW-NEXT: ] ; CODEVIEW-NEXT: LocalFramePtrReg: VFRAME (0x7536) ; CODEVIEW-NEXT: ParamFramePtrReg: VFRAME (0x7536)