diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -137,6 +137,10 @@ Windows Support --------------- +- For the MinGW driver, added the options ``-mguard=none``, ``-mguard=cf`` and + ``-mguard=cf-nochecks`` (equivalent to ``/guard:cf-``, ``/guard:cf`` and + ``/guard:cf,nochecks`` in clang-cl) for enabling Control Flow Guard checks + and generation of address-taken function table. AIX Support ----------- diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3363,6 +3363,9 @@ def mdll : Joined<["-"], "mdll">, Group, Flags<[NoXarchOption]>; def municode : Joined<["-"], "municode">, Group, Flags<[NoXarchOption]>; def mthreads : Joined<["-"], "mthreads">, Group, Flags<[NoXarchOption]>; +def mguard_EQ : Joined<["-"], "mguard=">, Group, Flags<[NoXarchOption]>, + HelpText<"Enable or disable Control Flow Guard checks and guard tables emission">, + Values<"none,cf,cf-nochecks">; def mcpu_EQ : Joined<["-"], "mcpu=">, Group; def mmcu_EQ : Joined<["-"], "mmcu=">, Group; def msim : Flag<["-"], "msim">, Group; diff --git a/clang/lib/Driver/ToolChains/MinGW.h b/clang/lib/Driver/ToolChains/MinGW.h --- a/clang/lib/Driver/ToolChains/MinGW.h +++ b/clang/lib/Driver/ToolChains/MinGW.h @@ -79,6 +79,10 @@ void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -169,6 +169,18 @@ if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); + if (Arg *A = Args.getLastArg(options::OPT_mguard_EQ)) { + StringRef GuardArgs = A->getValue(); + if (GuardArgs.equals_insensitive("none")) + CmdArgs.push_back("--no-guard-cf"); + else if (GuardArgs.equals_insensitive("cf") || + GuardArgs.equals_insensitive("cf-nochecks")) + CmdArgs.push_back("--guard-cf"); + else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << GuardArgs; + } + CmdArgs.push_back("-o"); const char *OutputFile = Output.getFilename(); // GCC implicitly adds an .exe extension if it is given an output file name @@ -607,6 +619,26 @@ addSystemInclude(DriverArgs, CC1Args, Base + "include"); } +void toolchains::MinGW::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const { + if (Arg *A = DriverArgs.getLastArg(options::OPT_mguard_EQ)) { + StringRef GuardArgs = A->getValue(); + if (GuardArgs.equals_insensitive("none")) { + // Do nothing. + } else if (GuardArgs.equals_insensitive("cf")) { + // Emit CFG instrumentation and the table of address-taken functions. + CC1Args.push_back("-cfguard"); + } else if (GuardArgs.equals_insensitive("cf-nochecks")) { + // Emit only the table of address-taken functions. + CC1Args.push_back("-cfguard-no-checks"); + } else { + getDriver().Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << GuardArgs; + } + } +} + void toolchains::MinGW::AddClangCXXStdlibIncludeArgs( const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || diff --git a/clang/test/Driver/mingw-cfguard.c b/clang/test/Driver/mingw-cfguard.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/mingw-cfguard.c @@ -0,0 +1,34 @@ +// RUN: %clang -v -target x86_64-w64-windows-gnu -### %s 2>&1 | FileCheck -check-prefixes=NO_CF,DEFAULT %s +// RUN: %clang -v -target x86_64-w64-windows-gnu -### %s -mguard=none 2>&1 | FileCheck -check-prefixes=NO_CF,GUARD_NONE %s +// NO_CF: "-cc1" +// NO_CF-NOT: "-cfguard" +// NO_CF-NOT: "-cfguard-no-checks" +// NO_CF-SAME: {{$}} +// NO_CF-NEXT: ld" +// NO_CF-NOT: "--guard-cf" +// DEFAULT-NOT: "--no-guard-cf" +// GUARD_NONE-SAME: "--no-guard-cf" +// NO_CF-SAME: {{$}} + +// RUN: %clang -v -target x86_64-w64-windows-gnu -### %s -mguard=cf 2>&1 | FileCheck -check-prefix=GUARD_CF %s +// GUARD_CF: "-cc1" +// GUARD_CF-SAME: "-cfguard" +// GUARD_CF-SAME: {{$}} +// GUARD_CF-NEXT: ld" +// GUARD_CF-SAME: "--guard-cf" +// GUARD_CF-NOT: "--no-guard-cf" +// GUARD_CF-SAME: {{$}} + +// RUN: %clang -v -target x86_64-w64-windows-gnu -### %s -mguard=cf-nochecks 2>&1 | FileCheck -check-prefix=GUARD_NOCHECKS %s +// GUARD_NOCHECKS: "-cc1" +// GUARD_NOCHECKS-NOT: "-cfguard" +// GUARD_NOCHECKS-SAME: "-cfguard-no-checks" +// GUARD_NOCHECKS-NOT: "-cfguard" +// GUARD_NOCHECKS-SAME: {{$}} +// GUARD_NOCHECKS-NEXT: ld" +// GUARD_NOCHECKS-SAME: "--guard-cf" +// GUARD_NOCHECKS-NOT: "--no-guard-cf" +// GUARD_NOCHECKS-SAME: {{$}} + +// RUN: %clang -v -target x86_64-w64-windows-gnu -### %s -mguard=xxx 2>&1 | FileCheck -check-prefix=GUARD_UNKNOWN %s +// GUARD_UNKNOWN: error: unsupported argument 'xxx' to option '--mguard='