Index: clang/include/clang/Basic/DiagnosticCommonKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticCommonKinds.td +++ clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -323,6 +323,8 @@ def err_target_unsupported_abi_for_triple : Error< "ABI '%0' is not supported for '%1'">; def err_unsupported_abi_for_opt : Error<"'%0' can only be used with the '%1' ABI">; +def err_unsupported_opt_for_execute_only_target + : Error<"unsupported option '%0' for the execute only target '%1'">; def err_mips_fp64_req : Error< "'%0' can only be used if the target supports the mfhc1 and mthc1 instructions">; def err_target_unknown_fpmath : Error<"unknown FP unit '%0'">; Index: clang/include/clang/Basic/Sanitizers.h =================================================================== --- clang/include/clang/Basic/Sanitizers.h +++ clang/include/clang/Basic/Sanitizers.h @@ -23,7 +23,11 @@ namespace llvm { class hash_code; +class Triple; +namespace opt { +class ArgList; } +} // namespace llvm namespace clang { @@ -205,6 +209,11 @@ llvm::AsanDetectStackUseAfterReturnMode AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr); +/// Return true if an execute-only target disallows data access to code +/// sections. +bool isExecuteOnlyTarget(const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + } // namespace clang #endif // LLVM_CLANG_BASIC_SANITIZERS_H Index: clang/lib/Basic/CMakeLists.txt =================================================================== --- clang/lib/Basic/CMakeLists.txt +++ clang/lib/Basic/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + Option Support TargetParser ) Index: clang/lib/Basic/Sanitizers.cpp =================================================================== --- clang/lib/Basic/Sanitizers.cpp +++ clang/lib/Basic/Sanitizers.cpp @@ -11,10 +11,14 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/Sanitizers.h" +#include "clang/Driver/Options.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/ArgList.h" #include "llvm/Support/MathExtras.h" +#include "llvm/TargetParser/ARMTargetParser.h" +#include "llvm/TargetParser/Triple.h" using namespace clang; @@ -112,4 +116,22 @@ .Default(llvm::AsanDetectStackUseAfterReturnMode::Invalid); } +bool isExecuteOnlyTarget(const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) { + if (Triple.isPS5()) + return true; + + // On Arm, the clang `-mexecute-only` option is used to generate the + // execute-only output (no data access to code sections). + if (const llvm::opt::Arg *A = + Args.getLastArg(clang::driver::options::OPT_mexecute_only, + clang::driver::options::OPT_mno_execute_only)) { + if (A->getOption().matches(clang::driver::options::OPT_mexecute_only) && + llvm::ARM::supportedExecuteOnly(Triple)) { + return true; + } + } + + return false; +} } // namespace clang Index: clang/lib/Driver/SanitizerArgs.cpp =================================================================== --- clang/lib/Driver/SanitizerArgs.cpp +++ clang/lib/Driver/SanitizerArgs.cpp @@ -37,6 +37,8 @@ SanitizerKind::Vptr | SanitizerKind::CFI; static const SanitizerMask NotAllowedWithTrap = SanitizerKind::Vptr; static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr; +static const SanitizerMask NotAllowedWithExecuteOnly = + SanitizerKind::Function | SanitizerKind::KCFI; static const SanitizerMask RequiresPIE = SanitizerKind::DataFlow | SanitizerKind::Scudo; static const SanitizerMask NeedsUnwindTables = @@ -395,6 +397,22 @@ DiagnosedKinds |= SanitizerKind::Function; } } + // -fsanitize=function and -fsanitize=kcfi instrument indirect function + // calls to load a type hash before the function label. Therefore, an + // execute-only target doesn't support the function and kcfi sanitizers. + const llvm::Triple &Triple = TC.getTriple(); + if (isExecuteOnlyTarget(Triple, Args)) { + if (SanitizerMask KindsToDiagnose = + Add & NotAllowedWithExecuteOnly & ~DiagnosedKinds) { + if (DiagnoseErrors) { + std::string Desc = describeSanitizeArg(Arg, KindsToDiagnose); + D.Diag(diag::err_unsupported_opt_for_execute_only_target) + << Desc << Triple.str(); + } + DiagnosedKinds |= KindsToDiagnose; + } + Add &= ~NotAllowedWithExecuteOnly; + } // FIXME: Make CFI on member function calls compatible with cross-DSO CFI. // There are currently two problems: @@ -457,6 +475,11 @@ if (MinimalRuntime) { Add &= ~NotAllowedWithMinimalRuntime; } + // `-fsanitize=function` is silently discarded on an execute-only target + // if implicitly enabled through group expansion. + if (isExecuteOnlyTarget(Triple, Args)) { + Add &= ~NotAllowedWithExecuteOnly; + } if (CfiCrossDso) Add &= ~SanitizerKind::CFIMFCall; Add &= Supported; Index: clang/lib/Driver/ToolChains/Arch/ARM.cpp =================================================================== --- clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -843,10 +843,9 @@ // Cannot be combined with -mno-movt. if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) { if (A->getOption().matches(options::OPT_mexecute_only)) { - if (getARMSubArchVersionNumber(Triple) < 7 && - llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2 && - llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6M) - D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName(); + if (!llvm::ARM::supportedExecuteOnly(Triple)) + D.Diag(diag::err_target_unsupported_execute_only) + << Triple.getArchName(); else if (llvm::ARM::parseArch(Triple.getArchName()) == llvm::ARM::ArchKind::ARMV6M) { if (Arg *PIArg = Args.getLastArg(options::OPT_fropi, options::OPT_frwpi, options::OPT_fpic, options::OPT_fpie, Index: clang/test/CodeGenObjCXX/crash-function-type.mm =================================================================== --- clang/test/CodeGenObjCXX/crash-function-type.mm +++ clang/test/CodeGenObjCXX/crash-function-type.mm @@ -1,3 +1,6 @@ +// Mark test as unsupported on PS5 due to PS5 doesn't support function sanitizer. +// UNSUPPORTED: target=x86_64-sie-ps5 + // RUN: %clang_cc1 -fblocks -fsanitize=function -emit-llvm %s -o %t void g(void (^)()); Index: clang/test/Driver/fsanitize.c =================================================================== --- clang/test/Driver/fsanitize.c +++ clang/test/Driver/fsanitize.c @@ -970,3 +970,19 @@ // RUN: not %clang --target=x86_64-linux-gnu -fsanitize=undefined,function -mcmodel=large %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION-CODE-MODEL // CHECK-UBSAN-FUNCTION-CODE-MODEL: error: invalid argument '-fsanitize=function' only allowed with '-mcmodel=small' + +// RUN: not %clang --target=x86_64-sie-ps5 -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION +// RUN: not %clang --target=x86_64-sie-ps5 -fsanitize=undefined -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION +// RUN: not %clang --target=x86_64-sie-ps5 -fsanitize=kcfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-KCFI +// RUN: not %clang --target=x86_64-sie-ps5 -fsanitize=function -fsanitize=kcfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-KCFI --check-prefix=CHECK-UBSAN-FUNCTION +// RUN: %clang --target=x86_64-sie-ps5 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-UNDEFINED + +// RUN: not %clang --target=armv6t2-eabi -mexecute-only -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION +// RUN: not %clang --target=armv6t2-eabi -mexecute-only -fsanitize=undefined -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION +// RUN: not %clang --target=armv6t2-eabi -mexecute-only -fsanitize=kcfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-KCFI +// RUN: not %clang --target=armv6t2-eabi -mexecute-only -fsanitize=function -fsanitize=kcfi %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-KCFI --check-prefix=CHECK-UBSAN-FUNCTION +// RUN: %clang --target=armv6t2-eabi -mexecute-only -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-UNDEFINED + +// CHECK-UBSAN-KCFI-DAG: error: unsupported option '-fsanitize=kcfi' for the execute only target {{('x86_64-sie-ps5'|'armv6t2-unknown-unknown-eabi')}} +// CHECK-UBSAN-FUNCTION-DAG: error: unsupported option '-fsanitize=function' for the execute only target {{('x86_64-sie-ps5'|'armv6t2-unknown-unknown-eabi')}} +// CHECK-UBSAN-UNDEFINED-NOT: error: unsupported option '-fsanitize=function' for the execute only target {{('x86_64-sie-ps5'|'armv6t2-unknown-unknown-eabi')}} Index: llvm/include/llvm/TargetParser/ARMTargetParser.h =================================================================== --- llvm/include/llvm/TargetParser/ARMTargetParser.h +++ llvm/include/llvm/TargetParser/ARMTargetParser.h @@ -259,6 +259,9 @@ /// string then the triple's arch name is used. StringRef getARMCPUForArch(const llvm::Triple &Triple, StringRef MArch = {}); +/// Return true if the arch supports the execute-only output. Currently, the +/// execute-only output is only supported on ARMv6T2 and ARMv7 and above. +bool supportedExecuteOnly(const Triple &TT); } // namespace ARM } // namespace llvm Index: llvm/lib/TargetParser/ARMTargetParser.cpp =================================================================== --- llvm/lib/TargetParser/ARMTargetParser.cpp +++ llvm/lib/TargetParser/ARMTargetParser.cpp @@ -598,3 +598,11 @@ llvm_unreachable("invalid arch name"); } + +bool ARM::supportedExecuteOnly(const Triple &TT) { + if (parseArchVersion(TT.getArchName()) < 7 && + parseArch(TT.getArchName()) != ArchKind::ARMV6T2 && + parseArch(TT.getArchName()) != ArchKind::ARMV6M) + return false; + return true; +}