From 306f70ff184a6740e165a13bd5868e4127d89047 Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha Date: Mon, 27 Sep 2021 08:00:00 -0700 Subject: [PATCH] [AArch64][MachO] Support ptrauth ABI version. --- clang/include/clang/Basic/LangOptions.def | 3 + clang/include/clang/Driver/Options.td | 16 +++- clang/lib/Basic/Targets/OSTargets.cpp | 5 ++ clang/lib/CodeGen/CodeGenModule.cpp | 5 ++ clang/lib/Driver/ToolChains/Clang.cpp | 41 +++++++++ clang/lib/Driver/ToolChains/Clang.h | 2 + clang/lib/Driver/ToolChains/Darwin.cpp | 32 +++++++ clang/lib/Frontend/CompilerInvocation.cpp | 14 +++ clang/test/CodeGen/ptrauth-abi-version.c | 18 ++++ .../arch-arm64e-abi-versioning-defaults.c | 16 ++++ .../test/Driver/arch-arm64e-abi-versioning.c | 16 ++++ clang/test/Preprocessor/ptrauth_abi_version.c | 8 ++ clang/tools/driver/cc1as_main.cpp | 20 +++++ llvm/docs/LangRef.rst | 5 ++ llvm/include/llvm/BinaryFormat/MachO.h | 33 ++++++++ llvm/include/llvm/IR/Module.h | 14 +++ llvm/include/llvm/MC/MCAssembler.h | 10 +++ llvm/include/llvm/MC/MCMachObjectWriter.h | 4 +- llvm/include/llvm/MC/MCStreamer.h | 3 + llvm/lib/BinaryFormat/MachO.cpp | 18 ++++ llvm/lib/IR/AutoUpgrade.cpp | 20 ++++- llvm/lib/IR/Module.cpp | 80 ++++++++++++++++++ llvm/lib/LTO/LTOModule.cpp | 8 ++ llvm/lib/MC/MCAsmStreamer.cpp | 12 +++ llvm/lib/MC/MCAssembler.cpp | 4 + llvm/lib/MC/MCMachOStreamer.cpp | 8 ++ llvm/lib/MC/MCParser/DarwinAsmParser.cpp | 47 ++++++++++ llvm/lib/MC/MachObjectWriter.cpp | 34 +++++++- llvm/lib/Object/MachOObjectFile.cpp | 2 +- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 59 +++++++++++++ llvm/test/Bitcode/upgrade-ptrauth.ll | 7 ++ llvm/test/Bitcode/upgrade-ptrauth.ll.bc | Bin 0 -> 1152 bytes .../arm64e-ptrauth-abi-version-default.ll | 3 + .../arm64e-ptrauth-abi-version-invalid.ll | 10 +++ .../arm64e-ptrauth-abi-version-mismatch.ll | 11 +++ .../AArch64/arm64e-ptrauth-abi-version-old.ll | 13 +++ .../arm64e-ptrauth-abi-version-zero.ll | 8 ++ .../AArch64/arm64e-ptrauth-abi-version.ll | 8 ++ .../arm64e-ptrauth-kernel-abi-version.ll | 8 ++ .../LTO/AArch64/arm64e-print-macho-cpu.ll | 8 ++ ...64e-ptrauth-abi-version-print-macho-cpu.ll | 14 +++ ...auth-kernel-abi-version-print-macho-cpu.ll | 13 +++ .../module-flags-ptrauth-abi-version-3.ll | 4 + .../module-flags-ptrauth-abi-version-5.ll | 4 + ...dule-flags-ptrauth-kernel-abi-version-3.ll | 4 + .../module-flags-ptrauth-abi-version-a.ll | 35 ++++++++ .../MC/AArch64/arm64e-ptrauth-abi-version.s | 15 ++++ .../fat.macho-arm64e-kernel-ptrauth-abi | Bin 0 -> 4128 bytes .../Inputs/fat.macho-arm64e-ptrauth-abi | Bin 0 -> 4128 bytes ...o-universal-arm64e-kernel-ptrauth-abi.test | 13 +++ .../macho-universal-arm64e-ptrauth-abi.test | 13 +++ .../macho-ptrauth-cpusubtype.test | 23 +++++ llvm/tools/dsymutil/MachOUtils.cpp | 17 +++- llvm/tools/llvm-lto/llvm-lto.cpp | 29 +++++-- llvm/tools/llvm-objdump/MachODump.cpp | 22 ++++- llvm/unittests/BinaryFormat/MachOTest.cpp | 41 +++++++++ 56 files changed, 861 insertions(+), 19 deletions(-) create mode 100644 clang/test/CodeGen/ptrauth-abi-version.c create mode 100644 clang/test/Driver/arch-arm64e-abi-versioning-defaults.c create mode 100644 clang/test/Driver/arch-arm64e-abi-versioning.c create mode 100644 clang/test/Preprocessor/ptrauth_abi_version.c create mode 100644 llvm/test/Bitcode/upgrade-ptrauth.ll create mode 100644 llvm/test/Bitcode/upgrade-ptrauth.ll.bc create mode 100644 llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-default.ll create mode 100644 llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-invalid.ll create mode 100644 llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-mismatch.ll create mode 100644 llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-old.ll create mode 100644 llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-zero.ll create mode 100644 llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version.ll create mode 100644 llvm/test/CodeGen/AArch64/arm64e-ptrauth-kernel-abi-version.ll create mode 100644 llvm/test/LTO/AArch64/arm64e-print-macho-cpu.ll create mode 100644 llvm/test/LTO/AArch64/arm64e-ptrauth-abi-version-print-macho-cpu.ll create mode 100644 llvm/test/LTO/AArch64/arm64e-ptrauth-kernel-abi-version-print-macho-cpu.ll create mode 100644 llvm/test/Linker/Inputs/module-flags-ptrauth-abi-version-3.ll create mode 100644 llvm/test/Linker/Inputs/module-flags-ptrauth-abi-version-5.ll create mode 100644 llvm/test/Linker/Inputs/module-flags-ptrauth-kernel-abi-version-3.ll create mode 100644 llvm/test/Linker/module-flags-ptrauth-abi-version-a.ll create mode 100644 llvm/test/MC/AArch64/arm64e-ptrauth-abi-version.s create mode 100644 llvm/test/tools/llvm-objdump/AArch64/Inputs/fat.macho-arm64e-kernel-ptrauth-abi create mode 100644 llvm/test/tools/llvm-objdump/AArch64/Inputs/fat.macho-arm64e-ptrauth-abi create mode 100644 llvm/test/tools/llvm-objdump/AArch64/macho-universal-arm64e-kernel-ptrauth-abi.test create mode 100644 llvm/test/tools/llvm-objdump/AArch64/macho-universal-arm64e-ptrauth-abi.test create mode 100644 llvm/test/tools/llvm-objdump/macho-ptrauth-cpusubtype.test diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index c51402d137e7..e84a2da2ff01 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -161,6 +161,9 @@ LANGOPT(RelaxedTemplateTemplateArgs, 1, 0, "C++17 relaxed matching of template t LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library features") LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics") +VALUE_LANGOPT(PointerAuthABIVersion, 32, 0, "pointer authentication ABI version") +LANGOPT(PointerAuthKernelABIVersion, 1, 0, "controls whether the pointer auth abi version represents a kernel ABI") +LANGOPT(PointerAuthABIVersionEncoded, 1, 0, "controls whether the pointer auth abi version should be encoded in the IR") LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index d3e80761b235..fc939564553d 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1,4 +1,4 @@ -//===--- Options.td - Options for clang -----------------------------------===// + // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -3881,6 +3881,20 @@ let Group = f_Group in { def fno_ptrauth_intrinsics : Flag<["-"], "fno-ptrauth-intrinsics">; } +let Group = f_Group in { + def fptrauth_abi_version_EQ : Joined<["-"], "fptrauth-abi-version=">, + Visibility<[ClangOption, CC1Option, CC1AsOption]>, + HelpText<"Pointer Authentication ABI version">; + def fno_ptrauth_abi_version : Flag<["-"], "fno-ptrauth-abi-version">, + HelpText<"Disable Pointer Authentication ABI versioning">; + + def fptrauth_kernel_abi_version : Flag<["-"], "fptrauth-kernel-abi-version">, + Visibility<[ClangOption, CC1Option, CC1AsOption]>, + HelpText<"Enable Pointer Authentication kernel ABI version">; + def fno_ptrauth_kernel_abi_version : Flag<["-"], "fno-ptrauth-kernel-abi-version">, + HelpText<"Disable Pointer Authentication kernel ABI versioning">; +} + def fenable_matrix : Flag<["-"], "fenable-matrix">, Group, Visibility<[ClangOption, CC1Option]>, HelpText<"Enable matrix data type and related builtin functions">, diff --git a/clang/lib/Basic/Targets/OSTargets.cpp b/clang/lib/Basic/Targets/OSTargets.cpp index 627bc912fa23..66c77cf731ad 100644 --- a/clang/lib/Basic/Targets/OSTargets.cpp +++ b/clang/lib/Basic/Targets/OSTargets.cpp @@ -11,6 +11,7 @@ #include "OSTargets.h" #include "clang/Basic/MacroBuilder.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" using namespace clang; @@ -31,6 +32,10 @@ void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, if (Opts.Sanitize.has(SanitizerKind::Address)) Builder.defineMacro("_FORTIFY_SOURCE", "0"); + if (Opts.PointerAuthABIVersionEncoded) + Builder.defineMacro("__ptrauth_abi_version__", + llvm::utostr(Opts.PointerAuthABIVersion)); + // Darwin defines __weak, __strong, and __unsafe_unretained even in C mode. if (!Opts.ObjC) { // __weak is always defined, for use in blocks and with objc pointers. diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 8b0c9340775c..74ecc341a23e 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1127,6 +1127,11 @@ void CodeGenModule::Release() { if (LangOpts.HLSL) getHLSLRuntime().finishCodeGen(); + if (LangOpts.PointerAuthABIVersionEncoded) + TheModule.setPtrAuthABIVersion( + {static_cast(LangOpts.PointerAuthABIVersion), + static_cast(LangOpts.PointerAuthKernelABIVersion)}); + if (uint32_t PLevel = Context.getLangOpts().PICLevel) { assert(PLevel < 3 && "Invalid PIC Level"); getModule().setPICLevel(static_cast(PLevel)); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index ef3f47f67d0e..be65e8e7e099 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -8097,6 +8097,46 @@ void ClangAs::AddRISCVTargetArgs(const ArgList &Args, } } +void ClangAs::AddAArch64TargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + const llvm::Triple &Triple = getToolChain().getTriple(); + + // In the assembler, arm64e support mostly consists of setting an ABI version. + // It also enables various preprocessor macros, but that's done before -cc1as. + if (Triple.isArm64e()) { + // The ptrauth ABI version is 0 by default, but can be overridden. + static const constexpr unsigned DefaultPtrauthABIVersion = 0; + + unsigned PtrAuthABIVersion = DefaultPtrauthABIVersion; + const Arg *A = Args.getLastArg(options::OPT_fptrauth_abi_version_EQ, + options::OPT_fno_ptrauth_abi_version); + bool HasVersionArg = + A && A->getOption().matches(options::OPT_fptrauth_abi_version_EQ); + if (HasVersionArg) { + unsigned PtrAuthABIVersionArg; + if (StringRef(A->getValue()).getAsInteger(10, PtrAuthABIVersionArg)) + getToolChain().getDriver().Diag(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(); + else + PtrAuthABIVersion = PtrAuthABIVersionArg; + } + + // Pass the ABI version to -cc1, regardless of its value, if the user asked + // for it or if the user didn't explicitly disable it. + if (HasVersionArg || !Args.hasArg(options::OPT_fno_ptrauth_abi_version)) { + CmdArgs.push_back(Args.MakeArgString("-fptrauth-abi-version=" + + llvm::utostr(PtrAuthABIVersion))); + + // -f(no-)ptrauth-kernel-abi-version can override -mkernel and + // -fapple-kext + if (Args.hasArg(options::OPT_fptrauth_kernel_abi_version, + options::OPT_mkernel, options::OPT_fapple_kext) && + !Args.hasArg(options::OPT_fno_ptrauth_kernel_abi_version)) + CmdArgs.push_back("-fptrauth-kernel-abi-version"); + } + } +} + void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, @@ -8278,6 +8318,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-aarch64-mark-bti-property"); } + AddAArch64TargetArgs(Args, CmdArgs); break; case llvm::Triple::loongarch32: diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h index 0f503c4bd1c4..8c4f18384d22 100644 --- a/clang/lib/Driver/ToolChains/Clang.h +++ b/clang/lib/Driver/ToolChains/Clang.h @@ -131,6 +131,8 @@ class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool { llvm::opt::ArgStringList &CmdArgs) const; void AddRISCVTargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + void AddAArch64TargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; bool hasGoodDiagnostics() const override { return true; } bool hasIntegratedAssembler() const override { return false; } bool hasIntegratedCPP() const override { return false; } diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 359d1510340b..438d42cdcef8 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -1160,6 +1160,38 @@ void DarwinClang::addClangTargetOptions( // On arm64e, enable pointer authentication intrinsics. if (getTriple().isArm64e()) { + // The ptrauth ABI version is 0 by default, but can be overridden. + static const constexpr unsigned DefaultPtrauthABIVersion = 0; + + unsigned PtrAuthABIVersion = DefaultPtrauthABIVersion; + const Arg *A = DriverArgs.getLastArg(options::OPT_fptrauth_abi_version_EQ, + options::OPT_fno_ptrauth_abi_version); + bool HasVersionArg = + A && A->getOption().matches(options::OPT_fptrauth_abi_version_EQ); + if (HasVersionArg) { + unsigned PtrAuthABIVersionArg; + if (StringRef(A->getValue()).getAsInteger(10, PtrAuthABIVersionArg)) + getDriver().Diag(diag::err_drv_invalid_value) + << A->getAsString(DriverArgs) << A->getValue(); + else + PtrAuthABIVersion = PtrAuthABIVersionArg; + } + + // Pass the ABI version to -cc1, regardless of its value, if the user asked + // for it or if the user didn't explicitly disable it. + if (HasVersionArg || + !DriverArgs.hasArg(options::OPT_fno_ptrauth_abi_version)) { + CC1Args.push_back(DriverArgs.MakeArgString( + "-fptrauth-abi-version=" + llvm::utostr(PtrAuthABIVersion))); + + // -f(no-)ptrauth-kernel-abi-version can override -mkernel and + // -fapple-kext + if (DriverArgs.hasArg(options::OPT_fptrauth_kernel_abi_version, + options::OPT_mkernel, options::OPT_fapple_kext) && + !DriverArgs.hasArg(options::OPT_fno_ptrauth_kernel_abi_version)) + CC1Args.push_back("-fptrauth-kernel-abi-version"); + } + if (!DriverArgs.hasArg(options::OPT_fptrauth_intrinsics, options::OPT_fno_ptrauth_intrinsics)) CC1Args.push_back("-fptrauth-intrinsics"); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 4a0d765f57eb..2ec87a363010 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3263,11 +3263,25 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts, ArgumentConsumer Consumer) { if (Opts.PointerAuthIntrinsics) GenerateArg(Consumer, OPT_fptrauth_intrinsics); + + if (Opts.PointerAuthABIVersionEncoded) { + GenerateArg(Consumer, OPT_fptrauth_abi_version_EQ, + Twine(Opts.PointerAuthABIVersion)); + if (Opts.PointerAuthKernelABIVersion) + GenerateArg(Consumer, OPT_fptrauth_kernel_abi_version); + } } static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { Opts.PointerAuthIntrinsics = Args.hasArg(OPT_fptrauth_intrinsics); + + Opts.PointerAuthABIVersionEncoded = + Args.hasArg(OPT_fptrauth_abi_version_EQ) || + Args.hasArg(OPT_fptrauth_kernel_abi_version); + Opts.PointerAuthABIVersion = + getLastArgIntValue(Args, OPT_fptrauth_abi_version_EQ, 0, Diags); + Opts.PointerAuthKernelABIVersion = Args.hasArg(OPT_fptrauth_kernel_abi_version); } /// Check if input file kind and language standard are compatible. diff --git a/clang/test/CodeGen/ptrauth-abi-version.c b/clang/test/CodeGen/ptrauth-abi-version.c new file mode 100644 index 000000000000..299bd9401a88 --- /dev/null +++ b/clang/test/CodeGen/ptrauth-abi-version.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 %s -triple arm64e-apple-ios -disable-llvm-passes -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-NONE +// RUN: %clang_cc1 %s -fptrauth-kernel-abi-version -triple arm64e-apple-ios -disable-llvm-passes -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-WITH --check-prefix=CHECK-ZEROK +// RUN: %clang_cc1 %s -fptrauth-abi-version=0 -triple arm64e-apple-ios -disable-llvm-passes -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-WITH --check-prefix=CHECK-ZERO +// RUN: %clang_cc1 %s -fptrauth-abi-version=0 -fptrauth-kernel-abi-version -triple arm64e-apple-ios -disable-llvm-passes -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-WITH --check-prefix=CHECK-ZEROK +// RUN: %clang_cc1 %s -fptrauth-abi-version=5 -triple arm64e-apple-ios -disable-llvm-passes -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-WITH --check-prefix=CHECK-FIVE +// RUN: %clang_cc1 %s -fptrauth-abi-version=5 -fptrauth-kernel-abi-version -triple arm64e-apple-ios -disable-llvm-passes -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-WITH --check-prefix=CHECK-FIVEK + +int f(void) { + return 0; +} +// CHECK-NONE-NOT: ptrauth.abi-version +// CHECK-WITH: !llvm.module.flags = !{{{.*}} ![[ABI_VERSION_REF:[0-9]+]]} +// CHECK-WITH: ![[ABI_VERSION_REF]] = !{i32 6, !"ptrauth.abi-version", ![[ABI_VERSION_VAR:[0-9]+]]} +// CHECK-WITH: ![[ABI_VERSION_VAR]] = !{![[ABI_VERSION_VAL:[0-9]+]]} +// CHECK-ZERO: ![[ABI_VERSION_VAL]] = !{i32 0, i1 false} +// CHECK-ZEROK: ![[ABI_VERSION_VAL]] = !{i32 0, i1 true} +// CHECK-FIVE: ![[ABI_VERSION_VAL]] = !{i32 5, i1 false} +// CHECK-FIVEK: ![[ABI_VERSION_VAL]] = !{i32 5, i1 true} diff --git a/clang/test/Driver/arch-arm64e-abi-versioning-defaults.c b/clang/test/Driver/arch-arm64e-abi-versioning-defaults.c new file mode 100644 index 000000000000..b30156b1845b --- /dev/null +++ b/clang/test/Driver/arch-arm64e-abi-versioning-defaults.c @@ -0,0 +1,16 @@ +// Check the ABI version support defaults. + +// RUN: %clang -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix ABIVERSION-DEFAULT --check-prefix NOKERNELABIVERSION +// RUN: %clang -mkernel -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix ABIVERSION-DEFAULT --check-prefix KERNELABIVERSION +// RUN: %clang -fapple-kext -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix ABIVERSION-DEFAULT --check-prefix KERNELABIVERSION +// +// RUN: %clang -fno-ptrauth-kernel-abi-version -mkernel -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix ABIVERSION-DEFAULT --check-prefix NOKERNELABIVERSION +// RUN: %clang -mkernel -fno-ptrauth-kernel-abi-version -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix ABIVERSION-DEFAULT --check-prefix NOKERNELABIVERSION +// RUN: %clang -fno-ptrauth-kernel-abi-version -fapple-kext -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix ABIVERSION-DEFAULT --check-prefix NOKERNELABIVERSION +// RUN: %clang -fapple-kext -fno-ptrauth-kernel-abi-version -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix ABIVERSION-DEFAULT --check-prefix NOKERNELABIVERSION +// RUN: %clang -fno-ptrauth-kernel-abi-version -fptrauth-kernel-abi-version -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix ABIVERSION-DEFAULT --check-prefix NOKERNELABIVERSION +// RUN: %clang -fptrauth-kernel-abi-version -fno-ptrauth-kernel-abi-version -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix ABIVERSION-DEFAULT --check-prefix NOKERNELABIVERSION +// +// ABIVERSION-DEFAULT: "-fptrauth-abi-version=0" +// KERNELABIVERSION: "-fptrauth-kernel-abi-version" +// NOKERNELABIVERSION-NOT: fptrauth-kernel-abi-version diff --git a/clang/test/Driver/arch-arm64e-abi-versioning.c b/clang/test/Driver/arch-arm64e-abi-versioning.c new file mode 100644 index 000000000000..bb5767a57952 --- /dev/null +++ b/clang/test/Driver/arch-arm64e-abi-versioning.c @@ -0,0 +1,16 @@ +// Check the ABI version support. + +// RUN: %clang -fptrauth-abi-version=5 -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix ABIVERSION --check-prefix NOKERNELABIVERSION +// RUN: %clang -fptrauth-abi-version=5 -mkernel -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix ABIVERSION --check-prefix KERNELABIVERSION +// RUN: %clang -fptrauth-abi-version=5 -fapple-kext -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix ABIVERSION --check-prefix KERNELABIVERSION +// RUN: %clang -fptrauth-abi-version=5 -fptrauth-kernel-abi-version -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix ABIVERSION --check-prefix KERNELABIVERSION + +// RUN: %clang -fno-ptrauth-abi-version -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix NOABIVERSION --check-prefix NOKERNELABIVERSION +// RUN: %clang -fptrauth-abi-version=5 -fno-ptrauth-abi-version -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix NOABIVERSION --check-prefix NOKERNELABIVERSION +// RUN: %clang -fno-ptrauth-abi-version -fptrauth-abi-version=5 -arch arm64e -c %s -### 2>&1 | FileCheck %s --check-prefix ABIVERSION --check-prefix NOKERNELABIVERSION + +// ABIVERSION: "-fptrauth-abi-version=5" +// ABIVERSION-DEFAULT: "-fptrauth-abi-version=0" +// NOABIVERSION-NOT: fptrauth-abi-version +// KERNELABIVERSION: "-fptrauth-kernel-abi-version" +// NOKERNELABIVERSION-NOT: fptrauth-kernel-abi-version diff --git a/clang/test/Preprocessor/ptrauth_abi_version.c b/clang/test/Preprocessor/ptrauth_abi_version.c new file mode 100644 index 000000000000..be5e2f9abc93 --- /dev/null +++ b/clang/test/Preprocessor/ptrauth_abi_version.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm64e-apple-ios < /dev/null | FileCheck %s --check-prefix=NONE +// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm64e-apple-ios -fptrauth-abi-version=0 < /dev/null | FileCheck %s --check-prefix=ZERO +// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm64e-apple-ios -fptrauth-kernel-abi-version < /dev/null | FileCheck %s --check-prefix=ZERO +// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm64e-apple-ios -fptrauth-abi-version=5 < /dev/null | FileCheck %s --check-prefix=FIVE + +// ZERO: #define __ptrauth_abi_version__ 0 +// FIVE: #define __ptrauth_abi_version__ 5 +// NONE-NOT: __ptrauth_abi_version__ diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp index bc398fa0731f..3d99600cefc1 100644 --- a/clang/tools/driver/cc1as_main.cpp +++ b/clang/tools/driver/cc1as_main.cpp @@ -164,6 +164,13 @@ struct AssemblerInvocation { /// The name of a file to use with \c .secure_log_unique directives. std::string AsSecureLogFile; + + /// The ptrauth ABI version targeted by the backend. + unsigned PointerAuthABIVersion; + /// Whether the ptrauth ABI version represents a kernel ABI. + unsigned PointerAuthKernelABIVersion : 1; + /// Whether the assembler should encode the ptrauth ABI version. + unsigned PointerAuthABIVersionEncoded : 1; /// @} public: @@ -336,6 +343,14 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, Args.hasArg(OPT_mincremental_linker_compatible); Opts.SymbolDefs = Args.getAllArgValues(OPT_defsym); + Opts.PointerAuthABIVersionEncoded = + Args.hasArg(OPT_fptrauth_abi_version_EQ) || + Args.hasArg(OPT_fptrauth_kernel_abi_version); + Opts.PointerAuthABIVersion = + getLastArgIntValue(Args, OPT_fptrauth_abi_version_EQ, 0, Diags); + Opts.PointerAuthKernelABIVersion = + Args.hasArg(OPT_fptrauth_kernel_abi_version); + // EmbedBitcode Option. If -fembed-bitcode is enabled, set the flag. // EmbedBitcode behaves the same for all embed options for assembly files. if (auto *A = Args.getLastArg(OPT_fembed_bitcode_EQ)) { @@ -561,6 +576,11 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts, // Assembly to object compilation should leverage assembly info. Str->setUseAssemblerInfoForParsing(true); + // Emit the ptrauth ABI version, if any. + if (Opts.PointerAuthABIVersionEncoded) + Str->EmitPtrAuthABIVersion(Opts.PointerAuthABIVersion, + Opts.PointerAuthKernelABIVersion); + bool Failed = false; std::unique_ptr Parser( diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 47ab3879657a..7a69489d5512 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -7876,6 +7876,11 @@ stored at:: !llvm.embedded.objects = !{!0} !0 = !{ptr @object, !".section"} +Pointer Authentication ABI Version Module Flags Metadata +-------------------------------------------------------- + +FIXME: write about abi version, maybe? + Automatic Linker Flags Named Metadata ===================================== diff --git a/llvm/include/llvm/BinaryFormat/MachO.h b/llvm/include/llvm/BinaryFormat/MachO.h index f59cd14c1b5c..f63abdaa63cf 100644 --- a/llvm/include/llvm/BinaryFormat/MachO.h +++ b/llvm/include/llvm/BinaryFormat/MachO.h @@ -1647,8 +1647,39 @@ enum CPUSubTypeARM64 { CPU_SUBTYPE_ARM64_ALL = 0, CPU_SUBTYPE_ARM64_V8 = 1, CPU_SUBTYPE_ARM64E = 2, + + // arm64 reserves bits in the high byte for subtype-specific flags. + // On arm64e, the 6 low bits represent the ptrauth ABI version. + CPU_SUBTYPE_ARM64E_PTRAUTH_MASK = 0x3f000000, + // On arm64e, the top bit tells whether the Mach-O is versioned. + CPU_SUBTYPE_ARM64E_VERSIONED_PTRAUTH_ABI_MASK = 0x80000000, + // On arm64e, the 2nd high bit tells whether the Mach-O is using kernel ABI. + CPU_SUBTYPE_ARM64E_KERNEL_PTRAUTH_ABI_MASK = 0x40000000 }; +inline int CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(unsigned ST) { + return (ST & CPU_SUBTYPE_ARM64E_PTRAUTH_MASK) >> 24; +} + +inline unsigned +CPU_SUBTYPE_ARM64E_WITH_PTRAUTH_VERSION(unsigned PtrAuthABIVersion, + bool PtrAuthKernelABIVersion) { + assert((PtrAuthABIVersion <= 0x3F) && + "ptrauth abi version must fit in 6 bits"); + return CPU_SUBTYPE_ARM64E | CPU_SUBTYPE_ARM64E_VERSIONED_PTRAUTH_ABI_MASK | + (PtrAuthKernelABIVersion ? CPU_SUBTYPE_ARM64E_KERNEL_PTRAUTH_ABI_MASK + : 0) | + (PtrAuthABIVersion << 24); +} + +inline unsigned CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(unsigned ST) { + return ST & CPU_SUBTYPE_ARM64E_VERSIONED_PTRAUTH_ABI_MASK; +} + +inline unsigned CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(unsigned ST) { + return ST & CPU_SUBTYPE_ARM64E_KERNEL_PTRAUTH_ABI_MASK; +} + enum CPUSubTypeARM64_32 { CPU_SUBTYPE_ARM64_32_V8 = 1 }; enum CPUSubTypeSPARC { CPU_SUBTYPE_SPARC_ALL = 0 }; @@ -1674,6 +1705,8 @@ enum CPUSubTypePowerPC { Expected getCPUType(const Triple &T); Expected getCPUSubType(const Triple &T); +Expected getCPUSubType(const Triple &T, unsigned PtrAuthABIVersion, + bool PtrAuthKernelABIVersion); struct x86_thread_state32_t { uint32_t eax; diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h index 61b19409a96d..121862fd1040 100644 --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -995,6 +995,20 @@ class LLVM_EXTERNAL_VISIBILITY Module { VersionTuple getSDKVersion() const; /// @} + /// With ptrauth enabled, the module has a version that is used to represent + /// ABI changes. + struct PtrAuthABIVersion { + int Version = 0; + bool Kernel = false; + }; + /// Return all the ptrauth abi versions that the module has. + SmallVector getPtrAuthABIVersions() const; + /// Return the "final" ptrauth abi version for the module. This handles errors + /// and does not report them to the caller. + std::optional getPtrAuthABIVersion() const; + /// Set the ptrauth abi version in the module. + void setPtrAuthABIVersion(PtrAuthABIVersion ABIVersion); + /// Take ownership of the given memory buffer. void setOwnedMemoryBuffer(std::unique_ptr MB); diff --git a/llvm/include/llvm/MC/MCAssembler.h b/llvm/include/llvm/MC/MCAssembler.h index 5e1fc738b1da..b5afbcb5040d 100644 --- a/llvm/include/llvm/MC/MCAssembler.h +++ b/llvm/include/llvm/MC/MCAssembler.h @@ -168,6 +168,9 @@ class MCAssembler { VersionInfoType VersionInfo; VersionInfoType DarwinTargetVariantVersionInfo; + std::optional PtrAuthABIVersion; + bool PtrAuthKernelABIVersion; + /// Evaluate a fixup to a relocatable expression and the value which should be /// placed into the fixup. /// @@ -314,6 +317,13 @@ class MCAssembler { DarwinTargetVariantVersionInfo.SDKVersion = SDKVersion; } + std::optional getPtrAuthABIVersion() const { + return PtrAuthABIVersion; + } + void setPtrAuthABIVersion(unsigned V) { PtrAuthABIVersion = V; } + bool getPtrAuthKernelABIVersion() const { return PtrAuthKernelABIVersion; } + void setPtrAuthKernelABIVersion(bool V) { PtrAuthKernelABIVersion = V; } + /// Reuse an assembler instance /// void reset(); diff --git a/llvm/include/llvm/MC/MCMachObjectWriter.h b/llvm/include/llvm/MC/MCMachObjectWriter.h index 05d816671b1a..aa05ad781654 100644 --- a/llvm/include/llvm/MC/MCMachObjectWriter.h +++ b/llvm/include/llvm/MC/MCMachObjectWriter.h @@ -177,7 +177,9 @@ class MachObjectWriter : public MCObjectWriter { /// @} void writeHeader(MachO::HeaderFileType Type, unsigned NumLoadCommands, - unsigned LoadCommandsSize, bool SubsectionsViaSymbols); + unsigned LoadCommandsSize, bool SubsectionsViaSymbols, + std::optional PtrAuthABIVersion, + bool PtrAuthKernelABIVersion); /// Write a segment load command. /// diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h index 3bf2d22e1823..4c07eed95234 100644 --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -524,6 +524,9 @@ class MCStreamer { const Triple *DarwinTargetVariantTriple, const VersionTuple &DarwinTargetVariantSDKVersion); + /// Specify Mach-O ptrauth ABI version. + virtual void EmitPtrAuthABIVersion(unsigned PtrAuthABIVersion, bool PtrAuthKernelABIVersion) {} + /// Note in the output that the specified \p Func is a Thumb mode /// function (ARM target only). virtual void emitThumbFunc(MCSymbol *Func); diff --git a/llvm/lib/BinaryFormat/MachO.cpp b/llvm/lib/BinaryFormat/MachO.cpp index 1b5941cf5275..4c682897241e 100644 --- a/llvm/lib/BinaryFormat/MachO.cpp +++ b/llvm/lib/BinaryFormat/MachO.cpp @@ -105,3 +105,21 @@ Expected MachO::getCPUSubType(const Triple &T) { return getPowerPCSubType(T); return unsupported("subtype", T); } + +Expected MachO::getCPUSubType(const Triple &T, + unsigned PtrAuthABIVersion, + bool PtrAuthKernelABIVersion) { + Expected Result = MachO::getCPUSubType(T); + if (!Result) + return Result.takeError(); + if (*Result != MachO::CPU_SUBTYPE_ARM64E) + return createStringError( + std::errc::invalid_argument, + "ptrauth ABI version is only supported on arm64e."); + if (PtrAuthABIVersion > 63) + return createStringError( + std::errc::invalid_argument, + "The ptrauth ABI version needs to fit within 6 bits."); + return CPU_SUBTYPE_ARM64E_WITH_PTRAUTH_VERSION(PtrAuthABIVersion, + PtrAuthKernelABIVersion); +} diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp index 5de0f027afae..c5ccb91736a0 100644 --- a/llvm/lib/IR/AutoUpgrade.cpp +++ b/llvm/lib/IR/AutoUpgrade.cpp @@ -4934,12 +4934,24 @@ void llvm::UpgradeARCRuntime(Module &M) { UpgradeToIntrinsic(I.first, I.second); } +// arm64e always needs the ptrauth.abi-version metadata, even when there are no +// module flags at all. +static bool insertMissingPtrAuthABIVersion(Module &M) { + Triple TT(M.getTargetTriple()); + if (TT.isArm64e()) { + M.setPtrAuthABIVersion(/*PointerAuthABIVersion=*/{-1}); + return true; + } + return false; +} + bool llvm::UpgradeModuleFlags(Module &M) { NamedMDNode *ModFlags = M.getModuleFlagsMetadata(); if (!ModFlags) - return false; + return insertMissingPtrAuthABIVersion(M); bool HasObjCFlag = false, HasClassProperties = false, Changed = false; + bool HasPtrAuthABIVersion = false; bool HasSwiftVersionFlag = false; uint8_t SwiftMajorVersion, SwiftMinorVersion; uint32_t SwiftABIVersion; @@ -5042,6 +5054,9 @@ bool llvm::UpgradeModuleFlags(Module &M) { Changed = true; } } + + if (ID->getString() == "ptrauth.abi-version") + HasPtrAuthABIVersion = true; } // "Objective-C Class Properties" is recently added for Objective-C. We @@ -5065,6 +5080,9 @@ bool llvm::UpgradeModuleFlags(Module &M) { Changed = true; } + if (!HasPtrAuthABIVersion) + Changed |= insertMissingPtrAuthABIVersion(M); + return Changed; } diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp index 5861bbd1f293..c8aa0143abb2 100644 --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -814,6 +814,86 @@ VersionTuple Module::getSDKVersion() const { return getSDKVersionMD(getModuleFlag("SDK Version")); } +SmallVector +Module::getPtrAuthABIVersions() const { + // Look for the ptrauth abi version in the module flags. + SmallVector Result; + const Metadata *Meta = getModuleFlag("ptrauth.abi-version"); + if (!Meta) + return Result; + const MDNode *MD = cast(Meta); + + auto extractVersionFromOperand = [](const Metadata *Meta) { + const auto *CV = cast(Meta)->getValue(); + return cast(CV)->getSExtValue(); + }; + + // If there are multiple versions, there's a mismatch. In that case, fall + // back to version "64". + if (MD->getNumOperands() == 1) { + int V = extractVersionFromOperand( + cast(MD->getOperand(0))->getOperand(0)); + // The version -1 has special meaning: we're treating old bitcode files with + // no ptrauth abi version. In that case, we want to fall back to the old + // behavior where the flags are 0. + if (V == -1) + return Result; + bool K = extractVersionFromOperand( + cast(MD->getOperand(0))->getOperand(1)); + Result.push_back({V, K}); + return Result; + } else if (MD->getNumOperands() >= 2) { + // If we do have multiple versions, print them in a warning. + int LV = extractVersionFromOperand( + cast(MD->getOperand(0))->getOperand(0)); + bool LK = extractVersionFromOperand( + cast(MD->getOperand(0))->getOperand(1)); + Result.push_back({LV, LK}); + int RV = extractVersionFromOperand( + cast(MD->getOperand(1))->getOperand(0)); + bool RK = extractVersionFromOperand( + cast(MD->getOperand(1))->getOperand(1)); + Result.push_back({RV, RK}); + return Result; + } else { + llvm_unreachable( + "Malformed ptrauth.abi-version metadata with no operands."); + return {}; + } +} + +std::optional Module::getPtrAuthABIVersion() const { + SmallVector Versions = getPtrAuthABIVersions(); + if (Versions.size() == 0) + return std::nullopt; + if (Versions.size() == 1) { + int V = Versions[0].Version; + if (V == -1) + return std::nullopt; + if (V > 64) + V = 64; + bool K = Versions[0].Kernel; + return PtrAuthABIVersion{V, K}; + } + // If there are multiple versions, there's a mismatch. In that case, fall + // back to version "64". + if (Versions.size() == 2) + return PtrAuthABIVersion{64, false}; + llvm_unreachable("Mismatch between more than two ptrauth abi versions."); +} + +void Module::setPtrAuthABIVersion(Module::PtrAuthABIVersion ABIVersion) { + // Add a module flag containing a tuple of i32s representing the version. + llvm::LLVMContext &Ctx = getContext(); + auto *ABIVer = llvm::ConstantAsMetadata::get( + llvm::ConstantInt::get(Type::getInt32Ty(Ctx), ABIVersion.Version)); + auto *KernelABI = llvm::ConstantAsMetadata::get( + llvm::ConstantInt::get(Type::getInt1Ty(Ctx), ABIVersion.Kernel)); + auto *ABIVerNode = llvm::MDNode::get(Ctx, {ABIVer, KernelABI}); + auto *ABIVerNodes = llvm::MDNode::get(Ctx, ABIVerNode); + addModuleFlag(llvm::Module::AppendUnique, "ptrauth.abi-version", ABIVerNodes); +} + GlobalVariable *llvm::collectUsedGlobalVariables( const Module &M, SmallVectorImpl &Vec, bool CompilerUsed) { const char *Name = CompilerUsed ? "llvm.compiler.used" : "llvm.used"; diff --git a/llvm/lib/LTO/LTOModule.cpp b/llvm/lib/LTO/LTOModule.cpp index 868169e78225..5032b602cee4 100644 --- a/llvm/lib/LTO/LTOModule.cpp +++ b/llvm/lib/LTO/LTOModule.cpp @@ -29,6 +29,7 @@ #include "llvm/Object/IRObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -686,6 +687,13 @@ Expected LTOModule::getMachOCPUType() const { } Expected LTOModule::getMachOCPUSubType() const { + if (Error E = const_cast(Mod.get())->materializeMetadata()) + return std::move(E); + // If there is a ptrauth version in the module, take that into account. + if (std::optional ABIVersion = + Mod->getPtrAuthABIVersion()) + return MachO::getCPUSubType(Triple(Mod->getTargetTriple()), + ABIVersion->Version, ABIVersion->Kernel); return MachO::getCPUSubType(Triple(Mod->getTargetTriple())); } diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index 06de70ad2f39..341c66c2109c 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -169,6 +169,8 @@ class MCAsmStreamer final : public MCStreamer { void emitDarwinTargetVariantBuildVersion(unsigned Platform, unsigned Major, unsigned Minor, unsigned Update, VersionTuple SDKVersion) override; + void EmitPtrAuthABIVersion(unsigned PtrAuthABIVersion, + bool PtrAuthKernelABIVersion) override; void emitThumbFunc(MCSymbol *Func) override; void emitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; @@ -662,6 +664,16 @@ void MCAsmStreamer::emitDarwinTargetVariantBuildVersion( emitBuildVersion(Platform, Major, Minor, Update, SDKVersion); } +void MCAsmStreamer::EmitPtrAuthABIVersion(unsigned PtrAuthABIVersion, + bool PtrAuthKernelABIVersion) { + if (PtrAuthKernelABIVersion) + OS << "\t.ptrauth_kernel_abi_version "; + else + OS << "\t.ptrauth_abi_version "; + OS << PtrAuthABIVersion; + EmitEOL(); +} + void MCAsmStreamer::emitThumbFunc(MCSymbol *Func) { // This needs to emit to a temporary string to get properly quoted // MCSymbols when they have spaces in them. diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp index 1cc408e11447..4ec273522554 100644 --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -91,6 +91,8 @@ MCAssembler::MCAssembler(MCContext &Context, IncrementalLinkerCompatible(false), ELFHeaderEFlags(0) { VersionInfo.Major = 0; // Major version == 0 for "none specified" DarwinTargetVariantVersionInfo.Major = 0; + PtrAuthABIVersion = std::nullopt; + PtrAuthKernelABIVersion = false; } MCAssembler::~MCAssembler() = default; @@ -113,6 +115,8 @@ void MCAssembler::reset() { VersionInfo.SDKVersion = VersionTuple(); DarwinTargetVariantVersionInfo.Major = 0; DarwinTargetVariantVersionInfo.SDKVersion = VersionTuple(); + PtrAuthABIVersion = std::nullopt; + PtrAuthKernelABIVersion = false; // reset objects owned by us if (getBackendPtr()) diff --git a/llvm/lib/MC/MCMachOStreamer.cpp b/llvm/lib/MC/MCMachOStreamer.cpp index 589855b30d0c..ea7a204db16e 100644 --- a/llvm/lib/MC/MCMachOStreamer.cpp +++ b/llvm/lib/MC/MCMachOStreamer.cpp @@ -99,6 +99,8 @@ class MCMachOStreamer : public MCObjectStreamer { void emitDarwinTargetVariantBuildVersion(unsigned Platform, unsigned Major, unsigned Minor, unsigned Update, VersionTuple SDKVersion) override; + void EmitPtrAuthABIVersion(unsigned PtrAuthABIVersion, + bool PtrAuthKernelABIVersion) override; void emitThumbFunc(MCSymbol *Func) override; bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; void emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override; @@ -309,6 +311,12 @@ void MCMachOStreamer::emitDarwinTargetVariantBuildVersion( (MachO::PlatformType)Platform, Major, Minor, Update, SDKVersion); } +void MCMachOStreamer::EmitPtrAuthABIVersion(unsigned PtrAuthABIVersion, + bool PtrAuthKernelABIVersion) { + getAssembler().setPtrAuthABIVersion(PtrAuthABIVersion); + getAssembler().setPtrAuthKernelABIVersion(PtrAuthKernelABIVersion); +} + void MCMachOStreamer::emitThumbFunc(MCSymbol *Symbol) { // Remember that the function is a thumb function. Fixup and relocation // values will need adjusted. diff --git a/llvm/lib/MC/MCParser/DarwinAsmParser.cpp b/llvm/lib/MC/MCParser/DarwinAsmParser.cpp index 7c390041b369..4dcf005d65a9 100644 --- a/llvm/lib/MC/MCParser/DarwinAsmParser.cpp +++ b/llvm/lib/MC/MCParser/DarwinAsmParser.cpp @@ -194,6 +194,10 @@ class DarwinAsmParser : public MCAsmParserExtension { addDirectiveHandler<&DarwinAsmParser::parseBuildVersion>(".build_version"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveCGProfile>( ".cg_profile"); + addDirectiveHandler<&DarwinAsmParser::parsePtrAuthABIVersion>( + ".ptrauth_abi_version"); + addDirectiveHandler<&DarwinAsmParser::parsePtrAuthKernelABIVersion>( + ".ptrauth_kernel_abi_version"); LastVersionDirective = SMLoc(); } @@ -467,6 +471,9 @@ class DarwinAsmParser : public MCAsmParserExtension { void checkVersion(StringRef Directive, StringRef Arg, SMLoc Loc, Triple::OSType ExpectedOS); bool parseDirectiveCGProfile(StringRef Directive, SMLoc Loc); + + bool parsePtrAuthABIVersion(StringRef Directive, SMLoc Loc); + bool parsePtrAuthKernelABIVersion(StringRef Directive, SMLoc Loc); }; } // end anonymous namespace @@ -1207,6 +1214,46 @@ bool DarwinAsmParser::parseDirectiveCGProfile(StringRef S, SMLoc Loc) { return MCAsmParserExtension::ParseDirectiveCGProfile(S, Loc); } +/// parsePtrAuthABIVersion +/// ::= .ptrauth_abi_version version +bool DarwinAsmParser::parsePtrAuthABIVersion(StringRef Directive, SMLoc Loc) { + int64_t PtrAuthABIVersion; + if (getParser().parseIntToken(PtrAuthABIVersion, + "expected integer version in '.ptrauth_abi_version' directive")) + return true; + + if (PtrAuthABIVersion > 63 || PtrAuthABIVersion < 0) + return TokError("invalid ptrauth ABI version number"); + + if (parseToken(AsmToken::EndOfStatement)) + return addErrorSuffix(" in '.ptrauth_abi_version' directive"); + + getStreamer().EmitPtrAuthABIVersion(PtrAuthABIVersion, + /*PtrAuthKernelABIVersion=*/false); + return false; +} + +/// parsePtrAuthKernelABIVersion +/// ::= .ptrauth_kernel_abi_version version +bool DarwinAsmParser::parsePtrAuthKernelABIVersion(StringRef Directive, + SMLoc Loc) { + int64_t PtrAuthKernelABIVersion; + if (getParser().parseIntToken(PtrAuthKernelABIVersion, + "expected integer version in " + "'.ptrauth_kernel_abi_version' directive")) + return true; + + if (PtrAuthKernelABIVersion > 63 || PtrAuthKernelABIVersion < 0) + return TokError("invalid ptrauth kernel ABI version number"); + + if (parseToken(AsmToken::EndOfStatement)) + return addErrorSuffix(" in '.ptrauth_kernel_abi_version' directive"); + + getStreamer().EmitPtrAuthABIVersion(PtrAuthKernelABIVersion, + /*PtrAuthKernelABIVersion=*/true); + return false; +} + namespace llvm { MCAsmParserExtension *createDarwinAsmParser() { diff --git a/llvm/lib/MC/MachObjectWriter.cpp b/llvm/lib/MC/MachObjectWriter.cpp index 04097dfe2e9f..35f105291463 100644 --- a/llvm/lib/MC/MachObjectWriter.cpp +++ b/llvm/lib/MC/MachObjectWriter.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator_range.h" #include "llvm/BinaryFormat/MachO.h" @@ -135,7 +136,9 @@ uint64_t MachObjectWriter::getPaddingSize(const MCSection *Sec, void MachObjectWriter::writeHeader(MachO::HeaderFileType Type, unsigned NumLoadCommands, unsigned LoadCommandsSize, - bool SubsectionsViaSymbols) { + bool SubsectionsViaSymbols, + std::optional PtrAuthABIVersion, + bool PtrAuthKernelABIVersion) { uint32_t Flags = 0; if (SubsectionsViaSymbols) @@ -150,7 +153,22 @@ void MachObjectWriter::writeHeader(MachO::HeaderFileType Type, W.write(is64Bit() ? MachO::MH_MAGIC_64 : MachO::MH_MAGIC); W.write(TargetObjectWriter->getCPUType()); - W.write(TargetObjectWriter->getCPUSubtype()); + + uint32_t Cpusubtype = TargetObjectWriter->getCPUSubtype(); + if (PtrAuthABIVersion) { + assert(TargetObjectWriter->getCPUType() == MachO::CPU_TYPE_ARM64 && + Cpusubtype == MachO::CPU_SUBTYPE_ARM64E && + "ptrauth ABI version is only supported on arm64e"); + // Changes to this format should be reflected in MachO::getCPUSubType to + // support LTO. + // FIXME: Use MachO::getCPUSubType here. We can't use it for now because at + // the time we create TargetObjectWriter, we don't know if the assembler + // encountered any directives that affect the result. + Cpusubtype = MachO::CPU_SUBTYPE_ARM64E_WITH_PTRAUTH_VERSION( + *PtrAuthABIVersion, PtrAuthKernelABIVersion); + } + + W.write(Cpusubtype); W.write(Type); W.write(NumLoadCommands); @@ -871,9 +889,19 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, offsetToAlignment(SectionDataFileSize, is64Bit() ? Align(8) : Align(4)); SectionDataFileSize += SectionDataPadding; + // The ptrauth ABI version is limited to 4 bits. + std::optional PtrAuthABIVersion = Asm.getPtrAuthABIVersion(); + if (PtrAuthABIVersion && *PtrAuthABIVersion > 63) { + Asm.getContext().reportError(SMLoc(), "invalid ptrauth ABI version: " + + utostr(*PtrAuthABIVersion)); + PtrAuthABIVersion = 63; + } + bool PtrAuthKernelABIVersion = Asm.getPtrAuthKernelABIVersion(); + // Write the prolog, starting with the header and load command... writeHeader(MachO::MH_OBJECT, NumLoadCommands, LoadCommandsSize, - Asm.getSubsectionsViaSymbols()); + Asm.getSubsectionsViaSymbols(), PtrAuthABIVersion, + PtrAuthKernelABIVersion); uint32_t Prot = MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE; writeSegmentLoadCommand("", NumSections, 0, VMSize, SectionDataStart, diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index ca3c6f1e02b1..24ceced4cef5 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -134,7 +134,7 @@ static unsigned getCPUType(const MachOObjectFile &O) { } static unsigned getCPUSubType(const MachOObjectFile &O) { - return O.getHeader().cpusubtype; + return O.getHeader().cpusubtype & ~MachO::CPU_SUBTYPE_MASK; } static uint32_t diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index e4c08b81dc7b..06d09d3e27f8 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -209,6 +209,9 @@ class AArch64AsmPrinter : public AsmPrinter { void emitFunctionBodyEnd() override; MCSymbol *GetCPISymbol(unsigned CPID) const override; + + void EmitPtrAuthVersion(Module &M); + void emitEndOfAsmFile(Module &M) override; AArch64FunctionInfo *AArch64FI = nullptr; @@ -262,6 +265,9 @@ void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) { S, MCConstantExpr::create(Feat00Value, MMI->getContext())); } + if (TM.getTargetTriple().isOSBinFormatMachO()) + EmitPtrAuthVersion(M); + if (!TT.isOSBinFormatELF()) return; @@ -551,6 +557,59 @@ void AArch64AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) { OutStreamer->emitLabel(Pass); } +class PtrauthABIVersionDiagnosticInfo : public DiagnosticInfo { + int V1, V2; + bool K1, K2; +public: + PtrauthABIVersionDiagnosticInfo(int V1, bool K1, int V2, bool K2) + : DiagnosticInfo(DK_Linker, DS_Warning), V1(V1), V2(V2), K1(K1), K2(K2) {} + void print(DiagnosticPrinter &DP) const override { + const char *Mode1 = K1 ? "kernel" : "user"; + const char *Mode2 = K2 ? "kernel" : "user"; + DP << "incompatible ptrauth ABI versions: " << V1 << " (" << Mode1 + << ") and " << V2 << " (" << Mode2 << "), falling back to 63 (user)"; + } +}; + +void AArch64AsmPrinter::EmitPtrAuthVersion(Module &M) { + // Emit the ptrauth ABI version, if any. + SmallVector Versions = + M.getPtrAuthABIVersions(); + if (Versions.size() == 0) + return; + + // The ptrauth ABI version is an arm64e concept, only implemented for MachO. + const Triple &TT = TM.getTargetTriple(); + if (!TT.isOSBinFormatMachO()) + report_fatal_error("ptrauth ABI version support not yet implemented"); + + LLVMContext &Ctx = M.getContext(); + + Module::PtrAuthABIVersion V = Versions[0]; + if (Versions.size() == 1) { + if (V.Version > 63) { + Ctx.emitError("invalid ptrauth ABI version: " + utostr(V.Version)); + V.Version = 63; + V.Kernel = false; + } + } + // If there are multiple versions, there's a mismatch. In that case, fall + // back to version "15", and emit a warning through the context. + if (Versions.size() == 2) { + int LV = Versions[0].Version; + bool LK = Versions[0].Kernel; + int RV = Versions[1].Version; + bool RK = Versions[1].Kernel; + V.Version = 63; + V.Kernel = false; + Ctx.diagnose(PtrauthABIVersionDiagnosticInfo(LV, LK, RV, RK)); + } + assert(Versions.size() <= 2 && + "Mismatch between more than two ptrauth abi versions."); + + OutStreamer->EmitPtrAuthABIVersion(V.Version, V.Kernel); +} + void AArch64AsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) { Register Reg = MI.getOperand(0).getReg(); bool IsShort = diff --git a/llvm/test/Bitcode/upgrade-ptrauth.ll b/llvm/test/Bitcode/upgrade-ptrauth.ll new file mode 100644 index 000000000000..6eaa3d1d8a9b --- /dev/null +++ b/llvm/test/Bitcode/upgrade-ptrauth.ll @@ -0,0 +1,7 @@ +; RUN: llvm-dis < %s.bc| FileCheck %s + +; Apple Internal: Upgrade files with no ptrauth-abi-version to version -1. +; CHECK: !llvm.module.flags = !{!0} +; CHECK: !0 = !{i32 6, !"ptrauth.abi-version", !1} +; CHECK: !1 = !{!2} +; CHECK: !2 = !{i32 -1, i1 false} diff --git a/llvm/test/Bitcode/upgrade-ptrauth.ll.bc b/llvm/test/Bitcode/upgrade-ptrauth.ll.bc new file mode 100644 index 0000000000000000000000000000000000000000..57df8c613d8a994c7b53e7b7353a4eb3f3173430 GIT binary patch literal 1152 zcmXX_K}_3b6n5eeXOR7NX;cznM|SBXRJGJeXh}#i5!|6noSy8tg0rqA(SYAb`wR>%BD_2+FnAR^uPE1 z=jZ=_-}nBvz1-4-fmmP-8!+rYkX~VV`#c12h=tAksW{b;uYKpt81^sNCOwDg!JdFc z%(dMPpsZ?=?D|$)LQ(wOwphQ&eDH zKbSXtXJLiDB>SVz=~S$z+fSz*pXV;$X0<$=dy9p8z&cOnP3+(e!yWFP0;;TJ)0XD` zo2e#cu%EI_7($|6H0t{x6T^-#%4u~fhj+KD7feJfPE3IlRHrk<*VIj)6&pDmvc0dn zSkHZ}da&kJ!;j1-GK5dgH`QjF`xbn|Cqt1%(dc$Yt)e zudXnUvvh=SsHY`b3%EZo_*1yQ5KB$U#5EH!6I5lHn3eIVm@2cXt#AzOrBR6|$9S?_ zMO6{Gs5NGrqc=HbRkBC;Ti%BW?}p%6!hH`DJ_Yv{s+Oq`ac!9B8djsA<0{~jLja4I zdes2OPRG@cP3pK+jb_xD%-os%D%vlizn9S-kB9SFx{{>}b-g9g>m0o{$E-`nU($jn zFL*L_{Xlas2<{~AUC_?KrH9wOPjPQfGygE6$^&XtPD~CHv5-1xRVNo!+v5+&eT@7| zM3pou_mCwP?Ewn5o!MHkuLkT-IC^W&zEz|vCFW0^Jz~A&&I#Rj6W)S&>NSv%Ivpco znM?f#X|l$E{Zsq8L_g=4?G@$=oxN5t$5bWbhc^=Lg67Q$ejwy<)mIU`N!V(s?;8QB zIt}%hh}m``nwh&?rqJFp+7Z!9zHQ}6z+Ne}Y?hd9C?II_<`Vv;M605?Q-Y_U`5vrz z@)}_D6@p9SCIYG&2LcCF+wYIiUWj~AG*(%1hbMPf@*fe6QK-x#*uE?p|0tr0h+gqR z={Jtq&C*p}y>hAV>93j_nw8VeZ3^85p*tyb1L_UoZR{KC(Ofk(M%$rR#O#2a5&S@T zPVj7K*LUeh**BjDYENmGV~#jD(OC|mXChEbR%!&3&qQ>PE5g6f`TN9d4*_rVX9~lN zV2Oh7Uc!49nuq%r6Fz8UTGK&XVlnIuu*VI7GmwhaV#+ZLYgKSvZEgvX`pF`J12WDY z&AAg%Cl#z(ORdXCFzYSgHRB84)&f_hkuis(gYV!!8JT2x=TK*7m#fR^8FD)$DG~<9 v;X3bjM8XcV?jsvyv>24xJtOY@&8b$LMJNh9mVq3}%1W literal 0 HcmV?d00001 diff --git a/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-default.ll b/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-default.ll new file mode 100644 index 000000000000..85e6948aa272 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-default.ll @@ -0,0 +1,3 @@ +; RUN: llc -mtriple arm64e-apple-darwin -o - %s | FileCheck %s + +; CHECK-NOT: .ptrauth_abi_version diff --git a/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-invalid.ll b/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-invalid.ll new file mode 100644 index 000000000000..f00f7f85e74b --- /dev/null +++ b/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-invalid.ll @@ -0,0 +1,10 @@ +; RUN: not llc -mtriple arm64e-apple-darwin -o - %s 2> %t | FileCheck %s +; RUN: FileCheck < %t %s --check-prefix=ERROR + +; ERROR: error: invalid ptrauth ABI version: 64 +; CHECK: .ptrauth_abi_version 63 + +!0 = !{ i32 64, i1 false } +!1 = !{ !0 } +!2 = !{ i32 6, !"ptrauth.abi-version", !1 } +!llvm.module.flags = !{ !2 } diff --git a/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-mismatch.ll b/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-mismatch.ll new file mode 100644 index 000000000000..1cbfe1c17650 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-mismatch.ll @@ -0,0 +1,11 @@ +; RUN: llc -mtriple arm64e-apple-darwin -o - %s 2> %t | FileCheck %s +; RUN: FileCheck < %t %s --check-prefix=WARNING + +; WARNING: warning: incompatible ptrauth ABI versions: 5 (user) and 2 (user), falling back to 63 (user) +; CHECK: .ptrauth_abi_version 63 + +!0 = !{ i32 5, i1 false } +!1 = !{ i32 2, i1 false } +!2 = !{ !0, !1 } +!3 = !{ i32 6, !"ptrauth.abi-version", !2 } +!llvm.module.flags = !{ !3 } diff --git a/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-old.ll b/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-old.ll new file mode 100644 index 000000000000..83e463083606 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-old.ll @@ -0,0 +1,13 @@ +; RUN: llc -mtriple arm64e-apple-darwin -o - %s | FileCheck %s +; RUN: llc -filetype=obj -mtriple arm64e-apple-darwin -o - %s | llvm-objdump --macho -d -p - | FileCheck %s --check-prefix=OBJ + +; CHECK-NOT: .ptrauth_abi_version + +; OBJ: Mach header +; OBJ: magic cputype cpusubtype caps filetype ncmds sizeofcmds flags +; OBJ: MH_MAGIC_64 ARM64 E 0x00 OBJECT 3 256 SUBSECTIONS_VIA_SYMBOLS + +!0 = !{ i32 -1, i1 false } +!1 = !{ !0 } +!2 = !{ i32 6, !"ptrauth.abi-version", !1 } +!llvm.module.flags = !{ !2 } diff --git a/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-zero.ll b/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-zero.ll new file mode 100644 index 000000000000..a01439167c43 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version-zero.ll @@ -0,0 +1,8 @@ +; RUN: llc -mtriple arm64e-apple-darwin -o - %s | FileCheck %s + +; CHECK: .ptrauth_abi_version 0 + +!0 = !{ i32 0, i1 false } +!1 = !{ !0 } +!2 = !{ i32 6, !"ptrauth.abi-version", !1 } +!llvm.module.flags = !{ !2 } diff --git a/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version.ll b/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version.ll new file mode 100644 index 000000000000..1bcd1818c180 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/arm64e-ptrauth-abi-version.ll @@ -0,0 +1,8 @@ +; RUN: llc -mtriple arm64e-apple-darwin -o - %s | FileCheck %s + +; CHECK: .ptrauth_abi_version 5 + +!0 = !{ i32 5, i1 false } +!1 = !{ !0 } +!2 = !{ i32 6, !"ptrauth.abi-version", !1 } +!llvm.module.flags = !{ !2 } diff --git a/llvm/test/CodeGen/AArch64/arm64e-ptrauth-kernel-abi-version.ll b/llvm/test/CodeGen/AArch64/arm64e-ptrauth-kernel-abi-version.ll new file mode 100644 index 000000000000..d32a0a5ca94e --- /dev/null +++ b/llvm/test/CodeGen/AArch64/arm64e-ptrauth-kernel-abi-version.ll @@ -0,0 +1,8 @@ +; RUN: llc -mtriple arm64e-apple-darwin -o - %s | FileCheck %s + +; CHECK: .ptrauth_kernel_abi_version 5 + +!0 = !{ i32 5, i1 true } +!1 = !{ !0 } +!2 = !{ i32 6, !"ptrauth.abi-version", !1 } +!llvm.module.flags = !{ !2 } diff --git a/llvm/test/LTO/AArch64/arm64e-print-macho-cpu.ll b/llvm/test/LTO/AArch64/arm64e-print-macho-cpu.ll new file mode 100644 index 000000000000..aec5558f1a9b --- /dev/null +++ b/llvm/test/LTO/AArch64/arm64e-print-macho-cpu.ll @@ -0,0 +1,8 @@ +; RUN: rm -rf %t && mkdir -p %t +; RUN: llvm-as -o %t/1.bc %s +; RUN: llvm-lto -print-macho-cpu-only %t/1.bc | FileCheck %s + +target triple = "arm64e-apple-darwin" +; CHECK: 1.bc: +; CHECK-NEXT: cputype: 16777228 +; CHECK-NEXT: cpusubtype: 2 diff --git a/llvm/test/LTO/AArch64/arm64e-ptrauth-abi-version-print-macho-cpu.ll b/llvm/test/LTO/AArch64/arm64e-ptrauth-abi-version-print-macho-cpu.ll new file mode 100644 index 000000000000..71632fdd7665 --- /dev/null +++ b/llvm/test/LTO/AArch64/arm64e-ptrauth-abi-version-print-macho-cpu.ll @@ -0,0 +1,14 @@ +; RUN: rm -rf %t && mkdir -p %t +; RUN: llvm-as -o %t/1.bc %s +; RUN: llvm-lto -print-macho-cpu-only %t/1.bc | FileCheck %s +; RUN: llvm-lto -print-macho-cpu-only-local %t/1.bc | FileCheck %s + +target triple = "arm64e-apple-darwin" + +!0 = !{ i32 5, i1 false } +!1 = !{ !0 } +!2 = !{ i32 6, !"ptrauth.abi-version", !1 } +!llvm.module.flags = !{ !2 } +; CHECK: 1.bc: +; CHECK-NEXT: cputype: 16777228 +; CHECK-NEXT: cpusubtype: 2231369730 diff --git a/llvm/test/LTO/AArch64/arm64e-ptrauth-kernel-abi-version-print-macho-cpu.ll b/llvm/test/LTO/AArch64/arm64e-ptrauth-kernel-abi-version-print-macho-cpu.ll new file mode 100644 index 000000000000..6d869bb5e8db --- /dev/null +++ b/llvm/test/LTO/AArch64/arm64e-ptrauth-kernel-abi-version-print-macho-cpu.ll @@ -0,0 +1,13 @@ +; RUN: rm -rf %t && mkdir -p %t +; RUN: llvm-as -o %t/1.bc %s +; RUN: llvm-lto -print-macho-cpu-only %t/1.bc | FileCheck %s + +target triple = "arm64e-apple-darwin" + +!0 = !{ i32 5, i1 true } +!1 = !{ !0 } +!2 = !{ i32 6, !"ptrauth.abi-version", !1 } +!llvm.module.flags = !{ !2 } +; CHECK: 1.bc: +; CHECK-NEXT: cputype: 16777228 +; CHECK-NEXT: cpusubtype: 3305111554 diff --git a/llvm/test/Linker/Inputs/module-flags-ptrauth-abi-version-3.ll b/llvm/test/Linker/Inputs/module-flags-ptrauth-abi-version-3.ll new file mode 100644 index 000000000000..b409afe96632 --- /dev/null +++ b/llvm/test/Linker/Inputs/module-flags-ptrauth-abi-version-3.ll @@ -0,0 +1,4 @@ +!0 = !{ i32 3, i1 false } +!1 = !{ !0 } +!2 = !{ i32 6, !"ptrauth.abi-version", !1 } +!llvm.module.flags = !{ !2 } diff --git a/llvm/test/Linker/Inputs/module-flags-ptrauth-abi-version-5.ll b/llvm/test/Linker/Inputs/module-flags-ptrauth-abi-version-5.ll new file mode 100644 index 000000000000..0efd50ce24bd --- /dev/null +++ b/llvm/test/Linker/Inputs/module-flags-ptrauth-abi-version-5.ll @@ -0,0 +1,4 @@ +!0 = !{ i32 5, i1 false } +!1 = !{ !0 } +!2 = !{ i32 6, !"ptrauth.abi-version", !1 } +!llvm.module.flags = !{ !2 } diff --git a/llvm/test/Linker/Inputs/module-flags-ptrauth-kernel-abi-version-3.ll b/llvm/test/Linker/Inputs/module-flags-ptrauth-kernel-abi-version-3.ll new file mode 100644 index 000000000000..818246ad154c --- /dev/null +++ b/llvm/test/Linker/Inputs/module-flags-ptrauth-kernel-abi-version-3.ll @@ -0,0 +1,4 @@ +!0 = !{ i32 3, i1 true } +!1 = !{ !0 } +!2 = !{ i32 6, !"ptrauth.abi-version", !1 } +!llvm.module.flags = !{ !2 } diff --git a/llvm/test/Linker/module-flags-ptrauth-abi-version-a.ll b/llvm/test/Linker/module-flags-ptrauth-abi-version-a.ll new file mode 100644 index 000000000000..f748ca4cd23d --- /dev/null +++ b/llvm/test/Linker/module-flags-ptrauth-abi-version-a.ll @@ -0,0 +1,35 @@ +; RUN: llvm-link %p/Inputs/module-flags-ptrauth-abi-version-5.ll %p/Inputs/module-flags-ptrauth-abi-version-5.ll -S -o - | FileCheck %s --check-prefix=SAME --check-prefix=CHECK +; RUN: llvm-link %p/Inputs/module-flags-ptrauth-abi-version-3.ll %p/Inputs/module-flags-ptrauth-abi-version-5.ll -S -o - | FileCheck %s --check-prefix=DIFFERENT --check-prefix=CHECK +; RUN: llvm-link %p/Inputs/module-flags-ptrauth-abi-version-3.ll %p/Inputs/module-flags-ptrauth-abi-version-5.ll %p/Inputs/module-flags-ptrauth-abi-version-3.ll -S -o - | FileCheck %s --check-prefix=DIFFERENT-MORE --check-prefix=CHECK +; RUN: llvm-link %s %p/Inputs/module-flags-ptrauth-abi-version-3.ll -S -o - | FileCheck %s --check-prefix=EMPTY --check-prefix=CHECK + + +; CHECK: !llvm.module.flags = !{!0} +; CHECK: !0 = {{(distinct )?}}!{i32 6, !"ptrauth.abi-version", !1} + +; test linking modules with the same ptrauth.abi-version: it should merge them +; SAME: !1 = distinct !{!2} +; SAME: !2 = !{i32 5, i1 false} + +; test linking modules with different ptrauth.abi-versions: it should append them +; DIFFERENT: !1 = distinct !{!2, !3} +; DIFFERENT: !2 = !{i32 3, i1 false} +; DIFFERENT: !3 = !{i32 5, i1 false} + +; test linking modules with three different ptrauth.abi-versions where two are the same: it should unique and append them +; DIFFERENT-MORE: !1 = distinct !{!2, !3} +; DIFFERENT-MORE: !2 = !{i32 3, i1 false} +; DIFFERENT-MORE: !3 = !{i32 5, i1 false} + +; test linking modules with no ptrauth.abi-version on one side: it should pick it up from the one that has it +; EMPTY: !1 = !{!2} +; EMPTY: !2 = !{i32 3, i1 false} + +; FIXME: test linking modules with no ptrauth.abi-version on one side: we +; auto-upgrade it to the version -1, and append it. We can't do this now because +; the module materializer doesn't run the auto-upgrader during llvm-link. + +; test linking modules with different modes: kernel and userand user: it should append them +; DIFFERENT-KERNEL: !1 = !{!2, !3} +; DIFFERENT-KERNEL: !2 = !{i32 3, i1 true} +; DIFFERENT-KERNEL: !3 = !{i32 3, i1 false} diff --git a/llvm/test/MC/AArch64/arm64e-ptrauth-abi-version.s b/llvm/test/MC/AArch64/arm64e-ptrauth-abi-version.s new file mode 100644 index 000000000000..4aa81f4ac578 --- /dev/null +++ b/llvm/test/MC/AArch64/arm64e-ptrauth-abi-version.s @@ -0,0 +1,15 @@ +; RUN: sed -e "s,VERSION,0,g" %s | llvm-mc -triple=arm64e-apple-ios -filetype=obj - -o - | llvm-objdump --macho -d -p - | FileCheck %s --check-prefix=V0 +; RUN: sed -e "s,VERSION,15,g" %s | llvm-mc -triple=arm64e-apple-ios -filetype=obj - -o - | llvm-objdump --macho -d -p - | FileCheck %s --check-prefix=V15 +; RUN: sed -e "s,VERSION,64,g" %s | not llvm-mc -triple=arm64e-apple-ios -filetype=obj - -o - 2>&1 | FileCheck %s --check-prefix=V64 + +; V15: Mach header +; V15: magic cputype cpusubtype caps filetype ncmds sizeofcmds flags +; V15: MH_MAGIC_64 ARM64 E PAC15 OBJECT 3 256 0x00000000 + +; V0: Mach header +; V0: magic cputype cpusubtype caps filetype ncmds sizeofcmds flags +; V0: MH_MAGIC_64 ARM64 E PAC00 OBJECT 3 256 0x00000000 + +; V64: error: invalid ptrauth ABI version number + +.ptrauth_abi_version VERSION diff --git a/llvm/test/tools/llvm-objdump/AArch64/Inputs/fat.macho-arm64e-kernel-ptrauth-abi b/llvm/test/tools/llvm-objdump/AArch64/Inputs/fat.macho-arm64e-kernel-ptrauth-abi new file mode 100644 index 0000000000000000000000000000000000000000..cd53fc1f7b9a2e048b5e88d547f758731ced4a1e GIT binary patch literal 4128 zcmeI$p$&jQ5Jb_x=o6Gc|0N*KoxxBE4InNInhHq%B%AEo=Vp(&cc2Q|fCbi^Y?<~h kMgavBP(T3%6i`3`1r$&~0R{dqaNgHU(XSN$ksrV(4;=*v+W-In literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-objdump/AArch64/Inputs/fat.macho-arm64e-ptrauth-abi b/llvm/test/tools/llvm-objdump/AArch64/Inputs/fat.macho-arm64e-ptrauth-abi new file mode 100644 index 0000000000000000000000000000000000000000..e8094fe2e66fea67d7c410b45e2a94895cf63257 GIT binary patch literal 4128 zcmeI$u?>JQ3`Egy>J*H?vRNtx1JE!D3s6KHH4`BHlPuZo>(0j7>3Mim}0tzUgfCB#)IPYtw=vRt=&kx{}2NH=0TL1t6 literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-objdump/AArch64/macho-universal-arm64e-kernel-ptrauth-abi.test b/llvm/test/tools/llvm-objdump/AArch64/macho-universal-arm64e-kernel-ptrauth-abi.test new file mode 100644 index 000000000000..c40a5dbd8459 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/AArch64/macho-universal-arm64e-kernel-ptrauth-abi.test @@ -0,0 +1,13 @@ +RUN: llvm-objdump %p/Inputs/fat.macho-arm64e-kernel-ptrauth-abi -m -p --universal-headers | FileCheck %s + +CHECK: Fat headers +CHECK: fat_magic FAT_MAGIC +CHECK: nfat_arch 1 +CHECK: architecture arm64e +CHECK: cputype CPU_TYPE_ARM64 +CHECK: cpusubtype CPU_SUBTYPE_ARM64E +CHECK: capabilities CPU_SUBTYPE_ARM64E_KERNEL_PTRAUTH_VERSION 5 + +CHECK: Mach header +CHECK: magic cputype cpusubtype caps filetype ncmds sizeofcmds flags +CHECK: MH_MAGIC_64 ARM64 E PAK05 OBJECT 0 0 0x00000000 diff --git a/llvm/test/tools/llvm-objdump/AArch64/macho-universal-arm64e-ptrauth-abi.test b/llvm/test/tools/llvm-objdump/AArch64/macho-universal-arm64e-ptrauth-abi.test new file mode 100644 index 000000000000..df352f52eeb1 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/AArch64/macho-universal-arm64e-ptrauth-abi.test @@ -0,0 +1,13 @@ +RUN: llvm-objdump %p/Inputs/fat.macho-arm64e-ptrauth-abi -m -p --universal-headers | FileCheck %s + +CHECK: Fat headers +CHECK: fat_magic FAT_MAGIC +CHECK: nfat_arch 1 +CHECK: architecture arm64e +CHECK: cputype CPU_TYPE_ARM64 +CHECK: cpusubtype CPU_SUBTYPE_ARM64E +CHECK: capabilities CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION 5 + +CHECK: Mach header +CHECK: magic cputype cpusubtype caps filetype ncmds sizeofcmds flags +CHECK: MH_MAGIC_64 ARM64 E PAC05 OBJECT 0 0 0x00000000 diff --git a/llvm/test/tools/llvm-objdump/macho-ptrauth-cpusubtype.test b/llvm/test/tools/llvm-objdump/macho-ptrauth-cpusubtype.test new file mode 100644 index 000000000000..5a06df071337 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/macho-ptrauth-cpusubtype.test @@ -0,0 +1,23 @@ +#RUN: sed -e "s,SRC_CPUSUBTYPE,0x80000002,g" %s | yaml2obj -o -| llvm-objdump --macho -p - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=V0 +#RUN: sed -e "s,SRC_CPUSUBTYPE,0x81000002,g" %s | yaml2obj -o -| llvm-objdump --macho -p - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=V1 +#RUN: sed -e "s,SRC_CPUSUBTYPE,0xc1000002,g" %s | yaml2obj -o -| llvm-objdump --macho -p - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=V1K +#RUN: sed -e "s,SRC_CPUSUBTYPE,0x00000002,g" %s | yaml2obj -o -| llvm-objdump --macho -p - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=VNONE + +# CHECK: Mach header +# CHECK: magic cputype cpusubtype caps filetype ncmds sizeofcmds flags +# V0: MH_MAGIC_64 ARM64 E PAC00 OBJECT 0 0 0x00000000 +# V1: MH_MAGIC_64 ARM64 E PAC01 OBJECT 0 0 0x00000000 +# V1K: MH_MAGIC_64 ARM64 E PAK01 OBJECT 0 0 0x00000000 +# VNONE: MH_MAGIC_64 ARM64 E 0x00 OBJECT 0 0 0x00000000 + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x0100000C + cpusubtype: SRC_CPUSUBTYPE + filetype: 0x00000001 + ncmds: 0 + sizeofcmds: 0 + flags: 0x00000000 + reserved: 0x00000000 +... diff --git a/llvm/tools/dsymutil/MachOUtils.cpp b/llvm/tools/dsymutil/MachOUtils.cpp index 44c925fce5c2..55943297f045 100644 --- a/llvm/tools/dsymutil/MachOUtils.cpp +++ b/llvm/tools/dsymutil/MachOUtils.cpp @@ -409,6 +409,19 @@ bool generateDsymCompanion( bool Is64Bit = Writer.is64Bit(); MachO::symtab_command SymtabCmd = InputBinary.getSymtabLoadCommand(); + // Get the ptrauth ABI version (for arm64 subtypes). + std::optional PtrAuthABIVersion; + bool PtrAuthKernelABIVersion = false; + unsigned CPUType = InputBinary.getHeader().cputype; + unsigned CPUSubTypeField = InputBinary.getHeader().cpusubtype; + if (CPUType == MachO::CPU_TYPE_ARM64 && + MachO::CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(CPUSubTypeField)) { + PtrAuthABIVersion = + MachO::CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(CPUSubTypeField); + PtrAuthKernelABIVersion = + MachO::CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(CPUSubTypeField); + } + // Compute the number of load commands we will need. unsigned LoadCommandSize = 0; unsigned NumLoadCommands = 0; @@ -529,7 +542,9 @@ bool generateDsymCompanion( SymtabStart = alignTo(SymtabStart, 0x1000); // We gathered all the information we need, start emitting the output file. - Writer.writeHeader(MachO::MH_DSYM, NumLoadCommands, LoadCommandSize, false); + Writer.writeHeader(MachO::MH_DSYM, NumLoadCommands, LoadCommandSize, + /*SubsectionsViaSymbols=*/false, PtrAuthABIVersion, + PtrAuthKernelABIVersion); // Write the load commands. assert(OutFile.tell() == HeaderSize); diff --git a/llvm/tools/llvm-lto/llvm-lto.cpp b/llvm/tools/llvm-lto/llvm-lto.cpp index abd45b305df0..5ed5779f9b41 100644 --- a/llvm/tools/llvm-lto/llvm-lto.cpp +++ b/llvm/tools/llvm-lto/llvm-lto.cpp @@ -256,6 +256,10 @@ static cl::opt PrintMachOCPUOnly( cl::desc("Instead of running LTO, print the mach-o cpu in each IR file"), cl::cat(LTOCategory)); +static cl::opt PrintMachOCPUOnlyLocal( + "print-macho-cpu-only-local", cl::init(false), + cl::desc("Same as print-macho-cpu-only, but using createInLocalContext.")); + static cl::opt DebugPassManager("debug-pass-manager", cl::init(false), cl::Hidden, cl::desc("Print pass management debugging information"), @@ -451,19 +455,26 @@ static void listDependentLibraries() { } } -static void printMachOCPUOnly() { +static void printMachOCPUOnly(bool Local) { LLVMContext Context; Context.setDiagnosticHandler(std::make_unique(), true); TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple()); for (auto &Filename : InputFilenames) { - ErrorOr> ModuleOrErr = - LTOModule::createFromFile(Context, Filename, Options); - if (!ModuleOrErr) - error(ModuleOrErr, "llvm-lto: "); + std::unique_ptr Buffer; + std::unique_ptr Module; + if (Local) { + Module = getLocalLTOModule(Filename, Buffer, Options); + } else { + ErrorOr> ModuleOrErr = + LTOModule::createFromFile(Context, Filename, Options); + if (!ModuleOrErr) + error(ModuleOrErr, "llvm-lto: "); + Module = std::move(*ModuleOrErr); + } - Expected CPUType = (*ModuleOrErr)->getMachOCPUType(); - Expected CPUSubType = (*ModuleOrErr)->getMachOCPUSubType(); + Expected CPUType = Module->getMachOCPUType(); + Expected CPUSubType = Module->getMachOCPUSubType(); if (!CPUType) error("Error while printing mach-o cputype: " + toString(CPUType.takeError())); @@ -980,8 +991,8 @@ int main(int argc, char **argv) { return 0; } - if (PrintMachOCPUOnly) { - printMachOCPUOnly(); + if (PrintMachOCPUOnly || PrintMachOCPUOnlyLocal) { + printMachOCPUOnly(PrintMachOCPUOnlyLocal); return 0; } diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp index 296cd698304d..d371b58b7658 100644 --- a/llvm/tools/llvm-objdump/MachODump.cpp +++ b/llvm/tools/llvm-objdump/MachODump.cpp @@ -2447,7 +2447,15 @@ static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB, outs() << " cpusubtype " << (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) << "\n"; } - if (verbose && + if (verbose && cputype == MachO::CPU_TYPE_ARM64 && + MachO::CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(cpusubtype)) { + outs() << " capabilities CPU_SUBTYPE_ARM64E_"; + if (MachO::CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(cpusubtype)) + outs() << "KERNEL_"; + outs() << format("PTRAUTH_VERSION %d", + MachO::CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(cpusubtype)) + << "\n"; + } else if (verbose && (cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64) outs() << " capabilities CPU_SUBTYPE_LIB64\n"; else @@ -8677,7 +8685,17 @@ static void PrintMachHeader(uint32_t magic, uint32_t cputype, outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK); break; } - if ((cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64) { + + if (cputype == MachO::CPU_TYPE_ARM64 && + MachO::CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(cpusubtype)) { + const char *Format = + MachO::CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(cpusubtype) + ? " PAK%02d" + : " PAC%02d"; + outs() << format(Format, + MachO::CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(cpusubtype)); + } else if ((cpusubtype & MachO::CPU_SUBTYPE_MASK) == + MachO::CPU_SUBTYPE_LIB64) { outs() << " LIB64"; } else { outs() << format(" 0x%02" PRIx32, diff --git a/llvm/unittests/BinaryFormat/MachOTest.cpp b/llvm/unittests/BinaryFormat/MachOTest.cpp index 391298ff38d7..182fdc05d04b 100644 --- a/llvm/unittests/BinaryFormat/MachOTest.cpp +++ b/llvm/unittests/BinaryFormat/MachOTest.cpp @@ -116,3 +116,44 @@ TEST(MachOTest, CPUSubType) { } #undef CHECK_CPUSUBTYPE } + +TEST(MachOTest, CPUSubTypePtrAuthABI) { + { + Expected Type = MachO::getCPUSubType( + Triple("x86_64-apple-darwin"), /*PtrAuthABIVersion=*/5, + /*PtrAuthKernelABIVersion=*/false); + ASSERT_EQ(toString(Type.takeError()), + "ptrauth ABI version is only supported on arm64e."); + } + { + Expected Type = MachO::getCPUSubType( + Triple("arm64e-apple-darwin"), /*PtrAuthABIVersion=*/0x40, + /*PtrAuthKernelABIVersion=*/false); + ASSERT_EQ(toString(Type.takeError()), + "The ptrauth ABI version needs to fit within 6 bits."); + } + { + uint32_t Type = cantFail(MachO::getCPUSubType( + Triple("arm64e-apple-darwin"), + /*PtrAuthABIVersion=*/5, /*PtrAuthKernelABIVersion=*/false)); + ASSERT_EQ(Type, 2231369730U); + } + { + uint32_t Type = cantFail(MachO::getCPUSubType( + Triple("arm64e-apple-darwin"), + /*PtrAuthABIVersion=*/5, /*PtrAuthKernelABIVersion=*/true)); + ASSERT_EQ(Type, 3305111554U); + } + { + uint32_t Type = cantFail(MachO::getCPUSubType( + Triple("arm64e-apple-darwin"), + /*PtrAuthABIVersion=*/0, /*PtrAuthKernelABIVersion=*/false)); + ASSERT_EQ(Type, 2147483650U); + } + { + uint32_t Type = cantFail(MachO::getCPUSubType( + Triple("arm64e-apple-darwin"), + /*PtrAuthABIVersion=*/0, /*PtrAuthKernelABIVersion=*/true)); + ASSERT_EQ(Type, 3221225474U); + } +}