diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 2692ddec26ff4..04ba0ef981a69 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -204,7 +204,8 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple, StringRef AArch64TargetInfo::getABI() const { return ABI; } bool AArch64TargetInfo::setABI(const std::string &Name) { - if (Name != "aapcs" && Name != "aapcs-soft" && Name != "darwinpcs") + if (Name != "aapcs" && Name != "aapcs-soft" && Name != "darwinpcs" && + Name != "pauthtest") return false; ABI = Name; @@ -218,6 +219,12 @@ bool AArch64TargetInfo::validateTarget(DiagnosticsEngine &Diags) const { Diags.Report(diag::err_target_unsupported_abi_with_fpu) << ABI; return false; } + if (getTriple().getEnvironment() == llvm::Triple::PAuthTest && + getTriple().getOS() != llvm::Triple::Linux) { + Diags.Report(diag::err_target_unsupported_abi_for_triple) + << getTriple().getEnvironmentName() << getTriple().getTriple(); + return false; + } return true; } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 0c002b553e4c6..b1ad0a7a0506e 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -149,6 +149,8 @@ createTargetCodeGenInfo(CodeGenModule &CGM) { return createWindowsAArch64TargetCodeGenInfo(CGM, AArch64ABIKind::Win64); else if (Target.getABI() == "aapcs-soft") Kind = AArch64ABIKind::AAPCSSoft; + else if (Target.getABI() == "pauthtest") + Kind = AArch64ABIKind::PAuthTest; return createAArch64TargetCodeGenInfo(CGM, Kind); } diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index 0925609cc74aa..2f2138582ba1e 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -437,6 +437,7 @@ enum class AArch64ABIKind { DarwinPCS, Win64, AAPCSSoft, + PAuthTest, }; std::unique_ptr diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 85ae4d2a26fee..20a555afb8092 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -1031,11 +1031,12 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, } case llvm::Triple::aarch64: { llvm::Triple Triple = getTriple(); + tools::aarch64::setPAuthABIInTriple(getDriver(), Args, Triple); if (!Triple.isOSBinFormatMachO()) - return getTripleString(); + return Triple.getTriple(); if (Triple.isArm64e()) - return getTripleString(); + return Triple.getTriple(); // FIXME: older versions of ld64 expect the "arm64" component in the actual // triple string and query it to determine whether an LTO file can be diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index 5fbf38cdda12b..f083e40df1314 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -449,3 +449,24 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, if (Args.getLastArg(options::OPT_mno_bti_at_return_twice)) Features.push_back("+no-bti-at-return-twice"); } + +void aarch64::setPAuthABIInTriple(const Driver &D, const ArgList &Args, + llvm::Triple &Triple) { + Arg *ABIArg = Args.getLastArg(options::OPT_mabi_EQ); + bool HasPAuthABI = + ABIArg ? (StringRef(ABIArg->getValue()) == "pauthtest") : false; + + switch (Triple.getEnvironment()) { + case llvm::Triple::UnknownEnvironment: + if (HasPAuthABI) + Triple.setEnvironment(llvm::Triple::PAuthTest); + break; + case llvm::Triple::PAuthTest: + break; + default: + if (HasPAuthABI) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << ABIArg->getAsString(Args) << Triple.getTriple(); + break; + } +} diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.h b/clang/lib/Driver/ToolChains/Arch/AArch64.h index d47c402d4a42d..6d071167bd392 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.h +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.h @@ -28,6 +28,9 @@ void getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple, std::string getAArch64TargetCPU(const llvm::opt::ArgList &Args, const llvm::Triple &Triple, llvm::opt::Arg *&A); +void setPAuthABIInTriple(const Driver &D, const llvm::opt::ArgList &Args, + llvm::Triple &triple); + } // end namespace aarch64 } // end namespace target } // end namespace driver diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index a8a7cef09972e..21a460432a386 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1484,6 +1484,41 @@ void AddUnalignedAccessWarning(ArgStringList &CmdArgs) { } } +// Each combination of options here forms a signing schema, and in most cases +// each signing schema is its own incompatible ABI. The default values of the +// options represent the default signing schema. +static void handlePAuthABI(const ArgList &DriverArgs, ArgStringList &CC1Args) { + if (!DriverArgs.hasArg(options::OPT_fptrauth_intrinsics, + options::OPT_fno_ptrauth_intrinsics)) + CC1Args.push_back("-fptrauth-intrinsics"); + + if (!DriverArgs.hasArg(options::OPT_fptrauth_calls, + options::OPT_fno_ptrauth_calls)) + CC1Args.push_back("-fptrauth-calls"); + + if (!DriverArgs.hasArg(options::OPT_fptrauth_returns, + options::OPT_fno_ptrauth_returns)) + CC1Args.push_back("-fptrauth-returns"); + + if (!DriverArgs.hasArg(options::OPT_fptrauth_auth_traps, + options::OPT_fno_ptrauth_auth_traps)) + CC1Args.push_back("-fptrauth-auth-traps"); + + if (!DriverArgs.hasArg( + options::OPT_fptrauth_vtable_pointer_address_discrimination, + options::OPT_fno_ptrauth_vtable_pointer_address_discrimination)) + CC1Args.push_back("-fptrauth-vtable-pointer-address-discrimination"); + + if (!DriverArgs.hasArg( + options::OPT_fptrauth_vtable_pointer_type_discrimination, + options::OPT_fno_ptrauth_vtable_pointer_type_discrimination)) + CC1Args.push_back("-fptrauth-vtable-pointer-type-discrimination"); + + if (!DriverArgs.hasArg(options::OPT_fptrauth_init_fini, + options::OPT_fno_ptrauth_init_fini)) + CC1Args.push_back("-fptrauth-init-fini"); +} + static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, bool isAArch64) { const Arg *A = isAArch64 @@ -1546,16 +1581,30 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back( Args.MakeArgString(Twine("-msign-return-address=") + Scope)); - if (Scope != "none") + if (Scope != "none") { + if (Triple.getEnvironment() == llvm::Triple::PAuthTest) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << Triple.getTriple(); CmdArgs.push_back( Args.MakeArgString(Twine("-msign-return-address-key=") + Key)); - if (BranchProtectionPAuthLR) + } + if (BranchProtectionPAuthLR) { + if (Triple.getEnvironment() == llvm::Triple::PAuthTest) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << Triple.getTriple(); CmdArgs.push_back( Args.MakeArgString(Twine("-mbranch-protection-pauth-lr"))); + } if (IndirectBranches) CmdArgs.push_back("-mbranch-target-enforce"); - if (GuardedControlStack) + // GCS is currently untested with PAuthABI, but enabling this could be allowed + // in future after testing with a suitable system. + if (GuardedControlStack) { + if (Triple.getEnvironment() == llvm::Triple::PAuthTest) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << Triple.getTriple(); CmdArgs.push_back("-mguarded-control-stack"); + } } void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, @@ -1699,6 +1748,8 @@ void RenderAArch64ABI(const llvm::Triple &Triple, const ArgList &Args, ABIName = A->getValue(); else if (Triple.isOSDarwin()) ABIName = "darwinpcs"; + else if (Triple.getEnvironment() == llvm::Triple::PAuthTest) + ABIName = "pauthtest"; else ABIName = "aapcs"; @@ -1735,6 +1786,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, // Enable/disable return address signing and indirect branch targets. CollectARMPACBTIOptions(getToolChain(), Args, CmdArgs, true /*isAArch64*/); + if (Triple.getEnvironment() == llvm::Triple::PAuthTest) + handlePAuthABI(Args, CmdArgs); + // Handle -msve_vector_bits= if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) { StringRef Val = A->getValue(); diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 98a878e1d764d..2265138edbffb 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -86,6 +86,9 @@ std::string Linux::getMultiarchTriple(const Driver &D, case llvm::Triple::aarch64: if (IsAndroid) return "aarch64-linux-android"; + if (hasEffectiveTriple() && + getEffectiveTriple().getEnvironment() == llvm::Triple::PAuthTest) + return "aarch64-linux-pauthtest"; return "aarch64-linux-gnu"; case llvm::Triple::aarch64_be: return "aarch64_be-linux-gnu"; diff --git a/clang/test/Driver/Inputs/multilib_aarch64_linux_tree/usr/include/aarch64-linux-gnu/.keep b/clang/test/Driver/Inputs/multilib_aarch64_linux_tree/usr/include/aarch64-linux-gnu/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/multilib_aarch64_linux_tree/usr/include/aarch64-linux-pauthtest/.keep b/clang/test/Driver/Inputs/multilib_aarch64_linux_tree/usr/include/aarch64-linux-pauthtest/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/aarch64-multilib-pauthabi.c b/clang/test/Driver/aarch64-multilib-pauthabi.c new file mode 100644 index 0000000000000..3046cb856e83c --- /dev/null +++ b/clang/test/Driver/aarch64-multilib-pauthabi.c @@ -0,0 +1,4 @@ +// RUN: %clang --target=aarch64-linux-pauthtest --sysroot=%S/Inputs/multilib_aarch64_linux_tree -### -c %s 2>&1 | FileCheck %s +// RUN: %clang --target=aarch64-linux -mabi=pauthtest --sysroot=%S/Inputs/multilib_aarch64_linux_tree -### -c %s 2>&1 | FileCheck %s + +// CHECK: "-internal-externc-isystem" "{{.*}}/usr/include/aarch64-linux-pauthtest" diff --git a/clang/test/Driver/aarch64-ptrauth.c b/clang/test/Driver/aarch64-ptrauth.c index fa0125f4b22a9..d13930e8f4b37 100644 --- a/clang/test/Driver/aarch64-ptrauth.c +++ b/clang/test/Driver/aarch64-ptrauth.c @@ -1,5 +1,7 @@ +// REQUIRES: aarch64-registered-target + // RUN: %clang -### -c --target=aarch64 %s 2>&1 | FileCheck %s --check-prefix NONE -// NONE: "-cc1" +// NONE: "-cc1" // NONE-NOT: "-fptrauth- // RUN: %clang -### -c --target=aarch64 \ @@ -13,13 +15,78 @@ // RUN: %s 2>&1 | FileCheck %s --check-prefix=ALL // ALL: "-cc1"{{.*}} "-fptrauth-intrinsics" "-fptrauth-calls" "-fptrauth-returns" "-fptrauth-auth-traps" "-fptrauth-vtable-pointer-address-discrimination" "-fptrauth-vtable-pointer-type-discrimination" "-fptrauth-init-fini" +// RUN: %clang -### -c --target=aarch64-linux -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=PAUTHABI1 +// RUN: %clang -### -c --target=aarch64-linux-pauthtest %s 2>&1 | FileCheck %s --check-prefix=PAUTHABI1 +// PAUTHABI1: "-cc1"{{.*}} "-triple" "aarch64-unknown-linux-pauthtest" +// PAUTHABI1-SAME: "-target-abi" "pauthtest" +// PAUTHABI1-SAME: "-fptrauth-intrinsics" "-fptrauth-calls" "-fptrauth-returns" "-fptrauth-auth-traps" "-fptrauth-vtable-pointer-address-discrimination" "-fptrauth-vtable-pointer-type-discrimination" "-fptrauth-init-fini" + +// RUN: %clang -### -c --target=aarch64 -mabi=pauthtest -fno-ptrauth-intrinsics \ +// RUN: -fno-ptrauth-calls -fno-ptrauth-returns -fno-ptrauth-auth-traps \ +// RUN: -fno-ptrauth-vtable-pointer-address-discrimination -fno-ptrauth-vtable-pointer-type-discrimination \ +// RUN: -fno-ptrauth-init-fini %s 2>&1 | FileCheck %s --check-prefix=PAUTHABI2 +// RUN: %clang -### -c --target=aarch64-pauthtest -fno-ptrauth-intrinsics \ +// RUN: -fno-ptrauth-calls -fno-ptrauth-returns -fno-ptrauth-auth-traps \ +// RUN: -fno-ptrauth-vtable-pointer-address-discrimination -fno-ptrauth-vtable-pointer-type-discrimination \ +// RUN: -fno-ptrauth-init-fini %s 2>&1 | FileCheck %s --check-prefix=PAUTHABI2 +// PAUTHABI2: "-cc1" +// PAUTHABI2-NOT: "-fptrauth- + // RUN: not %clang -### -c --target=x86_64 -fptrauth-intrinsics -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps \ // RUN: -fptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-type-discrimination \ -// RUN: -fptrauth-init-fini %s 2>&1 | FileCheck %s --check-prefix=ERR -// ERR: error: unsupported option '-fptrauth-intrinsics' for target '{{.*}}' -// ERR-NEXT: error: unsupported option '-fptrauth-calls' for target '{{.*}}' -// ERR-NEXT: error: unsupported option '-fptrauth-returns' for target '{{.*}}' -// ERR-NEXT: error: unsupported option '-fptrauth-auth-traps' for target '{{.*}}' -// ERR-NEXT: error: unsupported option '-fptrauth-vtable-pointer-address-discrimination' for target '{{.*}}' -// ERR-NEXT: error: unsupported option '-fptrauth-vtable-pointer-type-discrimination' for target '{{.*}}' -// ERR-NEXT: error: unsupported option '-fptrauth-init-fini' for target '{{.*}}' +// RUN: -fptrauth-init-fini %s 2>&1 | FileCheck %s --check-prefix=ERR1 +// ERR1: error: unsupported option '-fptrauth-intrinsics' for target '{{.*}}' +// ERR1-NEXT: error: unsupported option '-fptrauth-calls' for target '{{.*}}' +// ERR1-NEXT: error: unsupported option '-fptrauth-returns' for target '{{.*}}' +// ERR1-NEXT: error: unsupported option '-fptrauth-auth-traps' for target '{{.*}}' +// ERR1-NEXT: error: unsupported option '-fptrauth-vtable-pointer-address-discrimination' for target '{{.*}}' +// ERR1-NEXT: error: unsupported option '-fptrauth-vtable-pointer-type-discrimination' for target '{{.*}}' +// ERR1-NEXT: error: unsupported option '-fptrauth-init-fini' for target '{{.*}}' + +//// Only support PAuth ABI for Linux as for now. +// RUN: not %clang -c --target=aarch64-unknown -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=ERR2 +// RUN: not %clang -c --target=aarch64-unknown-pauthtest %s 2>&1 | FileCheck %s --check-prefix=ERR2 +// ERR2: error: ABI 'pauthtest' is not supported for 'aarch64-unknown-unknown-pauthtest' + +//// PAuth ABI is encoded as environment part of the triple, so don't allow to explicitly set other environments. +// RUN: not %clang -c --target=aarch64-linux-gnu -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=ERR3 +// ERR3: error: unsupported option '-mabi=pauthtest' for target 'aarch64-unknown-linux-gnu' +// RUN: %clang -c --target=aarch64-linux-pauthtest -mabi=pauthtest %s + +//// The only branch protection option compatible with PAuthABI is BTI. +// RUN: not %clang -### -c --target=aarch64-linux -mabi=pauthtest -mbranch-protection=pac-ret %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=ERR4 +// RUN: not %clang -### -c --target=aarch64-linux-pauthtest -mbranch-protection=pac-ret %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=ERR4 +// ERR4: error: unsupported option '-mbranch-protection=pac-ret' for target 'aarch64-unknown-linux-pauthtest' + +// RUN: not %clang -### -c --target=aarch64-linux -mabi=pauthtest -mbranch-protection=gcs %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=ERR5 +// RUN: not %clang -### -c --target=aarch64-linux-pauthtest -mbranch-protection=gcs %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=ERR5 +// ERR5: error: unsupported option '-mbranch-protection=gcs' for target 'aarch64-unknown-linux-pauthtest' + +// RUN: not %clang -### -c --target=aarch64-linux -mabi=pauthtest -mbranch-protection=standard %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=ERR6 +// RUN: not %clang -### -c --target=aarch64-linux-pauthtest -mbranch-protection=standard %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=ERR6 +// ERR6: error: unsupported option '-mbranch-protection=standard' for target 'aarch64-unknown-linux-pauthtest' + +// RUN: not %clang -### -c --target=aarch64-linux -mabi=pauthtest -msign-return-address=all %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=ERR7 +// RUN: not %clang -### -c --target=aarch64-linux-pauthtest -msign-return-address=all %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=ERR7 +// ERR7: error: unsupported option '-msign-return-address=all' for target 'aarch64-unknown-linux-pauthtest' + +// RUN: not %clang -### -c --target=aarch64-linux -mabi=pauthtest -msign-return-address=non-leaf %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=ERR8 +// RUN: not %clang -### -c --target=aarch64-linux-pauthtest -msign-return-address=non-leaf %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=ERR8 +// ERR8: error: unsupported option '-msign-return-address=non-leaf' for target 'aarch64-unknown-linux-pauthtest' + +// RUN: %clang -### -c --target=aarch64-linux -mabi=pauthtest -msign-return-address=none %s +// RUN: %clang -### -c --target=aarch64-linux-pauthtest -msign-return-address=none %s +// RUN: %clang -### -c --target=aarch64-linux -mabi=pauthtest -mbranch-protection=bti %s +// RUN: %clang -### -c --target=aarch64-linux-pauthtest -mbranch-protection=bti %s +// RUN: %clang -### -c --target=aarch64-linux -mabi=pauthtest -mbranch-protection=none %s +// RUN: %clang -### -c --target=aarch64-linux-pauthtest -mbranch-protection=none %s diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h index b3bb354b38ff5..ebd92f264d904 100644 --- a/llvm/include/llvm/TargetParser/Triple.h +++ b/llvm/include/llvm/TargetParser/Triple.h @@ -268,7 +268,7 @@ class Triple { Cygnus, CoreCLR, Simulator, // Simulator variants of other systems, e.g., Apple's iOS - MacABI, // Mac Catalyst variant of Apple's iOS deployment target. + MacABI, // Mac Catalyst variant of Apple's iOS deployment target. // Shader Stages // The order of these values matters, and must be kept in sync with the @@ -292,7 +292,9 @@ class Triple { OpenCL, OpenHOS, - LastEnvironmentType = OpenHOS + PAuthTest, + + LastEnvironmentType = PAuthTest }; enum ObjectFormatType { UnknownObjectFormat, diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp index 4fc1ff5aaa051..bf89aace65e58 100644 --- a/llvm/lib/TargetParser/Triple.cpp +++ b/llvm/lib/TargetParser/Triple.cpp @@ -352,6 +352,8 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) { case OpenCL: return "opencl"; case OpenHOS: return "ohos"; + case PAuthTest: + return "pauthtest"; } llvm_unreachable("Invalid EnvironmentType!"); @@ -728,6 +730,7 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { .StartsWith("amplification", Triple::Amplification) .StartsWith("opencl", Triple::OpenCL) .StartsWith("ohos", Triple::OpenHOS) + .StartsWith("pauthtest", Triple::PAuthTest) .Default(Triple::UnknownEnvironment); } diff --git a/llvm/unittests/TargetParser/TripleTest.cpp b/llvm/unittests/TargetParser/TripleTest.cpp index f93dc3671197a..0aecfc64da208 100644 --- a/llvm/unittests/TargetParser/TripleTest.cpp +++ b/llvm/unittests/TargetParser/TripleTest.cpp @@ -1169,6 +1169,12 @@ TEST(TripleTest, ParsedIDs) { EXPECT_EQ(Triple::Serenity, T.getOS()); EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); + T = Triple("aarch64-unknown-linux-pauthtest"); + EXPECT_EQ(Triple::aarch64, T.getArch()); + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); + EXPECT_EQ(Triple::Linux, T.getOS()); + EXPECT_EQ(Triple::PAuthTest, T.getEnvironment()); + T = Triple("huh"); EXPECT_EQ(Triple::UnknownArch, T.getArch()); }