From 8ba75e7019725fc0bbfc5e1a8aee57879b4881b6 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Mon, 15 Apr 2024 04:56:18 +0300 Subject: [PATCH 1/9] [clang] PR85235 --- clang/include/clang/Basic/Features.def | 6 ++ clang/include/clang/Basic/LangOptions.def | 6 ++ clang/include/clang/Driver/Options.td | 8 ++ clang/lib/CodeGen/CodeGenModule.cpp | 31 +++++++ clang/lib/Driver/ToolChains/Clang.cpp | 20 ++++ clang/lib/Frontend/CompilerInvocation.cpp | 20 ++++ clang/test/CodeGen/aarch64-elf-pauthabi.c | 59 ++++++++++++ clang/test/Driver/aarch64-ptrauth.c | 36 +++++++- clang/test/Preprocessor/ptrauth_feature.c | 107 +++++++++++++++++++++- 9 files changed, 289 insertions(+), 4 deletions(-) create mode 100644 clang/test/CodeGen/aarch64-elf-pauthabi.c diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index fe4d1c4afcca..b762e44e755e 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -103,6 +103,12 @@ FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread)) FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow)) FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo)) FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics) +FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls) +FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns) +FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination) +FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination) +FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls) +FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini) EXTENSION(swiftcc, PP.getTargetInfo().checkCallingConvention(CC_Swift) == clang::TargetInfo::CCCR_OK) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 8ef6700ecdc7..4b99e7029846 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -162,6 +162,12 @@ 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") +LANGOPT(PointerAuthCalls , 1, 0, "function pointer authentication") +LANGOPT(PointerAuthReturns, 1, 0, "return pointer authentication") +LANGOPT(PointerAuthAuthTraps, 1, 0, "pointer authentication failure traps") +LANGOPT(PointerAuthVTPtrAddressDiscrimination, 1, 0, "incorporate address discrimination in authenticated vtable pointers") +LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, "incorporate type discrimination in authenticated vtable pointers") +LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays") 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 52d161703f96..13e60e8766c2 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4148,6 +4148,14 @@ defm strict_return : BoolFOption<"strict-return", let Flags = [TargetSpecific] in { defm ptrauth_intrinsics : OptInCC1FFlag<"ptrauth-intrinsics", "Enable pointer authentication intrinsics">; +defm ptrauth_calls : OptInCC1FFlag<"ptrauth-calls", "Enable signing and authentication of all indirect calls">; +defm ptrauth_returns : OptInCC1FFlag<"ptrauth-returns", "Enable signing and authentication of return addresses">; +defm ptrauth_auth_traps : OptInCC1FFlag<"ptrauth-auth-traps", "Enable traps on authentication failures">; +defm ptrauth_vtable_pointer_address_discrimination : + OptInCC1FFlag<"ptrauth-vtable-pointer-address-discrimination", "Enable address discrimination of vtable pointers">; +defm ptrauth_vtable_pointer_type_discrimination : + OptInCC1FFlag<"ptrauth-vtable-pointer-type-discrimination", "Enable type discrimination of vtable pointers">; +defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of function pointers in init/fini arrays">; } def fenable_matrix : Flag<["-"], "fenable-matrix">, Group, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 0c447b20cef4..540b6d036291 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -53,6 +53,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" #include "llvm/IR/AttributeMask.h" #include "llvm/IR/CallingConv.h" @@ -1189,6 +1190,36 @@ void CodeGenModule::Release() { if (!LangOpts.isSignReturnAddressWithAKey()) getModule().addModuleFlag(llvm::Module::Min, "sign-return-address-with-bkey", 1); + + if (getTriple().isOSLinux() && getTriple().isOSBinFormatELF()) { + using namespace llvm::ELF; + uint64_t PAuthABIVersion = + (LangOpts.PointerAuthIntrinsics + << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INTRINSICS) | + (LangOpts.PointerAuthCalls + << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_CALLS) | + (LangOpts.PointerAuthReturns + << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_RETURNS) | + (LangOpts.PointerAuthAuthTraps + << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_AUTHTRAPS) | + (LangOpts.PointerAuthVTPtrAddressDiscrimination + << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRADDRDISCR) | + (LangOpts.PointerAuthVTPtrTypeDiscrimination + << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRTYPEDISCR) | + (LangOpts.PointerAuthInitFini + << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI); + static_assert(AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI == + AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST, + "Update when new enum items are defined"); + if (PAuthABIVersion != 0) { + getModule().addModuleFlag(llvm::Module::Error, + "aarch64-elf-pauthabi-platform", + AARCH64_PAUTH_PLATFORM_LLVM_LINUX); + getModule().addModuleFlag(llvm::Module::Error, + "aarch64-elf-pauthabi-version", + PAuthABIVersion); + } + } } if (CodeGenOpts.StackClashProtector) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 97b4aa1c9b1d..88984e9f156e 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1782,6 +1782,26 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_intrinsics, options::OPT_fno_ptrauth_intrinsics); + + Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_calls, + options::OPT_fno_ptrauth_calls); + + Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_returns, + options::OPT_fno_ptrauth_returns); + + Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_auth_traps, + options::OPT_fno_ptrauth_auth_traps); + + Args.addOptInFlag( + CmdArgs, options::OPT_fptrauth_vtable_pointer_address_discrimination, + options::OPT_fno_ptrauth_vtable_pointer_address_discrimination); + + Args.addOptInFlag( + CmdArgs, options::OPT_fptrauth_vtable_pointer_type_discrimination, + options::OPT_fno_ptrauth_vtable_pointer_type_discrimination); + + Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_init_fini, + options::OPT_fno_ptrauth_init_fini); } void Clang::AddLoongArchTargetArgs(const ArgList &Args, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 8236051e30c4..40731af0c9fb 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3319,11 +3319,31 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts, ArgumentConsumer Consumer) { if (Opts.PointerAuthIntrinsics) GenerateArg(Consumer, OPT_fptrauth_intrinsics); + if (Opts.PointerAuthCalls) + GenerateArg(Consumer, OPT_fptrauth_calls); + if (Opts.PointerAuthReturns) + GenerateArg(Consumer, OPT_fptrauth_returns); + if (Opts.PointerAuthAuthTraps) + GenerateArg(Consumer, OPT_fptrauth_auth_traps); + if (Opts.PointerAuthVTPtrAddressDiscrimination) + GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_address_discrimination); + if (Opts.PointerAuthVTPtrTypeDiscrimination) + GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_type_discrimination); + if (Opts.PointerAuthInitFini) + GenerateArg(Consumer, OPT_fptrauth_init_fini); } static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { Opts.PointerAuthIntrinsics = Args.hasArg(OPT_fptrauth_intrinsics); + Opts.PointerAuthCalls = Args.hasArg(OPT_fptrauth_calls); + Opts.PointerAuthReturns = Args.hasArg(OPT_fptrauth_returns); + Opts.PointerAuthAuthTraps = Args.hasArg(OPT_fptrauth_auth_traps); + Opts.PointerAuthVTPtrAddressDiscrimination = + Args.hasArg(OPT_fptrauth_vtable_pointer_address_discrimination); + Opts.PointerAuthVTPtrTypeDiscrimination = + Args.hasArg(OPT_fptrauth_vtable_pointer_type_discrimination); + Opts.PointerAuthInitFini = Args.hasArg(OPT_fptrauth_init_fini); } /// Check if input file kind and language standard are compatible. diff --git a/clang/test/CodeGen/aarch64-elf-pauthabi.c b/clang/test/CodeGen/aarch64-elf-pauthabi.c new file mode 100644 index 000000000000..35f0579c4c84 --- /dev/null +++ b/clang/test/CodeGen/aarch64-elf-pauthabi.c @@ -0,0 +1,59 @@ +// RUN: %clang --target=aarch64-linux -S -emit-llvm -o - \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-auth-traps \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-init-fini %s | \ +// RUN: FileCheck %s --check-prefix=ALL + +// RUN: %clang --target=aarch64-linux -S -emit-llvm -o - \ +// RUN: -fptrauth-intrinsics %s | FileCheck %s --check-prefix=INTRIN + +// RUN: %clang --target=aarch64-linux -S -emit-llvm -o - \ +// RUN: -fptrauth-calls %s | FileCheck %s --check-prefix=CALL + +// RUN: %clang --target=aarch64-linux -S -emit-llvm -o - \ +// RUN: -fptrauth-returns %s | FileCheck %s --check-prefix=RET + +// RUN: %clang --target=aarch64-linux -S -emit-llvm -o - \ +// RUN: -fptrauth-auth-traps %s | FileCheck %s --check-prefix=TRAP + +// RUN: %clang --target=aarch64-linux -S -emit-llvm -o - \ +// RUN: -fptrauth-calls -fptrauth-vtable-pointer-address-discrimination %s | \ +// RUN: FileCheck %s --check-prefix=VPTRADDR + +// RUN: %clang --target=aarch64-linux -S -emit-llvm -o - \ +// RUN: -fptrauth-calls -fptrauth-vtable-pointer-type-discrimination %s | \ +// RUN: FileCheck %s --check-prefix=VPTRTYPE + +// RUN: %clang --target=aarch64-linux -S -emit-llvm -o - \ +// RUN: -fptrauth-calls -fptrauth-init-fini %s | \ +// RUN: FileCheck %s --check-prefix=INITFINI + +// ALL: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// ALL: !{i32 1, !"aarch64-elf-pauthabi-version", i32 127} + +// INTRIN: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// INTRIN: !{i32 1, !"aarch64-elf-pauthabi-version", i32 1} + +// CALL: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// CALL: !{i32 1, !"aarch64-elf-pauthabi-version", i32 2} + +// RET: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// RET: !{i32 1, !"aarch64-elf-pauthabi-version", i32 4} + +// TRAP: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// TRAP: !{i32 1, !"aarch64-elf-pauthabi-version", i32 8} + +// VPTRADDR: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// VPTRADDR: !{i32 1, !"aarch64-elf-pauthabi-version", i32 18} + +// VPTRTYPE: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// VPTRTYPE: !{i32 1, !"aarch64-elf-pauthabi-version", i32 34} + +// INITFINI: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// INITFINI: !{i32 1, !"aarch64-elf-pauthabi-version", i32 66} + +void foo() {} diff --git a/clang/test/Driver/aarch64-ptrauth.c b/clang/test/Driver/aarch64-ptrauth.c index 1a69b2c6edfb..9ae0347a8ccb 100644 --- a/clang/test/Driver/aarch64-ptrauth.c +++ b/clang/test/Driver/aarch64-ptrauth.c @@ -1,5 +1,37 @@ +// RUN: %clang -### -c --target=aarch64 %s 2>&1 | FileCheck %s --check-prefix NONE +// NONE: "-cc1" +// NONE-NOT: "-fptrauth- + // RUN: %clang -### -c --target=aarch64 -fno-ptrauth-intrinsics -fptrauth-intrinsics %s 2>&1 | FileCheck %s --check-prefix=INTRIN // INTRIN: "-cc1"{{.*}} "-fptrauth-intrinsics" -// RUN: not %clang -### -c --target=x86_64 -fptrauth-intrinsics %s 2>&1 | FileCheck %s --check-prefix=ERR -// ERR: error: unsupported option '-fptrauth-intrinsics' for target '{{.*}}' +// RUN: %clang -### -c --target=aarch64 -fno-ptrauth-calls -fptrauth-calls %s 2>&1 | FileCheck %s --check-prefix=CALL +// CALL: "-cc1"{{.*}} "-fptrauth-calls" + +// RUN: %clang -### -c --target=aarch64 -fno-ptrauth-returns -fptrauth-returns %s 2>&1 | FileCheck %s --check-prefix=RETURN +// RETURN: "-cc1"{{.*}} "-fptrauth-returns" + +// RUN: %clang -### -c --target=aarch64 -fno-ptrauth-auth-traps -fptrauth-auth-traps %s 2>&1 | FileCheck %s --check-prefix=TRAP +// TRAP: "-cc1"{{.*}} "-fptrauth-auth-traps" + +// RUN: %clang -### -c --target=aarch64 -fno-ptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-vtable-pointer-address-discrimination %s 2>&1 | FileCheck %s --check-prefix=VPTRADDR +// VPTRADDR: "-cc1"{{.*}} "-fptrauth-vtable-pointer-address-discrimination" + +// RUN: %clang -### -c --target=aarch64 -fno-ptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination %s 2>&1 | FileCheck %s --check-prefix=VPTRTYPE +// VPTRTYPE: "-cc1"{{.*}} "-fptrauth-vtable-pointer-type-discrimination" + +// RUN: %clang -### -c --target=aarch64 -fno-ptrauth-init-fini -fptrauth-init-fini %s 2>&1 | FileCheck %s --check-prefix=INITFINI +// INITFINI: "-cc1"{{.*}} "-fptrauth-init-fini" + +// 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 '{{.*}}' diff --git a/clang/test/Preprocessor/ptrauth_feature.c b/clang/test/Preprocessor/ptrauth_feature.c index e45c6ea90fd1..80e239110ffc 100644 --- a/clang/test/Preprocessor/ptrauth_feature.c +++ b/clang/test/Preprocessor/ptrauth_feature.c @@ -1,5 +1,59 @@ -// RUN: %clang_cc1 %s -E -triple=arm64-- | FileCheck %s --check-prefixes=NOINTRIN -// RUN: %clang_cc1 %s -E -triple=arm64-- -fptrauth-intrinsics | FileCheck %s --check-prefixes=INTRIN +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-init-fini | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI + +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-init-fini | \ +// RUN: FileCheck %s --check-prefixes=NOINTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI + +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-init-fini | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,NOCALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI + +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-init-fini | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,NORETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI + +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-init-fini | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,NOVPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI + +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-init-fini | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,INITFINI + +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,NOINITFINI #if __has_feature(ptrauth_intrinsics) // INTRIN: has_ptrauth_intrinsics @@ -8,3 +62,52 @@ void has_ptrauth_intrinsics() {} // NOINTRIN: no_ptrauth_intrinsics void no_ptrauth_intrinsics() {} #endif + +#if __has_feature(ptrauth_calls) +// CALLS: has_ptrauth_calls +void has_ptrauth_calls() {} +#else +// NOCALLS: no_ptrauth_calls +void no_ptrauth_calls() {} +#endif + +// This is always enabled when ptrauth_calls is enabled +#if __has_feature(ptrauth_member_function_pointer_type_discrimination) +// CALLS: has_ptrauth_member_function_pointer_type_discrimination +void has_ptrauth_member_function_pointer_type_discrimination() {} +#else +// NOCALLS: no_ptrauth_member_function_pointer_type_discrimination +void no_ptrauth_member_function_pointer_type_discrimination() {} +#endif + +#if __has_feature(ptrauth_returns) +// RETS: has_ptrauth_returns +void has_ptrauth_returns() {} +#else +// NORETS: no_ptrauth_returns +void no_ptrauth_returns() {} +#endif + +#if __has_feature(ptrauth_vtable_pointer_address_discrimination) +// VPTR_ADDR_DISCR: has_ptrauth_vtable_pointer_address_discrimination +void has_ptrauth_vtable_pointer_address_discrimination() {} +#else +// NOVPTR_ADDR_DISCR: no_ptrauth_vtable_pointer_address_discrimination +void no_ptrauth_vtable_pointer_address_discrimination() {} +#endif + +#if __has_feature(ptrauth_vtable_pointer_type_discrimination) +// VPTR_TYPE_DISCR: has_ptrauth_vtable_pointer_type_discrimination +void has_ptrauth_vtable_pointer_type_discrimination() {} +#else +// NOVPTR_TYPE_DISCR: no_ptrauth_vtable_pointer_type_discrimination +void no_ptrauth_vtable_pointer_type_discrimination() {} +#endif + +#if __has_feature(ptrauth_init_fini) +// INITFINI: has_ptrauth_init_fini +void has_ptrauth_init_fini() {} +#else +// NOINITFINI: no_ptrauth_init_fini +void no_ptrauth_init_fini() {} +#endif From 752f98f88ef227f3f97b2428b0c56ab41a82210b Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Mon, 22 Apr 2024 02:00:46 +0300 Subject: [PATCH 2/9] [MC] PR89563 --- .../MCTargetDesc/AArch64ELFObjectWriter.cpp | 16 ++++++++-------- llvm/test/MC/AArch64/ilp32-diagnostics.s | 8 ++++++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp index 6e074b6a63c4..abbf20257edc 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp @@ -211,18 +211,18 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx, Target.getAccessVariant() == MCSymbolRefExpr::VK_GOTPCREL) ? ELF::R_AARCH64_GOTPCREL32 : R_CLS(ABS32); - case FK_Data_8: + case FK_Data_8: { + bool IsAuth = (RefKind == AArch64MCExpr::VK_AUTH || + RefKind == AArch64MCExpr::VK_AUTHADDR); if (IsILP32) { Ctx.reportError(Fixup.getLoc(), - "ILP32 8 byte absolute data " - "relocation not supported (LP64 eqv: ABS64)"); + Twine("ILP32 8 byte absolute data " + "relocation not supported (LP64 eqv: ") + + (IsAuth ? "AUTH_ABS64" : "ABS64") + Twine(')')); return ELF::R_AARCH64_NONE; - } else { - if (RefKind == AArch64MCExpr::VK_AUTH || - RefKind == AArch64MCExpr::VK_AUTHADDR) - return ELF::R_AARCH64_AUTH_ABS64; - return ELF::R_AARCH64_ABS64; } + return (IsAuth ? ELF::R_AARCH64_AUTH_ABS64 : ELF::R_AARCH64_ABS64); + } case AArch64::fixup_aarch64_add_imm12: if (RefKind == AArch64MCExpr::VK_DTPREL_HI12) return R_CLS(TLSLD_ADD_DTPREL_HI12); diff --git a/llvm/test/MC/AArch64/ilp32-diagnostics.s b/llvm/test/MC/AArch64/ilp32-diagnostics.s index 65c9e4ea5a1c..4ca15f160418 100644 --- a/llvm/test/MC/AArch64/ilp32-diagnostics.s +++ b/llvm/test/MC/AArch64/ilp32-diagnostics.s @@ -8,6 +8,14 @@ .xword sym+16 // CHECK-ERROR: error: ILP32 8 byte absolute data relocation not supported (LP64 eqv: ABS64) +// CHECK-ERROR: ^ + + .xword sym@AUTH(da,42) +// CHECK-ERROR: error: ILP32 8 byte absolute data relocation not supported (LP64 eqv: AUTH_ABS64) +// CHECK-ERROR: ^ + + .xword sym@AUTH(da,42,addr) +// CHECK-ERROR: error: ILP32 8 byte absolute data relocation not supported (LP64 eqv: AUTH_ABS64) // CHECK-ERROR: ^ movz x7, #:abs_g3:some_label From 61669e1a9072ba1e59a4e53c8827697a3accf040 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Mon, 15 Apr 2024 04:44:54 +0300 Subject: [PATCH 3/9] [PAC][llvm-readobj][ELF][AArch64] Define AUTH relocations for signed GOT AUTH variant GOT-generating relocations https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#auth-variant-got-generating-relocations AUTH variant dynamic relocations for signed GOT https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#additional-auth-variant-dynamic-relocations-for-signed-got --- .../llvm/BinaryFormat/ELFRelocs/AArch64.def | 17 ++++++++++ .../llvm-readobj/ELF/reloc-types-aarch64.test | 34 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/AArch64.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/AArch64.def index cb05db85e2b5..ece8577fe219 100644 --- a/llvm/include/llvm/BinaryFormat/ELFRelocs/AArch64.def +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/AArch64.def @@ -144,6 +144,23 @@ ELF_RELOC(R_AARCH64_IRELATIVE, 0x408) // https://github.com/ARM-software/abi-aa ELF_RELOC(R_AARCH64_AUTH_ABS64, 0x244) ELF_RELOC(R_AARCH64_AUTH_RELATIVE, 0x411) +ELF_RELOC(R_AARCH64_AUTH_MOVW_GOTOFF_G0, 0x8110) +ELF_RELOC(R_AARCH64_AUTH_MOVW_GOTOFF_G0_NC, 0x8111) +ELF_RELOC(R_AARCH64_AUTH_MOVW_GOTOFF_G1, 0x8112) +ELF_RELOC(R_AARCH64_AUTH_MOVW_GOTOFF_G1_NC, 0x8113) +ELF_RELOC(R_AARCH64_AUTH_MOVW_GOTOFF_G2, 0x8114) +ELF_RELOC(R_AARCH64_AUTH_MOVW_GOTOFF_G2_NC, 0x8115) +ELF_RELOC(R_AARCH64_AUTH_MOVW_GOTOFF_G3, 0x8116) +ELF_RELOC(R_AARCH64_AUTH_GOT_LD_PREL19, 0x8117) +ELF_RELOC(R_AARCH64_AUTH_LD64_GOTOFF_LO15, 0x8118) +ELF_RELOC(R_AARCH64_AUTH_ADR_GOT_PAGE, 0x8119) +ELF_RELOC(R_AARCH64_AUTH_GOT_LO12_NC, 0x811a) +ELF_RELOC(R_AARCH64_AUTH_LD64_GOTPAGE_LO15, 0x811b) +ELF_RELOC(R_AARCH64_AUTH_GOT_ADD_LO12_NC, 0x811c) +ELF_RELOC(R_AARCH64_AUTH_GOT_ADR_PREL21, 0x811d) +ELF_RELOC(R_AARCH64_AUTH_GLOB_DAT, 0xe201) +ELF_RELOC(R_AARCH64_AUTH_TLSDESC, 0xe202) +ELF_RELOC(R_AARCH64_AUTH_IRELATIVE, 0xe203) // ELF32 // ELF_RELOC(R_AARCH64_P32_NONE, 0) diff --git a/llvm/test/tools/llvm-readobj/ELF/reloc-types-aarch64.test b/llvm/test/tools/llvm-readobj/ELF/reloc-types-aarch64.test index cf95b5170026..8111bfe71c10 100644 --- a/llvm/test/tools/llvm-readobj/ELF/reloc-types-aarch64.test +++ b/llvm/test/tools/llvm-readobj/ELF/reloc-types-aarch64.test @@ -130,6 +130,23 @@ # CHECK: Type: R_AARCH64_TLSDESC (1031) # CHECK: Type: R_AARCH64_IRELATIVE (1032) # CHECK: Type: R_AARCH64_AUTH_RELATIVE (1041) +# CHECK: Type: R_AARCH64_AUTH_MOVW_GOTOFF_G0 (33040) +# CHECK: Type: R_AARCH64_AUTH_MOVW_GOTOFF_G0_NC (33041) +# CHECK: Type: R_AARCH64_AUTH_MOVW_GOTOFF_G1 (33042) +# CHECK: Type: R_AARCH64_AUTH_MOVW_GOTOFF_G1_NC (33043) +# CHECK: Type: R_AARCH64_AUTH_MOVW_GOTOFF_G2 (33044) +# CHECK: Type: R_AARCH64_AUTH_MOVW_GOTOFF_G2_NC (33045) +# CHECK: Type: R_AARCH64_AUTH_MOVW_GOTOFF_G3 (33046) +# CHECK: Type: R_AARCH64_AUTH_GOT_LD_PREL19 (33047) +# CHECK: Type: R_AARCH64_AUTH_LD64_GOTOFF_LO15 (33048) +# CHECK: Type: R_AARCH64_AUTH_ADR_GOT_PAGE (33049) +# CHECK: Type: R_AARCH64_AUTH_GOT_LO12_NC (33050) +# CHECK: Type: R_AARCH64_AUTH_LD64_GOTPAGE_LO15 (33051) +# CHECK: Type: R_AARCH64_AUTH_GOT_ADD_LO12_NC (33052) +# CHECK: Type: R_AARCH64_AUTH_GOT_ADR_PREL21 (33053) +# CHECK: Type: R_AARCH64_AUTH_GLOB_DAT (57857) +# CHECK: Type: R_AARCH64_AUTH_TLSDESC (57858) +# CHECK: Type: R_AARCH64_AUTH_IRELATIVE (57859) --- !ELF FileHeader: @@ -267,3 +284,20 @@ Sections: - Type: R_AARCH64_TLSDESC - Type: R_AARCH64_IRELATIVE - Type: R_AARCH64_AUTH_RELATIVE + - Type: R_AARCH64_AUTH_MOVW_GOTOFF_G0 + - Type: R_AARCH64_AUTH_MOVW_GOTOFF_G0_NC + - Type: R_AARCH64_AUTH_MOVW_GOTOFF_G1 + - Type: R_AARCH64_AUTH_MOVW_GOTOFF_G1_NC + - Type: R_AARCH64_AUTH_MOVW_GOTOFF_G2 + - Type: R_AARCH64_AUTH_MOVW_GOTOFF_G2_NC + - Type: R_AARCH64_AUTH_MOVW_GOTOFF_G3 + - Type: R_AARCH64_AUTH_GOT_LD_PREL19 + - Type: R_AARCH64_AUTH_LD64_GOTOFF_LO15 + - Type: R_AARCH64_AUTH_ADR_GOT_PAGE + - Type: R_AARCH64_AUTH_GOT_LO12_NC + - Type: R_AARCH64_AUTH_LD64_GOTPAGE_LO15 + - Type: R_AARCH64_AUTH_GOT_ADD_LO12_NC + - Type: R_AARCH64_AUTH_GOT_ADR_PREL21 + - Type: R_AARCH64_AUTH_GLOB_DAT + - Type: R_AARCH64_AUTH_TLSDESC + - Type: R_AARCH64_AUTH_IRELATIVE From 78719d2fd47c63a47ef644db4e4cba44732dcc73 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Mon, 15 Apr 2024 04:47:17 +0300 Subject: [PATCH 4/9] [PAC][ELF][AArch64] Encode signed GOT flag in PAuth core info Treat 7th bit of version value for llvm_linux platform as signed GOT flag. - llvm-readobj: print `PointerAuthELFGOT` or `!PointerAuthELFGOT` in version description of llvm_linux platform depending on whether the flag is set. - clang: define `PointerAuthELFGOT` LangOption and set 7th bit of `aarch64-elf-pauthabi-version` LLVM module flag correspondingly; --- clang/include/clang/Basic/LangOptions.def | 1 + clang/lib/CodeGen/CodeGenModule.cpp | 6 ++++-- llvm/include/llvm/BinaryFormat/ELF.h | 3 ++- .../AArch64/note-gnu-property-elf-pauthabi.ll | 2 +- .../ELF/AArch64/aarch64-feature-pauth.s | 18 +++++++++--------- llvm/tools/llvm-readobj/ELFDumper.cpp | 3 ++- 6 files changed, 19 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 4b99e7029846..e2016aab850e 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -168,6 +168,7 @@ LANGOPT(PointerAuthAuthTraps, 1, 0, "pointer authentication failure traps") LANGOPT(PointerAuthVTPtrAddressDiscrimination, 1, 0, "incorporate address discrimination in authenticated vtable pointers") LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, "incorporate type discrimination in authenticated vtable pointers") LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays") +LANGOPT(PointerAuthELFGOT, 1, 0, "authenticate pointers from GOT") LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes") diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 540b6d036291..ee88bd04104b 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1207,8 +1207,10 @@ void CodeGenModule::Release() { (LangOpts.PointerAuthVTPtrTypeDiscrimination << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRTYPEDISCR) | (LangOpts.PointerAuthInitFini - << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI); - static_assert(AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI == + << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI) | + (LangOpts.PointerAuthELFGOT + << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_GOT); + static_assert(AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_GOT == AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST, "Update when new enum items are defined"); if (PAuthABIVersion != 0) { diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index 56b5d4e399c6..8eb7a93c24ea 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -1770,8 +1770,9 @@ enum : unsigned { AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRADDRDISCR = 4, AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRTYPEDISCR = 5, AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI = 6, + AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_GOT = 7, AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST = - AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI, + AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_GOT, }; // x86 processor feature bits. diff --git a/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll b/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll index 728cffeba02a..fb69a12b2f90 100644 --- a/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll +++ b/llvm/test/CodeGen/AArch64/note-gnu-property-elf-pauthabi.ll @@ -27,7 +27,7 @@ ; OBJ: Displaying notes found in: .note.gnu.property ; OBJ-NEXT: Owner Data size Description ; OBJ-NEXT: GNU 0x00000018 NT_GNU_PROPERTY_TYPE_0 (property note) -; OBJ-NEXT: AArch64 PAuth ABI core info: platform 0x10000002 (llvm_linux), version 0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini) +; OBJ-NEXT: AArch64 PAuth ABI core info: platform 0x10000002 (llvm_linux), version 0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini, !PointerAuthELFGOT) ; ERR: either both or no 'aarch64-elf-pauthabi-platform' and 'aarch64-elf-pauthabi-version' module flags must be present diff --git a/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s b/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s index 512531748cd2..65e9b818729e 100644 --- a/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s +++ b/llvm/test/tools/llvm-readobj/ELF/AArch64/aarch64-feature-pauth.s @@ -106,12 +106,12 @@ end: # RUN: llvm-mc -filetype=obj -triple aarch64-linux-gnu gnu-0x10000002-85.s -o gnu-0x10000002-85.o # RUN: llvm-readelf --notes gnu-0x10000002-85.o | \ # RUN: FileCheck --check-prefix=ELF -DPLATFORM="0x10000002 (llvm_linux)" \ -# RUN: -DVERSION="0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini)" %s +# RUN: -DVERSION="0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini, !PointerAuthELFGOT)" %s # RUN: llvm-readobj --notes gnu-0x10000002-85.o | \ # RUN: FileCheck --check-prefix=OBJ -DPLATFORM="0x10000002 (llvm_linux)" \ -# RUN: -DVERSION="0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini)" %s +# RUN: -DVERSION="0x55 (PointerAuthIntrinsics, !PointerAuthCalls, PointerAuthReturns, !PointerAuthAuthTraps, PointerAuthVTPtrAddressDiscrimination, !PointerAuthVTPtrTypeDiscrimination, PointerAuthInitFini, !PointerAuthELFGOT)" %s -#--- gnu-0x10000002-128.s +#--- gnu-0x10000002-256.s .section ".note.gnu.property", "a" .long 4 // Name length is always 4 ("GNU") .long end - begin // Data length @@ -123,15 +123,15 @@ begin: .long 0xc0000001 // Type: GNU_PROPERTY_AARCH64_FEATURE_PAUTH .long 16 // Data size .quad 0x10000002 // PAuth ABI platform - .quad 128 // PAuth ABI version + .quad 256 // PAuth ABI version .p2align 3 // Align to 8 byte for 64 bit end: -# RUN: llvm-mc -filetype=obj -triple aarch64-linux-gnu gnu-0x10000002-128.s -o gnu-0x10000002-128.o -# RUN: llvm-readelf --notes gnu-0x10000002-128.o | \ -# RUN: FileCheck --check-prefix=ELF -DPLATFORM="0x10000002 (llvm_linux)" -DVERSION="0x80 (unknown)" %s -# RUN: llvm-readobj --notes gnu-0x10000002-128.o | \ -# RUN: FileCheck --check-prefix=OBJ -DPLATFORM="0x10000002 (llvm_linux)" -DVERSION="0x80 (unknown)" %s +# RUN: llvm-mc -filetype=obj -triple aarch64-linux-gnu gnu-0x10000002-256.s -o gnu-0x10000002-256.o +# RUN: llvm-readelf --notes gnu-0x10000002-256.o | \ +# RUN: FileCheck --check-prefix=ELF -DPLATFORM="0x10000002 (llvm_linux)" -DVERSION="0x100 (unknown)" %s +# RUN: llvm-readobj --notes gnu-0x10000002-256.o | \ +# RUN: FileCheck --check-prefix=OBJ -DPLATFORM="0x10000002 (llvm_linux)" -DVERSION="0x100 (unknown)" %s #--- gnu-short.s .section ".note.gnu.property", "a" diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index f145653ac743..38cfa1fc0a5f 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -5236,8 +5236,9 @@ static bool printAArch64PAuthABICoreInfo(raw_ostream &OS, uint32_t DataSize, Flags[AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRTYPEDISCR] = "VTPtrTypeDiscrimination"; Flags[AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI] = "InitFini"; + Flags[AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_GOT] = "ELFGOT"; - static_assert(AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI == + static_assert(AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_GOT == AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST, "Update when new enum items are defined"); From d7c34e8f0611133fd478dd1227bdd271720cc1bb Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Mon, 22 Apr 2024 03:58:40 +0300 Subject: [PATCH 5/9] [PAC][clang][Driver] Add signed GOT flag Add `-fptrauth-elf-got` clang driver flag and set `ptrauth_elf_got` preprocessor feature and `PointerAuthELFGOT` LangOption correspondingly. For non-ELF triples, the driver flag is ignored and a warning is emitted. --- .../clang/Basic/DiagnosticDriverKinds.td | 4 ++ clang/include/clang/Basic/Features.def | 1 + clang/include/clang/Driver/Options.td | 1 + clang/lib/Driver/ToolChains/Clang.cpp | 7 +++ clang/lib/Frontend/CompilerInvocation.cpp | 4 ++ clang/test/CodeGen/aarch64-elf-pauthabi.c | 11 +++- clang/test/Driver/aarch64-ptrauth.c | 9 +++- clang/test/Preprocessor/ptrauth_feature.c | 52 ++++++++++++++----- 8 files changed, 72 insertions(+), 17 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index ed3fd9b1c4a5..0b440f9860ae 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -748,6 +748,10 @@ def warn_drv_fjmc_for_elf_only : Warning< "-fjmc works only for ELF; option ignored">, InGroup; +def warn_drv_ptrauth_elf_got_for_elf_only : Warning< + "-fptrauth-elf-got works only for ELF; option ignored">, + InGroup; + def warn_target_override_arm64ec : Warning< "/arm64EC has been overridden by specified target: %0; option ignored">, InGroup; diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index b762e44e755e..2f2f1af8dc28 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -109,6 +109,7 @@ FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtr FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination) FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls) FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini) +FEATURE(ptrauth_elf_got, LangOpts.PointerAuthELFGOT) EXTENSION(swiftcc, PP.getTargetInfo().checkCallingConvention(CC_Swift) == clang::TargetInfo::CCCR_OK) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 13e60e8766c2..e62e2d0bfd4a 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4156,6 +4156,7 @@ defm ptrauth_vtable_pointer_address_discrimination : defm ptrauth_vtable_pointer_type_discrimination : OptInCC1FFlag<"ptrauth-vtable-pointer-type-discrimination", "Enable type discrimination of vtable pointers">; defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of function pointers in init/fini arrays">; +defm ptrauth_elf_got : OptInCC1FFlag<"ptrauth-elf-got", "Enable authentication of pointers from GOT (ELF only)">; } def fenable_matrix : Flag<["-"], "fenable-matrix">, Group, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 88984e9f156e..b6ad28b7736c 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1802,6 +1802,13 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_init_fini, options::OPT_fno_ptrauth_init_fini); + + Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_elf_got, + options::OPT_fno_ptrauth_elf_got); + + if (Args.hasArg(options::OPT_fptrauth_elf_got)) + getToolChain().getDriver().Diag( + diag::warn_drv_ptrauth_elf_got_for_elf_only); } void Clang::AddLoongArchTargetArgs(const ArgList &Args, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 40731af0c9fb..2539e7a35bf9 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3331,6 +3331,8 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts, GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_type_discrimination); if (Opts.PointerAuthInitFini) GenerateArg(Consumer, OPT_fptrauth_init_fini); + if (Opts.PointerAuthELFGOT) + GenerateArg(Consumer, OPT_fptrauth_elf_got); } static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args, @@ -3344,6 +3346,7 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args, Opts.PointerAuthVTPtrTypeDiscrimination = Args.hasArg(OPT_fptrauth_vtable_pointer_type_discrimination); Opts.PointerAuthInitFini = Args.hasArg(OPT_fptrauth_init_fini); + Opts.PointerAuthELFGOT = Args.hasArg(OPT_fptrauth_elf_got); } /// Check if input file kind and language standard are compatible. @@ -4697,6 +4700,7 @@ bool CompilerInvocation::CreateFromArgsImpl( ParseAPINotesArgs(Res.getAPINotesOpts(), Args, Diags); ParsePointerAuthArgs(LangOpts, Args, Diags); + LangOpts.PointerAuthELFGOT &= T.isOSBinFormatELF(); ParseLangArgs(LangOpts, Args, DashX, T, Res.getPreprocessorOpts().Includes, Diags); diff --git a/clang/test/CodeGen/aarch64-elf-pauthabi.c b/clang/test/CodeGen/aarch64-elf-pauthabi.c index 35f0579c4c84..c1b7b9e7ee60 100644 --- a/clang/test/CodeGen/aarch64-elf-pauthabi.c +++ b/clang/test/CodeGen/aarch64-elf-pauthabi.c @@ -5,7 +5,8 @@ // RUN: -fptrauth-auth-traps \ // RUN: -fptrauth-vtable-pointer-address-discrimination \ // RUN: -fptrauth-vtable-pointer-type-discrimination \ -// RUN: -fptrauth-init-fini %s | \ +// RUN: -fptrauth-init-fini \ +// RUN: -fptrauth-elf-got %s | \ // RUN: FileCheck %s --check-prefix=ALL // RUN: %clang --target=aarch64-linux -S -emit-llvm -o - \ @@ -32,8 +33,11 @@ // RUN: -fptrauth-calls -fptrauth-init-fini %s | \ // RUN: FileCheck %s --check-prefix=INITFINI +// RUN: %clang --target=aarch64-linux -S -emit-llvm -o - \ +// RUN: -fptrauth-elf-got %s | FileCheck %s --check-prefix=ELFGOT + // ALL: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} -// ALL: !{i32 1, !"aarch64-elf-pauthabi-version", i32 127} +// ALL: !{i32 1, !"aarch64-elf-pauthabi-version", i32 255} // INTRIN: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} // INTRIN: !{i32 1, !"aarch64-elf-pauthabi-version", i32 1} @@ -56,4 +60,7 @@ // INITFINI: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} // INITFINI: !{i32 1, !"aarch64-elf-pauthabi-version", i32 66} +// ELFGOT: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// ELFGOT: !{i32 1, !"aarch64-elf-pauthabi-version", i32 128} + void foo() {} diff --git a/clang/test/Driver/aarch64-ptrauth.c b/clang/test/Driver/aarch64-ptrauth.c index 9ae0347a8ccb..027ed3a5d9ef 100644 --- a/clang/test/Driver/aarch64-ptrauth.c +++ b/clang/test/Driver/aarch64-ptrauth.c @@ -25,9 +25,15 @@ // RUN: %clang -### -c --target=aarch64 -fno-ptrauth-init-fini -fptrauth-init-fini %s 2>&1 | FileCheck %s --check-prefix=INITFINI // INITFINI: "-cc1"{{.*}} "-fptrauth-init-fini" +// RUN: %clang -### -c --target=aarch64-elf -fno-ptrauth-elf-got -fptrauth-elf-got %s 2>&1 | FileCheck %s --check-prefix=ELFGOT +// ELFGOT: "-cc1"{{.*}} "-fptrauth-elf-got" + +// RUN: %clang -### -c --target=aarch64-darwin -fptrauth-elf-got %s 2>&1 | FileCheck %s --check-prefix=NOELFGOT +// NOELFGOT: warning: -fptrauth-elf-got works only for ELF; option ignored [-Woption-ignored] + // 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 +// RUN: -fptrauth-init-fini -fptrauth-elf-got %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 '{{.*}}' @@ -35,3 +41,4 @@ // 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 '{{.*}}' +// ERR-NEXT: error: unsupported option '-fptrauth-elf-got' for target '{{.*}}' diff --git a/clang/test/Preprocessor/ptrauth_feature.c b/clang/test/Preprocessor/ptrauth_feature.c index 80e239110ffc..ba256384199f 100644 --- a/clang/test/Preprocessor/ptrauth_feature.c +++ b/clang/test/Preprocessor/ptrauth_feature.c @@ -4,56 +4,72 @@ // RUN: -fptrauth-returns \ // RUN: -fptrauth-vtable-pointer-address-discrimination \ // RUN: -fptrauth-vtable-pointer-type-discrimination \ -// RUN: -fptrauth-init-fini | \ -// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI +// RUN: -fptrauth-init-fini \ +// RUN: -fptrauth-elf-got | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI,ELFGOT // RUN: %clang_cc1 -E %s -triple=aarch64 \ // RUN: -fptrauth-calls \ // RUN: -fptrauth-returns \ // RUN: -fptrauth-vtable-pointer-address-discrimination \ // RUN: -fptrauth-vtable-pointer-type-discrimination \ -// RUN: -fptrauth-init-fini | \ -// RUN: FileCheck %s --check-prefixes=NOINTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI +// RUN: -fptrauth-init-fini \ +// RUN: -fptrauth-elf-got | \ +// RUN: FileCheck %s --check-prefixes=NOINTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI,ELFGOT // RUN: %clang_cc1 -E %s -triple=aarch64 \ // RUN: -fptrauth-intrinsics \ // RUN: -fptrauth-returns \ // RUN: -fptrauth-vtable-pointer-address-discrimination \ // RUN: -fptrauth-vtable-pointer-type-discrimination \ -// RUN: -fptrauth-init-fini | \ -// RUN: FileCheck %s --check-prefixes=INTRIN,NOCALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI +// RUN: -fptrauth-init-fini \ +// RUN: -fptrauth-elf-got | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,NOCALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI,ELFGOT // RUN: %clang_cc1 -E %s -triple=aarch64 \ // RUN: -fptrauth-intrinsics \ // RUN: -fptrauth-calls \ // RUN: -fptrauth-vtable-pointer-address-discrimination \ // RUN: -fptrauth-vtable-pointer-type-discrimination \ -// RUN: -fptrauth-init-fini | \ -// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,NORETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI +// RUN: -fptrauth-init-fini \ +// RUN: -fptrauth-elf-got | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,NORETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI,ELFGOT // RUN: %clang_cc1 -E %s -triple=aarch64 \ // RUN: -fptrauth-intrinsics \ // RUN: -fptrauth-calls \ // RUN: -fptrauth-returns \ // RUN: -fptrauth-vtable-pointer-type-discrimination \ -// RUN: -fptrauth-init-fini | \ -// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,NOVPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI +// RUN: -fptrauth-init-fini \ +// RUN: -fptrauth-elf-got | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,NOVPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI,ELFGOT // RUN: %clang_cc1 -E %s -triple=aarch64 \ // RUN: -fptrauth-intrinsics \ // RUN: -fptrauth-calls \ // RUN: -fptrauth-returns \ // RUN: -fptrauth-vtable-pointer-address-discrimination \ -// RUN: -fptrauth-init-fini | \ -// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,INITFINI +// RUN: -fptrauth-init-fini \ +// RUN: -fptrauth-elf-got | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,INITFINI,ELFGOT + +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-elf-got | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,NOINITFINI,ELFGOT // RUN: %clang_cc1 -E %s -triple=aarch64 \ // RUN: -fptrauth-intrinsics \ // RUN: -fptrauth-calls \ // RUN: -fptrauth-returns \ // RUN: -fptrauth-vtable-pointer-address-discrimination \ -// RUN: -fptrauth-vtable-pointer-type-discrimination | \ -// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,NOINITFINI +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-init-fini | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI,NOELFGOT #if __has_feature(ptrauth_intrinsics) // INTRIN: has_ptrauth_intrinsics @@ -111,3 +127,11 @@ void has_ptrauth_init_fini() {} // NOINITFINI: no_ptrauth_init_fini void no_ptrauth_init_fini() {} #endif + +#if __has_feature(ptrauth_elf_got) +// ELFGOT: has_ptrauth_elf_got +void has_ptrauth_elf_got() {} +#else +// NOELFGOT: no_ptrauth_elf_got +void no_ptrauth_elf_got() {} +#endif From e4c67fa923e15e40c1d9eb00a1e407f45afdd4b5 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Thu, 18 Apr 2024 22:20:13 +0300 Subject: [PATCH 6/9] [PAC][CodeGen][ELF][AArch64] Support signed GOT Support the following relocations and assembly operators: - `R_AARCH64_AUTH_ADR_GOT_PAGE` (`:got_auth:` for `adrp`) - `R_AARCH64_AUTH_GOT_LO12_NC` (`:got_auth_lo12:` for `ldr`) - `R_AARCH64_AUTH_GOT_ADD_LO12_NC` (`:got_auth_lo12:` for `add`) `LOADgotAUTH` pseudo-instruction is introduced which is later expanded to actual instruction sequence like the following. ``` adrp x16, :got_auth:sym add x16, x16, :got_auth_lo12:sym ldr x0, [x16] autia x0, x16 ``` Both SelectionDAG and GlobalISel are suppported. For FastISel, we fall back to SelectionDAG. Tests with 'auth' in name have corresponding variants w/o it. --- llvm/include/llvm/IR/Module.h | 6 ++ llvm/lib/IR/Module.cpp | 19 ++++++ .../AArch64/AArch64ExpandPseudoInsts.cpp | 33 ++++++++++ llvm/lib/Target/AArch64/AArch64FastISel.cpp | 3 + .../Target/AArch64/AArch64ISelLowering.cpp | 3 + llvm/lib/Target/AArch64/AArch64InstrInfo.td | 4 ++ .../lib/Target/AArch64/AArch64MCInstLower.cpp | 13 +++- .../AArch64/AsmParser/AArch64AsmParser.cpp | 32 +++++---- .../GISel/AArch64InstructionSelector.cpp | 4 +- .../MCTargetDesc/AArch64ELFObjectWriter.cpp | 37 +++++++++-- .../AArch64/MCTargetDesc/AArch64MCExpr.cpp | 5 ++ .../AArch64/MCTargetDesc/AArch64MCExpr.h | 5 ++ llvm/test/CodeGen/AArch64/basic-pic-auth.ll | 39 +++++++++++ .../CodeGen/AArch64/elf-globals-pic-auth.ll | 23 +++++++ llvm/test/CodeGen/AArch64/extern-weak-auth.ll | 36 ++++++++++ llvm/test/CodeGen/AArch64/got-abuse-auth.ll | 44 +++++++++++++ .../AArch64/tagged-globals-pic-auth.ll | 66 +++++++++++++++++++ llvm/test/MC/AArch64/adrp-auth-relocation.s | 12 ++++ llvm/test/MC/AArch64/arm64-elf-relocs.s | 20 +++++- llvm/test/MC/AArch64/ilp32-diagnostics.s | 8 +++ 20 files changed, 385 insertions(+), 27 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/basic-pic-auth.ll create mode 100644 llvm/test/CodeGen/AArch64/elf-globals-pic-auth.ll create mode 100644 llvm/test/CodeGen/AArch64/extern-weak-auth.ll create mode 100644 llvm/test/CodeGen/AArch64/got-abuse-auth.ll create mode 100644 llvm/test/CodeGen/AArch64/tagged-globals-pic-auth.ll create mode 100644 llvm/test/MC/AArch64/adrp-auth-relocation.s diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h index 6135e15fd030..694149cc85cf 100644 --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -1062,6 +1062,12 @@ class LLVM_EXTERNAL_VISIBILITY Module { /// Set the target variant version build SDK version metadata. void setDarwinTargetVariantSDKVersion(VersionTuple Version); + + /// Check if the module is compiled with signed GOT. + /// @returns true if and only if aarch64-elf-pauthabi-platform module flag + /// equals AARCH64_PAUTH_PLATFORM_LLVM_LINUX and aarch64-elf-pauthabi-version + /// module flag has AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_GOT bit set. + bool hasELFSignedGOT() const; }; /// Given "llvm.used" or "llvm.compiler.used" as a global name, collect the diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp index a8696ed9e3ce..33f173188680 100644 --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/Comdat.h" #include "llvm/IR/Constants.h" @@ -44,6 +45,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/VersionTuple.h" +#include "llvm/TargetParser/Triple.h" #include #include #include @@ -893,3 +895,20 @@ VersionTuple Module::getDarwinTargetVariantSDKVersion() const { void Module::setDarwinTargetVariantSDKVersion(VersionTuple Version) { addSDKVersionMD(Version, *this, "darwin.target_variant.SDK Version"); } + +bool Module::hasELFSignedGOT() const { + if (!Triple(TargetTriple).isOSBinFormatELF()) + return false; + uint64_t PAuthABIPlatform = -1; + if (const auto *PAP = mdconst::extract_or_null( + getModuleFlag("aarch64-elf-pauthabi-platform"))) + PAuthABIPlatform = PAP->getZExtValue(); + if (PAuthABIPlatform != ELF::AARCH64_PAUTH_PLATFORM_LLVM_LINUX) + return false; + uint64_t PAuthABIVersion = -1; + if (const auto *PAV = mdconst::extract_or_null( + getModuleFlag("aarch64-elf-pauthabi-version"))) + PAuthABIVersion = PAV->getZExtValue(); + return (PAuthABIVersion & + (1 << ELF::AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_GOT)) != 0; +} diff --git a/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp b/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp index 03f0778bae59..6d27e982533c 100644 --- a/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp +++ b/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp @@ -1246,7 +1246,40 @@ bool AArch64ExpandPseudo::expandMI(MachineBasicBlock &MBB, MI.eraseFromParent(); return true; } + case AArch64::LOADgotAUTH: { + Register DstReg = MI.getOperand(0).getReg(); + const MachineOperand &MO1 = MI.getOperand(1); + + MachineOperand GAHiOp(MO1); + MachineOperand GALoOp(MO1); + GAHiOp.addTargetFlag(AArch64II::MO_PAGE); + GALoOp.addTargetFlag(AArch64II::MO_PAGEOFF | AArch64II::MO_NC); + + DebugLoc DL = MI.getDebugLoc(); + BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADRP), AArch64::X16) + .add(GAHiOp); + BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADDXri), AArch64::X16) + .addReg(AArch64::X16) + .add(GALoOp) + .addImm(0); + + BuildMI(MBB, MBBI, DL, TII->get(AArch64::LDRXui), DstReg) + .addReg(AArch64::X16) + .addImm(0); + + assert(MO1.isGlobal()); + assert(MO1.getGlobal()->getValueType() != nullptr); + unsigned AuthOpcode = MO1.getGlobal()->getValueType()->isFunctionTy() + ? AArch64::AUTIA + : AArch64::AUTDA; + BuildMI(MBB, MBBI, DL, TII->get(AuthOpcode), DstReg) + .addReg(DstReg) + .addReg(AArch64::X16); + + MI.eraseFromParent(); + return true; + } case AArch64::LOADgot: { MachineFunction *MF = MBB.getParent(); Register DstReg = MI.getOperand(0).getReg(); diff --git a/llvm/lib/Target/AArch64/AArch64FastISel.cpp b/llvm/lib/Target/AArch64/AArch64FastISel.cpp index 62cf6a2c47ac..b1f846a84c96 100644 --- a/llvm/lib/Target/AArch64/AArch64FastISel.cpp +++ b/llvm/lib/Target/AArch64/AArch64FastISel.cpp @@ -452,6 +452,9 @@ unsigned AArch64FastISel::materializeGV(const GlobalValue *GV) { if (!Subtarget->useSmallAddressing() && !Subtarget->isTargetMachO()) return 0; + if (GV->getParent()->hasELFSignedGOT()) + return 0; + unsigned OpFlags = Subtarget->ClassifyGlobalReference(GV, TM); EVT DestEVT = TLI.getValueType(DL, GV->getType(), true); diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 3d1453e3beb9..04e5e84e1f19 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -8709,6 +8709,9 @@ SDValue AArch64TargetLowering::getGOT(NodeTy *N, SelectionDAG &DAG, SDValue GotAddr = getTargetNode(N, Ty, DAG, AArch64II::MO_GOT | Flags); // FIXME: Once remat is capable of dealing with instructions with register // operands, expand this into two nodes instead of using a wrapper node. + if (DAG.getMachineFunction().getFunction().getParent()->hasELFSignedGOT()) + return SDValue(DAG.getMachineNode(AArch64::LOADgotAUTH, DL, Ty, GotAddr), + 0); return DAG.getNode(AArch64ISD::LOADgot, DL, Ty, GotAddr); } diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index be53be782077..25bf85ffbc14 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -1689,6 +1689,10 @@ let Predicates = [HasPAuth] in { defm LDRAA : AuthLoad<0, "ldraa", simm10Scaled>; defm LDRAB : AuthLoad<1, "ldrab", simm10Scaled>; + def LOADgotAUTH : Pseudo<(outs GPR64common:$dst), (ins i64imm:$addr), []>, + Sched<[WriteI, ReadI]> { + let Defs = [X16]; + } } // v9.5-A pointer authentication extensions diff --git a/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp b/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp index 37d621cd2f65..5870696c7219 100644 --- a/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp +++ b/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp @@ -184,9 +184,16 @@ MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO, MCSymbol *Sym) const { uint32_t RefFlags = 0; - if (MO.getTargetFlags() & AArch64II::MO_GOT) - RefFlags |= AArch64MCExpr::VK_GOT; - else if (MO.getTargetFlags() & AArch64II::MO_TLS) { + if (MO.getTargetFlags() & AArch64II::MO_GOT) { + // TODO: it's probably better to introduce MO_GOT_AUTH or smth and avoid + // running M->hasELFSignedGOT() every time, but existing flags already cover + // all 12 bits of SubReg_TargetFlags field in MachineOperand, and making the + // field wider breaks static assertions. + const Module *M = + MO.getParent()->getParent()->getParent()->getFunction().getParent(); + RefFlags |= (M->hasELFSignedGOT() ? AArch64MCExpr::VK_GOT_AUTH + : AArch64MCExpr::VK_GOT); + } else if (MO.getTargetFlags() & AArch64II::MO_TLS) { TLSModel::Model Model; if (MO.isGlobal()) { const GlobalValue *GV = MO.getGlobal(); diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index a3b966aa6155..4db8c081613d 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -873,6 +873,7 @@ class AArch64Operand : public MCParsedAsmOperand { if (DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF || ELFRefKind == AArch64MCExpr::VK_LO12 || ELFRefKind == AArch64MCExpr::VK_GOT_LO12 || + ELFRefKind == AArch64MCExpr::VK_GOT_AUTH_LO12 || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC || ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 || @@ -984,19 +985,20 @@ class AArch64Operand : public MCParsedAsmOperand { int64_t Addend; if (AArch64AsmParser::classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) { - return DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF - || DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF - || (DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGEOFF && Addend == 0) - || ELFRefKind == AArch64MCExpr::VK_LO12 - || ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 - || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 - || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC - || ELFRefKind == AArch64MCExpr::VK_TPREL_HI12 - || ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 - || ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC - || ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12 - || ELFRefKind == AArch64MCExpr::VK_SECREL_HI12 - || ELFRefKind == AArch64MCExpr::VK_SECREL_LO12; + return DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF || + DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF || + (DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGEOFF && Addend == 0) || + ELFRefKind == AArch64MCExpr::VK_LO12 || + ELFRefKind == AArch64MCExpr::VK_GOT_AUTH_LO12 || + ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 || + ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 || + ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC || + ELFRefKind == AArch64MCExpr::VK_TPREL_HI12 || + ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 || + ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC || + ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12 || + ELFRefKind == AArch64MCExpr::VK_SECREL_HI12 || + ELFRefKind == AArch64MCExpr::VK_SECREL_LO12; } // If it's a constant, it should be a real immediate in range. @@ -3248,6 +3250,7 @@ ParseStatus AArch64AsmParser::tryParseAdrpLabel(OperandVector &Operands) { DarwinRefKind != MCSymbolRefExpr::VK_TLVPPAGE && ELFRefKind != AArch64MCExpr::VK_ABS_PAGE_NC && ELFRefKind != AArch64MCExpr::VK_GOT_PAGE && + ELFRefKind != AArch64MCExpr::VK_GOT_AUTH_PAGE && ELFRefKind != AArch64MCExpr::VK_GOT_PAGE_LO15 && ELFRefKind != AArch64MCExpr::VK_GOTTPREL_PAGE && ELFRefKind != AArch64MCExpr::VK_TLSDESC_PAGE) { @@ -4333,6 +4336,8 @@ bool AArch64AsmParser::parseSymbolicImmVal(const MCExpr *&ImmVal) { .Case("got", AArch64MCExpr::VK_GOT_PAGE) .Case("gotpage_lo15", AArch64MCExpr::VK_GOT_PAGE_LO15) .Case("got_lo12", AArch64MCExpr::VK_GOT_LO12) + .Case("got_auth", AArch64MCExpr::VK_GOT_AUTH_PAGE) + .Case("got_auth_lo12", AArch64MCExpr::VK_GOT_AUTH_LO12) .Case("gottprel", AArch64MCExpr::VK_GOTTPREL_PAGE) .Case("gottprel_lo12", AArch64MCExpr::VK_GOTTPREL_LO12_NC) .Case("gottprel_g1", AArch64MCExpr::VK_GOTTPREL_G1) @@ -5682,6 +5687,7 @@ bool AArch64AsmParser::validateInstruction(MCInst &Inst, SMLoc &IDLoc, // Only allow these with ADDXri/ADDWri if ((ELFRefKind == AArch64MCExpr::VK_LO12 || + ELFRefKind == AArch64MCExpr::VK_GOT_AUTH_LO12 || ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC || diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp index 61f5bc2464ee..aacba7afbeb1 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -2819,7 +2819,9 @@ bool AArch64InstructionSelector::select(MachineInstr &I) { } if (OpFlags & AArch64II::MO_GOT) { - I.setDesc(TII.get(AArch64::LOADgot)); + I.setDesc(TII.get(MF.getFunction().getParent()->hasELFSignedGOT() + ? AArch64::LOADgotAUTH + : AArch64::LOADgot)); I.getOperand(1).setTargetFlags(OpFlags); } else if (TM.getCodeModel() == CodeModel::Large && !TM.isPositionIndependent()) { diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp index abbf20257edc..8df844e477a5 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp @@ -168,6 +168,15 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx, } if (SymLoc == AArch64MCExpr::VK_GOT && !IsNC) return R_CLS(ADR_GOT_PAGE); + if (SymLoc == AArch64MCExpr::VK_GOT_AUTH && !IsNC) { + if (IsILP32) { + Ctx.reportError(Fixup.getLoc(), + "ILP32 ADRP AUTH relocation not supported " + "(LP64 eqv: AUTH_ADR_GOT_PAGE)"); + return ELF::R_AARCH64_NONE; + } + return ELF::R_AARCH64_AUTH_ADR_GOT_PAGE; + } if (SymLoc == AArch64MCExpr::VK_GOTTPREL && !IsNC) return R_CLS(TLSIE_ADR_GOTTPREL_PAGE21); if (SymLoc == AArch64MCExpr::VK_TLSDESC && !IsNC) @@ -238,6 +247,15 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx, return R_CLS(TLSLE_ADD_TPREL_LO12); if (RefKind == AArch64MCExpr::VK_TLSDESC_LO12) return R_CLS(TLSDESC_ADD_LO12); + if (RefKind == AArch64MCExpr::VK_GOT_AUTH_LO12 && IsNC) { + if (IsILP32) { + Ctx.reportError(Fixup.getLoc(), + "ILP32 ADD AUTH relocation not supported " + "(LP64 eqv: AUTH_GOT_ADD_LO12_NC)"); + return ELF::R_AARCH64_NONE; + } + return ELF::R_AARCH64_AUTH_GOT_ADD_LO12_NC; + } if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return R_CLS(ADD_ABS_LO12_NC); @@ -337,19 +355,24 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx, case AArch64::fixup_aarch64_ldst_imm12_scale8: if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return R_CLS(LDST64_ABS_LO12_NC); - if (SymLoc == AArch64MCExpr::VK_GOT && IsNC) { + if ((SymLoc == AArch64MCExpr::VK_GOT || + SymLoc == AArch64MCExpr::VK_GOT_AUTH) && + IsNC) { AArch64MCExpr::VariantKind AddressLoc = AArch64MCExpr::getAddressFrag(RefKind); + bool IsAuth = (SymLoc == AArch64MCExpr::VK_GOT_AUTH); if (!IsILP32) { if (AddressLoc == AArch64MCExpr::VK_LO15) return ELF::R_AARCH64_LD64_GOTPAGE_LO15; - return ELF::R_AARCH64_LD64_GOT_LO12_NC; - } else { - Ctx.reportError(Fixup.getLoc(), "ILP32 64-bit load/store " - "relocation not supported (LP64 eqv: " - "LD64_GOT_LO12_NC)"); - return ELF::R_AARCH64_NONE; + return (IsAuth ? ELF::R_AARCH64_AUTH_GOT_LO12_NC + : ELF::R_AARCH64_LD64_GOT_LO12_NC); } + Ctx.reportError(Fixup.getLoc(), + Twine("ILP32 64-bit load/store " + "relocation not supported (LP64 eqv: ") + + (IsAuth ? "AUTH_GOT_LO12_NC" : "LD64_GOT_LO12_NC") + + Twine(')')); + return ELF::R_AARCH64_NONE; } if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC) return R_CLS(TLSLD_LDST64_DTPREL_LO12); diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.cpp index 0c5a9d79f6cb..768170281a05 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.cpp @@ -30,6 +30,7 @@ const AArch64MCExpr *AArch64MCExpr::create(const MCExpr *Expr, VariantKind Kind, } StringRef AArch64MCExpr::getVariantKindName() const { + // clang-format off switch (static_cast(getKind())) { case VK_CALL: return ""; case VK_LO12: return ":lo12:"; @@ -82,9 +83,13 @@ StringRef AArch64MCExpr::getVariantKindName() const { case VK_TLSDESC_PAGE: return ":tlsdesc:"; case VK_SECREL_LO12: return ":secrel_lo12:"; case VK_SECREL_HI12: return ":secrel_hi12:"; + case VK_GOT_AUTH: return ":got_auth:"; + case VK_GOT_AUTH_PAGE: return ":got_auth:"; + case VK_GOT_AUTH_LO12: return ":got_auth_lo12:"; default: llvm_unreachable("Invalid ELF symbol kind"); } + // clang-format on } void AArch64MCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.h index 48235988869c..780ae39c15a7 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.h +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.h @@ -24,6 +24,7 @@ namespace llvm { class AArch64MCExpr : public MCTargetExpr { public: enum VariantKind { + // clang-format off // Symbol locations specifying (roughly speaking) what calculation should be // performed to construct the final address for the relocated // symbol. E.g. direct, via the GOT, ... @@ -38,6 +39,7 @@ class AArch64MCExpr : public MCTargetExpr { VK_SECREL = 0x009, VK_AUTH = 0x00a, VK_AUTHADDR = 0x00b, + VK_GOT_AUTH = 0x00c, VK_SymLocBits = 0x00f, // Variants specifying which part of the final address calculation is @@ -88,6 +90,8 @@ class AArch64MCExpr : public MCTargetExpr { VK_GOT_LO12 = VK_GOT | VK_PAGEOFF | VK_NC, VK_GOT_PAGE = VK_GOT | VK_PAGE, VK_GOT_PAGE_LO15 = VK_GOT | VK_LO15 | VK_NC, + VK_GOT_AUTH_LO12 = VK_GOT_AUTH | VK_PAGEOFF | VK_NC, + VK_GOT_AUTH_PAGE = VK_GOT_AUTH | VK_PAGE, VK_DTPREL_G2 = VK_DTPREL | VK_G2, VK_DTPREL_G1 = VK_DTPREL | VK_G1, VK_DTPREL_G1_NC = VK_DTPREL | VK_G1 | VK_NC, @@ -114,6 +118,7 @@ class AArch64MCExpr : public MCTargetExpr { VK_SECREL_HI12 = VK_SECREL | VK_HI12, VK_INVALID = 0xfff + // clang-format on }; private: diff --git a/llvm/test/CodeGen/AArch64/basic-pic-auth.ll b/llvm/test/CodeGen/AArch64/basic-pic-auth.ll new file mode 100644 index 000000000000..32d2098ee63c --- /dev/null +++ b/llvm/test/CodeGen/AArch64/basic-pic-auth.ll @@ -0,0 +1,39 @@ +; RUN: llc -mtriple=aarch64-linux-gnu -global-isel=0 -fast-isel=0 -verify-machineinstrs \ +; RUN: -relocation-model=pic -mattr=+pauth %s -o - | FileCheck %s +; RUN: llc -mtriple=aarch64-linux-gnu -global-isel=0 -fast-isel=1 -verify-machineinstrs \ +; RUN: -relocation-model=pic -mattr=+pauth %s -o - | FileCheck %s +; RUN: llc -mtriple=aarch64-linux-gnu -global-isel=1 -verify-machineinstrs \ +; RUN: -relocation-model=pic -mattr=+pauth %s -o - | FileCheck %s + +;; Note: for FastISel, we fall back to SelectionDAG + +@var = global i32 0 + +define i32 @get_globalvar() { +; CHECK-LABEL: get_globalvar: + + %val = load i32, ptr @var + +; CHECK: adrp x[[GOT:[0-9]+]], :got_auth:var +; CHECK: add x[[GOT]], x[[GOT]], :got_auth_lo12:var +; CHECK: ldr x[[SYM:[0-9]+]], [x[[GOT]]] +; CHECK: autda x[[SYM]], x[[GOT]] +; CHECK: ldr w0, [x[[SYM]]] + ret i32 %val +} + +define ptr @get_globalvaraddr() { +; CHECK-LABEL: get_globalvaraddr: + + %val = load i32, ptr @var + +; CHECK: adrp x[[GOT:[0-9]+]], :got_auth:var +; CHECK: add x[[GOT]], x[[GOT]], :got_auth_lo12:var +; CHECK: ldr x0, [x[[GOT]]] +; CHECK: autda x0, x[[GOT]] + ret ptr @var +} + +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +!1 = !{i32 1, !"aarch64-elf-pauthabi-version", i32 128} diff --git a/llvm/test/CodeGen/AArch64/elf-globals-pic-auth.ll b/llvm/test/CodeGen/AArch64/elf-globals-pic-auth.ll new file mode 100644 index 000000000000..0bf76aeebd2c --- /dev/null +++ b/llvm/test/CodeGen/AArch64/elf-globals-pic-auth.ll @@ -0,0 +1,23 @@ +; RUN: llc -mtriple=arm64 -global-isel=0 -fast-isel=0 -relocation-model=pic -o - %s -mcpu=cyclone -mattr=+pauth | FileCheck %s +; RUN: llc -mtriple=arm64 -global-isel=0 -fast-isel=1 -relocation-model=pic -o - %s -mcpu=cyclone -mattr=+pauth | FileCheck %s +; RUN: llc -mtriple=arm64 -global-isel=1 -relocation-model=pic -o - %s -mcpu=cyclone -mattr=+pauth | FileCheck %s + +;; Note: for FastISel, we fall back to SelectionDAG + +@var8 = external global i8, align 1 + +define i8 @test_i8(i8 %new) { + %val = load i8, ptr @var8, align 1 + store i8 %new, ptr @var8 + ret i8 %val + +; CHECK: adrp x[[HIREG:[0-9]+]], :got_auth:var8 +; CHECK: add x[[HIREG]], x[[HIREG]], :got_auth_lo12:var8 +; CHECK: ldr x[[VAR_ADDR:[0-9]+]], [x[[HIREG]]] +; CHECK: autda x[[VAR_ADDR]], x[[HIREG]] +; CHECK: ldrb {{w[0-9]+}}, [x[[VAR_ADDR]]] +} + +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +!1 = !{i32 1, !"aarch64-elf-pauthabi-version", i32 128} diff --git a/llvm/test/CodeGen/AArch64/extern-weak-auth.ll b/llvm/test/CodeGen/AArch64/extern-weak-auth.ll new file mode 100644 index 000000000000..a6184501363a --- /dev/null +++ b/llvm/test/CodeGen/AArch64/extern-weak-auth.ll @@ -0,0 +1,36 @@ +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=0 -fast-isel=0 -relocation-model=pic -mattr=+pauth -o - %s | FileCheck %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=0 -fast-isel=1 -relocation-model=pic -mattr=+pauth -o - %s | FileCheck %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=1 -relocation-model=pic -mattr=+pauth -o - %s | FileCheck %s + +;; Note: for FastISel, we fall back to SelectionDAG + +declare extern_weak dso_local i32 @var() + +define ptr @foo() { +; The usual ADRP/ADD pair can't be used for a weak reference because it must +; evaluate to 0 if the symbol is undefined. We use a GOT entry for PIC +; otherwise a litpool entry. + ret ptr @var + +; CHECK: adrp x[[ADDRHI:[0-9]+]], :got_auth:var +; CHECK: add x[[ADDRHI]], x[[ADDRHI]], :got_auth_lo12:var +; CHECK: ldr x0, [x[[ADDRHI]]] +; CHECK: autia x0, x[[ADDRHI]] +} + +@arr_var = extern_weak global [10 x i32] + +define ptr @bar() { + %addr = getelementptr [10 x i32], ptr @arr_var, i32 0, i32 5 + +; CHECK: adrp x[[ADDRHI:[0-9]+]], :got_auth:arr_var +; CHECK: add x[[ADDRHI]], x[[ADDRHI]], :got_auth_lo12:arr_var +; CHECK: ldr [[BASE:x[0-9]+]], [x[[ADDRHI]]] +; CHECK: autda [[BASE]], x[[ADDRHI]] +; CHECK: add x0, [[BASE]], #20 + ret ptr %addr +} + +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +!1 = !{i32 1, !"aarch64-elf-pauthabi-version", i32 128} diff --git a/llvm/test/CodeGen/AArch64/got-abuse-auth.ll b/llvm/test/CodeGen/AArch64/got-abuse-auth.ll new file mode 100644 index 000000000000..da0aa19ea6bb --- /dev/null +++ b/llvm/test/CodeGen/AArch64/got-abuse-auth.ll @@ -0,0 +1,44 @@ +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=0 -fast-isel=0 -relocation-model=pic -mattr=+pauth -o - %s | FileCheck %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=0 -fast-isel=1 -relocation-model=pic -mattr=+pauth -o - %s | FileCheck %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=1 -relocation-model=pic -mattr=+pauth -o - %s | FileCheck %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=0 -fast-isel=0 -relocation-model=pic -filetype=obj -mattr=+pauth -o /dev/null %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=0 -fast-isel=1 -relocation-model=pic -filetype=obj -mattr=+pauth -o /dev/null %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=1 -relocation-model=pic -filetype=obj -mattr=+pauth -o /dev/null %s + +;; Note: for FastISel, we fall back to SelectionDAG + +declare void @consume(i32) +declare void @func() + +define void @aliasee_func() { + ret void +} +@alias_func = alias void (), ptr @aliasee_func + +@aliasee_global = global i32 42 +@alias_global = alias i32, ptr @aliasee_global + +define void @foo() nounwind { +; CHECK-LABEL: foo: +entry: + call void @consume(i32 ptrtoint (ptr @func to i32)) +; CHECK: adrp x[[ADDRHI:[0-9]+]], :got_auth:func +; CHECK: add x[[ADDRHI]], x[[ADDRHI]], :got_auth_lo12:func +; CHECK: ldr x[[SYM:[0-9]+]], [x[[ADDRHI]]] +; CHECK: autia x[[SYM:[0-9]+]], x[[ADDRHI]] + call void @consume(i32 ptrtoint (ptr @alias_func to i32)) +; CHECK: adrp x[[ADDRHI:[0-9]+]], :got_auth:alias_func +; CHECK: add x[[ADDRHI]], x[[ADDRHI]], :got_auth_lo12:alias_func +; CHECK: ldr x[[SYM:[0-9]+]], [x[[ADDRHI]]] +; CHECK: autia x[[SYM:[0-9]+]], x[[ADDRHI]] + call void @consume(i32 ptrtoint (ptr @alias_global to i32)) +; CHECK: adrp x[[ADDRHI:[0-9]+]], :got_auth:alias_global +; CHECK: add x[[ADDRHI]], x[[ADDRHI]], :got_auth_lo12:alias_global +; CHECK: ldr x[[SYM:[0-9]+]], [x[[ADDRHI]]] +; CHECK: autda x[[SYM:[0-9]+]], x[[ADDRHI]] + ret void +} + +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +!1 = !{i32 1, !"aarch64-elf-pauthabi-version", i32 128} diff --git a/llvm/test/CodeGen/AArch64/tagged-globals-pic-auth.ll b/llvm/test/CodeGen/AArch64/tagged-globals-pic-auth.ll new file mode 100644 index 000000000000..d0ba1c2bb9e2 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/tagged-globals-pic-auth.ll @@ -0,0 +1,66 @@ +; RUN: llc --relocation-model=pic -mattr=+pauth < %s | FileCheck %s + +; RUN: llc -global-isel=0 -fast-isel=0 -O0 --relocation-model=pic < %s -mattr=+pauth | FileCheck %s --check-prefixes=CHECK,DAGISEL +; RUN: llc -global-isel=0 -fast-isel=1 -O0 --relocation-model=pic < %s -mattr=+pauth | FileCheck %s --check-prefixes=CHECK,DAGISEL +; RUN: llc -global-isel=1 -O0 --relocation-model=pic < %s -mattr=+pauth | FileCheck %s --check-prefixes=CHECK,GISEL + +;; Note: for FastISel, we fall back to SelectionDAG + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-unknown-linux-android" + +@global = external global i32 +declare void @func() + +define ptr @global_addr() #0 { + ; CHECK: global_addr: + ; CHECK: adrp [[REG:x[0-9]+]], :got_auth:global + ; CHECK: add [[REG]], [[REG]], :got_auth_lo12:global + ; CHECK: ldr x0, [[[REG]]] + ; CHECK: autda x0, [[REG]] + ; CHECK: ret + + ret ptr @global +} + +define i32 @global_load() #0 { + ; CHECK: global_load: + ; CHECK: adrp [[REG0:x[0-9]+]], :got_auth:global + ; CHECK: add [[REG0]], [[REG0]], :got_auth_lo12:global + ; CHECK: ldr [[REG1:x[0-9]+]], [[[REG0]]] + ; CHECK: autda [[REG1]], [[REG0]] + ; CHECK: ldr w0, [[[REG1]]] + ; CHECK: ret + %load = load i32, ptr @global + ret i32 %load +} + +define void @global_store() #0 { + ; CHECK: global_store: + ; CHECK: adrp [[REG0:x[0-9]+]], :got_auth:global + ; CHECK: add [[REG0]], [[REG0]], :got_auth_lo12:global + ; CHECK: ldr [[REG1:x[0-9]+]], [[[REG0]]] + ; CHECK: autda [[REG1]], [[REG0]] + ; GISEL: str wzr, [[[REG1]]] + ; DAGISEL: mov w8, wzr + ; DAGISEL: str w8, [[[REG1]]] + ; CHECK: ret + store i32 0, ptr @global + ret void +} + +define ptr @func_addr() #0 { + ; CHECK: func_addr: + ; CHECK: adrp [[REG:x[0-9]+]], :got_auth:func + ; CHECK: add [[REG]], [[REG]], :got_auth_lo12:func + ; CHECK: ldr x0, [[[REG]]] + ; CHECK: autia x0, [[REG]] + ; CHECK: ret + ret ptr @func +} + +attributes #0 = { "target-features"="+tagged-globals" } + +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +!1 = !{i32 1, !"aarch64-elf-pauthabi-version", i32 128} diff --git a/llvm/test/MC/AArch64/adrp-auth-relocation.s b/llvm/test/MC/AArch64/adrp-auth-relocation.s new file mode 100644 index 000000000000..57021c71632f --- /dev/null +++ b/llvm/test/MC/AArch64/adrp-auth-relocation.s @@ -0,0 +1,12 @@ +// RUN: llvm-mc -triple=aarch64-linux-gnu -filetype=obj -o - %s | llvm-readobj -r - | FileCheck %s +// RUN: not llvm-mc -triple=aarch64-linux-gnu_ilp32 -filetype=obj \ +// RUN: -o /dev/null %s 2>&1 | FileCheck -check-prefix=CHECK-ILP32 %s + +.text +adrp x0, :got_auth:sym + +.global sym +sym: + +// CHECK: R_AARCH64_AUTH_ADR_GOT_PAGE sym +// CHECK-ILP32: error: ILP32 ADRP AUTH relocation not supported (LP64 eqv: AUTH_ADR_GOT_PAGE) diff --git a/llvm/test/MC/AArch64/arm64-elf-relocs.s b/llvm/test/MC/AArch64/arm64-elf-relocs.s index 8813c4bd7d1a..b2d6d9fe9ae4 100644 --- a/llvm/test/MC/AArch64/arm64-elf-relocs.s +++ b/llvm/test/MC/AArch64/arm64-elf-relocs.s @@ -81,13 +81,17 @@ // CHECK: adrp x15, :got:sym // CHECK-OBJ-LP64: 58 R_AARCH64_ADR_GOT_PAGE sym + adrp x15, :got_auth:sym +// CHECK: adrp x15, :got_auth:sym +// CHECK-OBJ-LP64: 5c R_AARCH64_AUTH_ADR_GOT_PAGE sym + adrp x29, :gottprel:sym // CHECK: adrp x29, :gottprel:sym -// CHECK-OBJ-LP64: 5c R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 sym +// CHECK-OBJ-LP64: 60 R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 sym adrp x2, :tlsdesc:sym // CHECK: adrp x2, :tlsdesc:sym -// CHECK-OBJ-LP64: 60 R_AARCH64_TLSDESC_ADR_PAGE21 sym +// CHECK-OBJ-LP64: 64 R_AARCH64_TLSDESC_ADR_PAGE21 sym // LLVM is not competent enough to do this relocation because the // page boundary could occur anywhere after linking. A relocation @@ -96,7 +100,7 @@ .global trickQuestion trickQuestion: // CHECK: adrp x3, trickQuestion -// CHECK-OBJ-LP64: 64 R_AARCH64_ADR_PREL_PG_HI21 trickQuestion +// CHECK-OBJ-LP64: 68 R_AARCH64_ADR_PREL_PG_HI21 trickQuestion ldrb w2, [x3, :lo12:sym] ldrsb w5, [x7, #:lo12:sym] @@ -245,6 +249,16 @@ trickQuestion: // CHECK-OBJ-LP64: R_AARCH64_LD64_GOT_LO12_NC sym // CHECK-OBJ-LP64: R_AARCH64_LD64_GOT_LO12_NC sym+0x7 + ldr x24, [x23, #:got_auth_lo12:sym] + ldr d22, [x21, :got_auth_lo12:sym] + ldr x24, [x23, :got_auth_lo12:sym+7] +// CHECK: ldr x24, [x23, :got_auth_lo12:sym] +// CHECK: ldr d22, [x21, :got_auth_lo12:sym] +// CHECK: ldr x24, [x23, :got_auth_lo12:sym+7] +// CHECK-OBJ-LP64: R_AARCH64_AUTH_GOT_LO12_NC sym +// CHECK-OBJ-LP64: R_AARCH64_AUTH_GOT_LO12_NC sym +// CHECK-OBJ-LP64: R_AARCH64_AUTH_GOT_LO12_NC sym+0x7 + ldr x24, [x23, #:gotpage_lo15:sym] ldr d22, [x21, :gotpage_lo15:sym] ldr d22, [x23, :gotpage_lo15:sym+7] diff --git a/llvm/test/MC/AArch64/ilp32-diagnostics.s b/llvm/test/MC/AArch64/ilp32-diagnostics.s index 4ca15f160418..f2d0c8d2e37d 100644 --- a/llvm/test/MC/AArch64/ilp32-diagnostics.s +++ b/llvm/test/MC/AArch64/ilp32-diagnostics.s @@ -85,6 +85,14 @@ ldr x24, [x23, #:got_lo12:sym] // CHECK-ERROR: error: ILP32 64-bit load/store relocation not supported (LP64 eqv: LD64_GOT_LO12_NC) +// CHECK-ERROR: ^ + + ldr x24, [x23, #:got_auth_lo12:sym] +// CHECK-ERROR: error: ILP32 64-bit load/store relocation not supported (LP64 eqv: AUTH_GOT_LO12_NC) +// CHECK-ERROR: ^ + + add x24, x23, #:got_auth_lo12:sym +// CHECK-ERROR: error: ILP32 ADD AUTH relocation not supported (LP64 eqv: AUTH_GOT_ADD_LO12_NC) // CHECK-ERROR: ^ ldr x24, [x23, :gottprel_lo12:sym] From 9f0d4643e5fb8d24afede67a2fb660ef4c87f242 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Mon, 15 Apr 2024 04:53:06 +0300 Subject: [PATCH 7/9] [PAC][lld][AArch64][ELF] Support signed GOT Support `R_AARCH64_AUTH_ADR_GOT_PAGE`, `R_AARCH64_AUTH_GOT_LO12_NC` and `R_AARCH64_AUTH_GOT_ADD_LO12_NC` GOT-generating relocations. For preemptible symbols, dynamic relocation `R_AARCH64_AUTH_GLOB_DAT` is emitted. Otherwise, we unconditionally emit `R_AARCH64_AUTH_RELATIVE` dynamic relocation since pointers in signed GOT needs to be signed during dynamic link time. --- lld/ELF/Arch/AArch64.cpp | 9 ++ lld/ELF/InputSection.cpp | 2 + lld/ELF/Relocations.cpp | 42 +++++++-- lld/ELF/Relocations.h | 2 + lld/ELF/Symbols.h | 1 + lld/ELF/SyntheticSections.cpp | 19 +++++ lld/ELF/SyntheticSections.h | 5 ++ lld/test/ELF/aarch64-auth-got-relocations.s | 94 +++++++++++++++++++++ 8 files changed, 165 insertions(+), 9 deletions(-) create mode 100644 lld/test/ELF/aarch64-auth-got-relocations.s diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index 2bf6e2c6c851..661799f51661 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -169,11 +169,16 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s, case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: return R_GOT; + case R_AARCH64_AUTH_GOT_LO12_NC: + case R_AARCH64_AUTH_GOT_ADD_LO12_NC: + return R_AARCH64_AUTH_GOT; case R_AARCH64_LD64_GOTPAGE_LO15: return R_AARCH64_GOT_PAGE; case R_AARCH64_ADR_GOT_PAGE: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: return R_AARCH64_GOT_PAGE_PC; + case R_AARCH64_AUTH_ADR_GOT_PAGE: + return R_AARCH64_AUTH_GOT_PAGE_PC; case R_AARCH64_GOTPCREL32: return R_GOT_PC; case R_AARCH64_NONE: @@ -224,6 +229,7 @@ int64_t AArch64::getImplicitAddend(const uint8_t *buf, RelType type) const { return read64(buf + 8); case R_AARCH64_NONE: case R_AARCH64_GLOB_DAT: + case R_AARCH64_AUTH_GLOB_DAT: case R_AARCH64_JUMP_SLOT: return 0; case R_AARCH64_ABS16: @@ -429,9 +435,11 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel, write64(loc, val); break; case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_AUTH_GOT_ADD_LO12_NC: or32AArch64Imm(loc, val); break; case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_AUTH_ADR_GOT_PAGE: case R_AARCH64_ADR_PREL_PG_HI21: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case R_AARCH64_TLSDESC_ADR_PAGE21: @@ -480,6 +488,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel, break; case R_AARCH64_LDST64_ABS_LO12_NC: case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_AUTH_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: case R_AARCH64_TLSDESC_LD64_LO12: diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index fa48552b8f7a..f31feeb1d17e 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -691,6 +691,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, case R_ARM_SBREL: return sym.getVA(a) - getARMStaticBase(sym); case R_GOT: + case R_AARCH64_AUTH_GOT: case R_RELAX_TLS_GD_TO_IE_ABS: return sym.getGotVA() + a; case R_LOONGARCH_GOT: @@ -718,6 +719,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, case R_RELAX_TLS_GD_TO_IE_GOT_OFF: return sym.getGotOffset() + a; case R_AARCH64_GOT_PAGE_PC: + case R_AARCH64_AUTH_GOT_PAGE_PC: case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC: return getAArch64Page(sym.getGotVA() + a) - getAArch64Page(p); case R_AARCH64_GOT_PAGE: diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 04db413a6609..ebb55c1d9bd6 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -209,8 +209,9 @@ static bool needsPlt(RelExpr expr) { } bool lld::elf::needsGot(RelExpr expr) { - return oneof( expr); } @@ -924,13 +925,25 @@ void elf::addGotEntry(Symbol &sym) { // If preemptible, emit a GLOB_DAT relocation. if (sym.isPreemptible) { - mainPart->relaDyn->addReloc({target->gotRel, in.got.get(), off, + RelType gotRel = target->gotRel; + if (sym.hasFlag(NEEDS_GOT_AUTH)) { + assert(config->emachine == EM_AARCH64); + gotRel = R_AARCH64_AUTH_GLOB_DAT; + } + mainPart->relaDyn->addReloc({gotRel, in.got.get(), off, DynamicReloc::AgainstSymbol, sym, 0, R_ABS}); return; } // Otherwise, the value is either a link-time constant or the load base - // plus a constant. + // plus a constant. Signed GOT requires dynamic relocation. + if (sym.hasFlag(NEEDS_GOT_AUTH)) { + in.got->getPartition().relaDyn->addReloc( + {R_AARCH64_AUTH_RELATIVE, in.got.get(), off, + DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS}); + return; + } + if (!config->isPic || isAbsolute(sym)) in.got->addConstant({R_ABS, target->symbolicRel, off, 0, &sym}); else @@ -983,10 +996,11 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type, // These expressions always compute a constant if (oneof(e)) return true; @@ -1099,7 +1113,17 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset, } else if (!sym.isTls() || config->emachine != EM_LOONGARCH) { // Many LoongArch TLS relocs reuse the R_LOONGARCH_GOT type, in which // case the NEEDS_GOT flag shouldn't get set. - sym.setFlags(NEEDS_GOT); + bool needsGotAuth = + (expr == R_AARCH64_AUTH_GOT || expr == R_AARCH64_AUTH_GOT_PAGE_PC); + if (!sym.hasFlag(NEEDS_GOT)) { + sym.setFlags(NEEDS_GOT); + if (needsGotAuth) + sym.setFlags(NEEDS_GOT_AUTH); + } else if (needsGotAuth != sym.hasFlag(NEEDS_GOT_AUTH)) { + fatal("both AUTH and non-AUTH GOT entries for '" + sym.getName() + + "' requested, but only one type of GOT entry per symbol is " + "supported"); + } } } else if (needsPlt(expr)) { sym.setFlags(NEEDS_PLT); diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index b7b9c09e1b89..19521ab6eac2 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -83,7 +83,9 @@ enum RelExpr { // of a relocation type, there are some relocations whose semantics are // unique to a target. Such relocation are marked with R_. R_AARCH64_GOT_PAGE_PC, + R_AARCH64_AUTH_GOT_PAGE_PC, R_AARCH64_GOT_PAGE, + R_AARCH64_AUTH_GOT, R_AARCH64_PAGE_PC, R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC, R_AARCH64_TLSDESC_PAGE, diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index c65c5d6cd0dc..c8aa3d937af0 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -54,6 +54,7 @@ enum { NEEDS_TLSGD_TO_IE = 1 << 6, NEEDS_GOT_DTPREL = 1 << 7, NEEDS_TLSIE = 1 << 8, + NEEDS_GOT_AUTH = 1 << 9, }; // Some index properties of a symbol are stored separately in this auxiliary diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 7b9ada40c0f6..2b4219344081 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -655,6 +655,10 @@ void GotSection::addConstant(const Relocation &r) { relocations.push_back(r); } void GotSection::addEntry(const Symbol &sym) { assert(sym.auxIdx == symAux.size() - 1); symAux.back().gotIdx = numEntries++; + if (sym.hasFlag(NEEDS_GOT_AUTH)) { + assert(config->emachine == EM_AARCH64); + authEntries.push_back({(numEntries - 1) * config->wordsize, sym.isFunc()}); + } } bool GotSection::addTlsDescEntry(const Symbol &sym) { @@ -718,6 +722,21 @@ void GotSection::writeTo(uint8_t *buf) { return; target->writeGotHeader(buf); target->relocateAlloc(*this, buf); + for (const AuthEntryInfo &authEntry : authEntries) { + // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#default-signing-schema + // Signed GOT entries use the IA key for symbols of type STT_FUNC and the + // DA key for all other symbol types, with the address of the GOT entry as + // the modifier. The static linker must encode the signing schema into the + // GOT slot. + // + // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#encoding-the-signing-schema + // If address diversity is set and the discriminator + // is 0 then modifier = Place + uint8_t *dest = buf + authEntry.offset; + uint64_t key = authEntry.isSymbolFunc ? /*IA*/ 0b00 : /*DA*/ 0b10; + uint64_t addrDiversity = 1; + write64(dest, (addrDiversity << 63) | (key << 60)); + } } static uint64_t getMipsPageAddr(uint64_t addr) { diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 995fd4b344b0..6a217cd9af45 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -131,6 +131,11 @@ class GotSection final : public SyntheticSection { size_t numEntries = 0; uint32_t tlsIndexOff = -1; uint64_t size = 0; + struct AuthEntryInfo { + size_t offset; + bool isSymbolFunc; + }; + SmallVector authEntries; }; // .note.GNU-stack section. diff --git a/lld/test/ELF/aarch64-auth-got-relocations.s b/lld/test/ELF/aarch64-auth-got-relocations.s new file mode 100644 index 000000000000..f04e3d953388 --- /dev/null +++ b/lld/test/ELF/aarch64-auth-got-relocations.s @@ -0,0 +1,94 @@ +# REQUIRES: aarch64 + +# RUN: rm -rf %t && split-file %s %t && cd %t + +# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %p/Inputs/shared.s -o a.o +# RUN: ld.lld -shared a.o -o a.so + +#--- ok.s + +# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux ok.s -o ok.o + +# RUN: ld.lld ok.o a.so -pie -o external +# RUN: llvm-readelf -r -S -x .got external | FileCheck %s --check-prefix=EXTERNAL + +# RUN: ld.lld ok.o a.o -pie -o local +# RUN: llvm-readelf -r -S -x .got -s local | FileCheck %s --check-prefix=LOCAL + +# EXTERNAL: Offset Info Type Symbol's Value Symbol's Name + Addend +# EXTERNAL-NEXT: 0000000000020380 000000010000e201 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 bar + 0 +# EXTERNAL-NEXT: 0000000000020388 000000020000e201 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 zed + 0 + +## Symbol's values for bar and zed are equal since they contain no content (see Inputs/shared.s) +# LOCAL: Offset Info Type Symbol's Value Symbol's Name + Addend +# LOCAL-NEXT: 0000000000020320 0000000000000411 R_AARCH64_AUTH_RELATIVE 10260 +# LOCAL-NEXT: 0000000000020328 0000000000000411 R_AARCH64_AUTH_RELATIVE 10260 + +# EXTERNAL: Hex dump of section '.got': +# EXTERNAL-NEXT: 0x00020380 00000000 00000080 00000000 000000a0 +# ^^ +# 0b10000000 bit 63 address diversity = true, bits 61..60 key = IA +# ^^ +# 0b10100000 bit 63 address diversity = true, bits 61..60 key = DA + +# LOCAL: Symbol table '.symtab' contains {{.*}} entries: +# LOCAL: Num: Value Size Type Bind Vis Ndx Name +# LOCAL: 0000000000010260 0 FUNC GLOBAL DEFAULT 6 bar +# LOCAL: 0000000000010260 0 NOTYPE GLOBAL DEFAULT 6 zed + +# LOCAL: Hex dump of section '.got': +# LOCAL-NEXT: 0x00020320 00000000 00000080 00000000 000000a0 +# ^^ +# 0b10000000 bit 63 address diversity = true, bits 61..60 key = IA +# ^^ +# 0b10100000 bit 63 address diversity = true, bits 61..60 key = DA + +# RUN: llvm-objdump -d external | FileCheck %s --check-prefix=EXTERNAL-ASM + +# EXTERNAL-ASM: <_start>: +# EXTERNAL-ASM-NEXT: adrp x0, 0x20000 +# EXTERNAL-ASM-NEXT: ldr x0, [x0, #0x380] +# EXTERNAL-ASM-NEXT: adrp x1, 0x20000 +# EXTERNAL-ASM-NEXT: add x1, x1, #0x380 +# EXTERNAL-ASM-NEXT: adrp x0, 0x20000 +# EXTERNAL-ASM-NEXT: ldr x0, [x0, #0x388] +# EXTERNAL-ASM-NEXT: adrp x1, 0x20000 +# EXTERNAL-ASM-NEXT: add x1, x1, #0x388 + +# RUN: llvm-objdump -d local | FileCheck %s --check-prefix=LOCAL-ASM + +# LOCAL-ASM: <_start>: +# LOCAL-ASM-NEXT: adrp x0, 0x20000 +# LOCAL-ASM-NEXT: ldr x0, [x0, #0x320] +# LOCAL-ASM-NEXT: adrp x1, 0x20000 +# LOCAL-ASM-NEXT: add x1, x1, #0x320 +# LOCAL-ASM-NEXT: adrp x0, 0x20000 +# LOCAL-ASM-NEXT: ldr x0, [x0, #0x328] +# LOCAL-ASM-NEXT: adrp x1, 0x20000 +# LOCAL-ASM-NEXT: add x1, x1, #0x328 + +.globl _start +_start: + adrp x0, :got_auth:bar + ldr x0, [x0, :got_auth_lo12:bar] + adrp x1, :got_auth:bar + add x1, x1, :got_auth_lo12:bar + adrp x0, :got_auth:zed + ldr x0, [x0, :got_auth_lo12:zed] + adrp x1, :got_auth:zed + add x1, x1, :got_auth_lo12:zed + +#--- err.s + +# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux err.s -o err.o + +# RUN: not ld.lld err.o a.so -pie -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR + +# ERR: error: both AUTH and non-AUTH GOT entries for 'bar' requested, but only one type of GOT entry per symbol is supported + +.globl _start +_start: + adrp x0, :got_auth:bar + ldr x0, [x0, :got_auth_lo12:bar] + adrp x0, :got:bar + ldr x0, [x0, :got_lo12:bar] From 09344487f191eb68731db9b8089c02cb5fbdbabb Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Mon, 22 Apr 2024 04:52:38 +0300 Subject: [PATCH 8/9] [PAC][CodeGen][ELF][AArch64] Support signed GOT with tiny code model Support the following relocations and assembly operators: - `R_AARCH64_AUTH_GOT_ADR_PREL21` (`:got_auth:` for `adr`) - `R_AARCH64_AUTH_GOT_LD_PREL19` (`:got_auth:` for `ldr`) `LOADgotAUTH` pseudo-instruction is expanded to actual instruction sequence like the following. ``` adr x16, :got_auth:sym ldr x0, [x16] autia x0, x16 ``` Both SelectionDAG and GlobalISel are suppported. For FastISel, we fall back to SelectionDAG. Tests with 'auth' in name have corresponding variants w/o it. --- .../AArch64/AArch64ExpandPseudoInsts.cpp | 35 +++-- .../AArch64/AsmParser/AArch64AsmParser.cpp | 8 +- .../MCTargetDesc/AArch64ELFObjectWriter.cpp | 18 +++ llvm/test/CodeGen/AArch64/extern-weak-auth.ll | 13 +- .../CodeGen/AArch64/tiny-model-pic-auth.ll | 148 ++++++++++++++++++ .../CodeGen/AArch64/tiny-model-static-auth.ll | 126 +++++++++++++++ llvm/test/MC/AArch64/arm64-elf-relocs.s | 13 ++ llvm/test/MC/AArch64/ilp32-diagnostics.s | 8 + 8 files changed, 353 insertions(+), 16 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/tiny-model-pic-auth.ll create mode 100644 llvm/test/CodeGen/AArch64/tiny-model-static-auth.ll diff --git a/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp b/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp index 6d27e982533c..09431e4cde40 100644 --- a/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp +++ b/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp @@ -1247,26 +1247,33 @@ bool AArch64ExpandPseudo::expandMI(MachineBasicBlock &MBB, return true; } case AArch64::LOADgotAUTH: { + const MachineFunction *MF = MBB.getParent(); Register DstReg = MI.getOperand(0).getReg(); const MachineOperand &MO1 = MI.getOperand(1); + DebugLoc DL = MI.getDebugLoc(); - MachineOperand GAHiOp(MO1); - MachineOperand GALoOp(MO1); - GAHiOp.addTargetFlag(AArch64II::MO_PAGE); - GALoOp.addTargetFlag(AArch64II::MO_PAGEOFF | AArch64II::MO_NC); + if (MF->getTarget().getCodeModel() == CodeModel::Tiny) { + BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADR), AArch64::X16).add(MO1); + BuildMI(MBB, MBBI, DL, TII->get(AArch64::LDRXui), DstReg) + .addReg(AArch64::X16) + .addImm(0); + } else { + MachineOperand GAHiOp(MO1); + MachineOperand GALoOp(MO1); + GAHiOp.addTargetFlag(AArch64II::MO_PAGE); + GALoOp.addTargetFlag(AArch64II::MO_PAGEOFF | AArch64II::MO_NC); - DebugLoc DL = MI.getDebugLoc(); - BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADRP), AArch64::X16) - .add(GAHiOp); + BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADRP), AArch64::X16).add(GAHiOp); - BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADDXri), AArch64::X16) - .addReg(AArch64::X16) - .add(GALoOp) - .addImm(0); + BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADDXri), AArch64::X16) + .addReg(AArch64::X16) + .add(GALoOp) + .addImm(0); - BuildMI(MBB, MBBI, DL, TII->get(AArch64::LDRXui), DstReg) - .addReg(AArch64::X16) - .addImm(0); + BuildMI(MBB, MBBI, DL, TII->get(AArch64::LDRXui), DstReg) + .addReg(AArch64::X16) + .addImm(0); + } assert(MO1.isGlobal()); assert(MO1.getGlobal()->getValueType() != nullptr); diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 4db8c081613d..fd4b98526711 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -3293,7 +3293,13 @@ ParseStatus AArch64AsmParser::tryParseAdrLabel(OperandVector &Operands) { // No modifier was specified at all; this is the syntax for an ELF basic // ADR relocation (unfortunately). Expr = AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS, getContext()); - } else { + } else if (ELFRefKind != AArch64MCExpr::VK_GOT_AUTH_PAGE) { + // For tiny code model, we use :got_auth: operator to fill 21-bit imm of + // adr. It's not actually GOT entry page address but the GOT address + // itself - we just share the same variant kind with :got_auth: operator + // applied for adrp. + // TODO: can we somehow get current TargetMachine object to call + // getCodeModel() on it to ensure we are using tiny code model? return Error(S, "unexpected adr label"); } } diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp index 8df844e477a5..6a583681e7a8 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp @@ -149,6 +149,15 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx, } else return ELF::R_AARCH64_PREL64; case AArch64::fixup_aarch64_pcrel_adr_imm21: + if (SymLoc == AArch64MCExpr::VK_GOT_AUTH) { + if (IsILP32) { + Ctx.reportError(Fixup.getLoc(), + "ILP32 ADR AUTH relocation not supported " + "(LP64 eqv: AUTH_GOT_ADR_PREL21)"); + return ELF::R_AARCH64_NONE; + } + return ELF::R_AARCH64_AUTH_GOT_ADR_PREL21; + } if (SymLoc != AArch64MCExpr::VK_ABS) Ctx.reportError(Fixup.getLoc(), "invalid symbol kind for ADR relocation"); @@ -193,6 +202,15 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx, return R_CLS(TLSIE_LD_GOTTPREL_PREL19); if (SymLoc == AArch64MCExpr::VK_GOT) return R_CLS(GOT_LD_PREL19); + if (SymLoc == AArch64MCExpr::VK_GOT_AUTH) { + if (IsILP32) { + Ctx.reportError(Fixup.getLoc(), + "ILP32 LDR AUTH relocation not supported " + "(LP64 eqv: AUTH_GOT_LD_PREL19)"); + return ELF::R_AARCH64_NONE; + } + return ELF::R_AARCH64_AUTH_GOT_LD_PREL19; + } return R_CLS(LD_PREL_LO19); case AArch64::fixup_aarch64_pcrel_branch14: return R_CLS(TSTBR14); diff --git a/llvm/test/CodeGen/AArch64/extern-weak-auth.ll b/llvm/test/CodeGen/AArch64/extern-weak-auth.ll index a6184501363a..605630be4d53 100644 --- a/llvm/test/CodeGen/AArch64/extern-weak-auth.ll +++ b/llvm/test/CodeGen/AArch64/extern-weak-auth.ll @@ -2,6 +2,8 @@ ; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=0 -fast-isel=1 -relocation-model=pic -mattr=+pauth -o - %s | FileCheck %s ; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=1 -relocation-model=pic -mattr=+pauth -o - %s | FileCheck %s +; RUN: llc -mtriple=aarch64-none-elf -code-model=tiny -mattr=+pauth -o - %s | FileCheck --check-prefix=CHECK-TINY %s + ;; Note: for FastISel, we fall back to SelectionDAG declare extern_weak dso_local i32 @var() @@ -16,19 +18,28 @@ define ptr @foo() { ; CHECK: add x[[ADDRHI]], x[[ADDRHI]], :got_auth_lo12:var ; CHECK: ldr x0, [x[[ADDRHI]]] ; CHECK: autia x0, x[[ADDRHI]] + +; CHECK-TINY: adr x16, :got_auth:var +; CHECK-TINY: ldr x0, [x16] +; CHECK-TINY: autia x0, x16 } @arr_var = extern_weak global [10 x i32] define ptr @bar() { %addr = getelementptr [10 x i32], ptr @arr_var, i32 0, i32 5 + ret ptr %addr ; CHECK: adrp x[[ADDRHI:[0-9]+]], :got_auth:arr_var ; CHECK: add x[[ADDRHI]], x[[ADDRHI]], :got_auth_lo12:arr_var ; CHECK: ldr [[BASE:x[0-9]+]], [x[[ADDRHI]]] ; CHECK: autda [[BASE]], x[[ADDRHI]] ; CHECK: add x0, [[BASE]], #20 - ret ptr %addr + +; CHECK-TINY: adr x16, :got_auth:arr_var +; CHECK-TINY: ldr [[BASE:x[0-9]+]], [x16] +; CHECK-TINY: autda [[BASE]], x16 +; CHECK-TINY: add x0, [[BASE]], #20 } !llvm.module.flags = !{!0, !1} diff --git a/llvm/test/CodeGen/AArch64/tiny-model-pic-auth.ll b/llvm/test/CodeGen/AArch64/tiny-model-pic-auth.ll new file mode 100644 index 000000000000..6d602afc53ef --- /dev/null +++ b/llvm/test/CodeGen/AArch64/tiny-model-pic-auth.ll @@ -0,0 +1,148 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -mtriple=aarch64 -mattr=+pauth -code-model=tiny -relocation-model=pic < %s | FileCheck %s --check-prefix=CHECK-PIC +; RUN: llc -verify-machineinstrs -mtriple=aarch64 -mattr=+pauth -code-model=tiny -relocation-model=pic -fast-isel < %s | FileCheck %s --check-prefix=CHECK-PIC +; RUN: llc -verify-machineinstrs -mtriple=aarch64 -mattr=+pauth -code-model=tiny -relocation-model=pic -global-isel < %s | FileCheck %s --check-prefix=CHECK-PIC-GLOBISEL + +; TODO Note fast-isel tests here will fall back to isel + +@src = external local_unnamed_addr global [65536 x i8], align 1 +@dst = external global [65536 x i8], align 1 +@ptr = external local_unnamed_addr global ptr, align 8 + +define dso_preemptable void @foo1() { +; CHECK-PIC-LABEL: foo1: +; CHECK-PIC: // %bb.0: // %entry +; CHECK-PIC-NEXT: adr x16, :got_auth:src +; CHECK-PIC-NEXT: ldr x8, [x16] +; CHECK-PIC-NEXT: autda x8, x16 +; CHECK-PIC-NEXT: adr x16, :got_auth:dst +; CHECK-PIC-NEXT: ldrb w8, [x8] +; CHECK-PIC-NEXT: ldr x9, [x16] +; CHECK-PIC-NEXT: autda x9, x16 +; CHECK-PIC-NEXT: strb w8, [x9] +; CHECK-PIC-NEXT: ret +; +; CHECK-PIC-GLOBISEL-LABEL: foo1: +; CHECK-PIC-GLOBISEL: // %bb.0: // %entry +; CHECK-PIC-GLOBISEL-NEXT: adr x16, :got_auth:src +; CHECK-PIC-GLOBISEL-NEXT: ldr x8, [x16] +; CHECK-PIC-GLOBISEL-NEXT: autda x8, x16 +; CHECK-PIC-GLOBISEL-NEXT: adr x16, :got_auth:dst +; CHECK-PIC-GLOBISEL-NEXT: ldrb w8, [x8] +; CHECK-PIC-GLOBISEL-NEXT: ldr x9, [x16] +; CHECK-PIC-GLOBISEL-NEXT: autda x9, x16 +; CHECK-PIC-GLOBISEL-NEXT: strb w8, [x9] +; CHECK-PIC-GLOBISEL-NEXT: ret +entry: + %0 = load i8, ptr @src, align 1 + store i8 %0, ptr @dst, align 1 + ret void +} + +define dso_preemptable void @foo2() { +; CHECK-PIC-LABEL: foo2: +; CHECK-PIC: // %bb.0: // %entry +; CHECK-PIC-NEXT: adr x16, :got_auth:ptr +; CHECK-PIC-NEXT: ldr x8, [x16] +; CHECK-PIC-NEXT: autda x8, x16 +; CHECK-PIC-NEXT: adr x16, :got_auth:dst +; CHECK-PIC-NEXT: ldr x9, [x16] +; CHECK-PIC-NEXT: autda x9, x16 +; CHECK-PIC-NEXT: str x9, [x8] +; CHECK-PIC-NEXT: ret +; +; CHECK-PIC-GLOBISEL-LABEL: foo2: +; CHECK-PIC-GLOBISEL: // %bb.0: // %entry +; CHECK-PIC-GLOBISEL-NEXT: adr x16, :got_auth:ptr +; CHECK-PIC-GLOBISEL-NEXT: ldr x8, [x16] +; CHECK-PIC-GLOBISEL-NEXT: autda x8, x16 +; CHECK-PIC-GLOBISEL-NEXT: adr x16, :got_auth:dst +; CHECK-PIC-GLOBISEL-NEXT: ldr x9, [x16] +; CHECK-PIC-GLOBISEL-NEXT: autda x9, x16 +; CHECK-PIC-GLOBISEL-NEXT: str x9, [x8] +; CHECK-PIC-GLOBISEL-NEXT: ret +entry: + store ptr @dst, ptr @ptr, align 8 + ret void +} + +define dso_preemptable void @foo3() { +; FIXME: Needn't adr ptr +; +; CHECK-PIC-LABEL: foo3: +; CHECK-PIC: // %bb.0: // %entry +; CHECK-PIC-NEXT: adr x16, :got_auth:src +; CHECK-PIC-NEXT: ldr x8, [x16] +; CHECK-PIC-NEXT: autda x8, x16 +; CHECK-PIC-NEXT: adr x16, :got_auth:ptr +; CHECK-PIC-NEXT: ldrb w8, [x8] +; CHECK-PIC-NEXT: ldr x9, [x16] +; CHECK-PIC-NEXT: autda x9, x16 +; CHECK-PIC-NEXT: ldr x9, [x9] +; CHECK-PIC-NEXT: strb w8, [x9] +; CHECK-PIC-NEXT: ret +; +; CHECK-PIC-GLOBISEL-LABEL: foo3: +; CHECK-PIC-GLOBISEL: // %bb.0: // %entry +; CHECK-PIC-GLOBISEL-NEXT: adr x16, :got_auth:src +; CHECK-PIC-GLOBISEL-NEXT: ldr x8, [x16] +; CHECK-PIC-GLOBISEL-NEXT: autda x8, x16 +; CHECK-PIC-GLOBISEL-NEXT: adr x16, :got_auth:ptr +; CHECK-PIC-GLOBISEL-NEXT: ldrb w8, [x8] +; CHECK-PIC-GLOBISEL-NEXT: ldr x9, [x16] +; CHECK-PIC-GLOBISEL-NEXT: autda x9, x16 +; CHECK-PIC-GLOBISEL-NEXT: ldr x9, [x9] +; CHECK-PIC-GLOBISEL-NEXT: strb w8, [x9] +; CHECK-PIC-GLOBISEL-NEXT: ret +entry: + %0 = load i8, ptr @src, align 1 + %1 = load ptr, ptr @ptr, align 8 + store i8 %0, ptr %1, align 1 + ret void +} + +@lsrc = internal global i8 0, align 4 +@ldst = internal global i8 0, align 4 +@lptr = internal global ptr null, align 8 + +declare void @func(...) + +define dso_preemptable ptr @externfuncaddr() { +; CHECK-PIC-LABEL: externfuncaddr: +; CHECK-PIC: // %bb.0: // %entry +; CHECK-PIC-NEXT: adr x16, :got_auth:func +; CHECK-PIC-NEXT: ldr x0, [x16] +; CHECK-PIC-NEXT: autia x0, x16 +; CHECK-PIC-NEXT: ret +; +; CHECK-PIC-GLOBISEL-LABEL: externfuncaddr: +; CHECK-PIC-GLOBISEL: // %bb.0: // %entry +; CHECK-PIC-GLOBISEL-NEXT: adr x16, :got_auth:func +; CHECK-PIC-GLOBISEL-NEXT: ldr x0, [x16] +; CHECK-PIC-GLOBISEL-NEXT: autia x0, x16 +; CHECK-PIC-GLOBISEL-NEXT: ret +entry: + ret ptr @func +} + +define dso_preemptable ptr @localfuncaddr() { +; CHECK-PIC-LABEL: localfuncaddr: +; CHECK-PIC: // %bb.0: // %entry +; CHECK-PIC-NEXT: adr x16, :got_auth:externfuncaddr +; CHECK-PIC-NEXT: ldr x0, [x16] +; CHECK-PIC-NEXT: autia x0, x16 +; CHECK-PIC-NEXT: ret +; +; CHECK-PIC-GLOBISEL-LABEL: localfuncaddr: +; CHECK-PIC-GLOBISEL: // %bb.0: // %entry +; CHECK-PIC-GLOBISEL-NEXT: adr x16, :got_auth:externfuncaddr +; CHECK-PIC-GLOBISEL-NEXT: ldr x0, [x16] +; CHECK-PIC-GLOBISEL-NEXT: autia x0, x16 +; CHECK-PIC-GLOBISEL-NEXT: ret +entry: + ret ptr @externfuncaddr +} + +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +!1 = !{i32 1, !"aarch64-elf-pauthabi-version", i32 128} diff --git a/llvm/test/CodeGen/AArch64/tiny-model-static-auth.ll b/llvm/test/CodeGen/AArch64/tiny-model-static-auth.ll new file mode 100644 index 000000000000..4e8b1bedfb51 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/tiny-model-static-auth.ll @@ -0,0 +1,126 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -o - -mtriple=aarch64-none-linux-gnu -mattr=+pauth -code-model=tiny < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -o - -mtriple=aarch64-none-linux-gnu -mattr=+pauth -code-model=tiny -fast-isel < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -o - -mtriple=aarch64-none-linux-gnu -mattr=+pauth -code-model=tiny -global-isel < %s | FileCheck %s --check-prefix=CHECK-GLOBISEL + +; Note fast-isel tests here will fall back to isel + +@src = external local_unnamed_addr global [65536 x i8], align 1 +@dst = external global [65536 x i8], align 1 +@ptr = external local_unnamed_addr global ptr, align 8 + +define dso_local void @foo1() { +; CHECK-LABEL: foo1: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: adr x16, :got_auth:src +; CHECK-NEXT: ldr x8, [x16] +; CHECK-NEXT: autda x8, x16 +; CHECK-NEXT: adr x16, :got_auth:dst +; CHECK-NEXT: ldrb w8, [x8] +; CHECK-NEXT: ldr x9, [x16] +; CHECK-NEXT: autda x9, x16 +; CHECK-NEXT: strb w8, [x9] +; CHECK-NEXT: ret +; +; CHECK-GLOBISEL-LABEL: foo1: +; CHECK-GLOBISEL: // %bb.0: // %entry +; CHECK-GLOBISEL-NEXT: adr x16, :got_auth:src +; CHECK-GLOBISEL-NEXT: ldr x8, [x16] +; CHECK-GLOBISEL-NEXT: autda x8, x16 +; CHECK-GLOBISEL-NEXT: adr x16, :got_auth:dst +; CHECK-GLOBISEL-NEXT: ldrb w8, [x8] +; CHECK-GLOBISEL-NEXT: ldr x9, [x16] +; CHECK-GLOBISEL-NEXT: autda x9, x16 +; CHECK-GLOBISEL-NEXT: strb w8, [x9] +; CHECK-GLOBISEL-NEXT: ret +entry: + %0 = load i8, ptr @src, align 1 + store i8 %0, ptr @dst, align 1 + ret void +} + +define dso_local void @foo2() { +; CHECK-LABEL: foo2: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: adr x16, :got_auth:ptr +; CHECK-NEXT: ldr x8, [x16] +; CHECK-NEXT: autda x8, x16 +; CHECK-NEXT: adr x16, :got_auth:dst +; CHECK-NEXT: ldr x9, [x16] +; CHECK-NEXT: autda x9, x16 +; CHECK-NEXT: str x9, [x8] +; CHECK-NEXT: ret +; +; CHECK-GLOBISEL-LABEL: foo2: +; CHECK-GLOBISEL: // %bb.0: // %entry +; CHECK-GLOBISEL-NEXT: adr x16, :got_auth:ptr +; CHECK-GLOBISEL-NEXT: ldr x8, [x16] +; CHECK-GLOBISEL-NEXT: autda x8, x16 +; CHECK-GLOBISEL-NEXT: adr x16, :got_auth:dst +; CHECK-GLOBISEL-NEXT: ldr x9, [x16] +; CHECK-GLOBISEL-NEXT: autda x9, x16 +; CHECK-GLOBISEL-NEXT: str x9, [x8] +; CHECK-GLOBISEL-NEXT: ret +entry: + store ptr @dst, ptr @ptr, align 8 + ret void +} + +define dso_local void @foo3() { +; FIXME: Needn't adr ptr +; +; CHECK-LABEL: foo3: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: adr x16, :got_auth:src +; CHECK-NEXT: ldr x8, [x16] +; CHECK-NEXT: autda x8, x16 +; CHECK-NEXT: adr x16, :got_auth:ptr +; CHECK-NEXT: ldrb w8, [x8] +; CHECK-NEXT: ldr x9, [x16] +; CHECK-NEXT: autda x9, x16 +; CHECK-NEXT: ldr x9, [x9] +; CHECK-NEXT: strb w8, [x9] +; CHECK-NEXT: ret +; +; CHECK-GLOBISEL-LABEL: foo3: +; CHECK-GLOBISEL: // %bb.0: // %entry +; CHECK-GLOBISEL-NEXT: adr x16, :got_auth:src +; CHECK-GLOBISEL-NEXT: ldr x8, [x16] +; CHECK-GLOBISEL-NEXT: autda x8, x16 +; CHECK-GLOBISEL-NEXT: adr x16, :got_auth:ptr +; CHECK-GLOBISEL-NEXT: ldrb w8, [x8] +; CHECK-GLOBISEL-NEXT: ldr x9, [x16] +; CHECK-GLOBISEL-NEXT: autda x9, x16 +; CHECK-GLOBISEL-NEXT: ldr x9, [x9] +; CHECK-GLOBISEL-NEXT: strb w8, [x9] +; CHECK-GLOBISEL-NEXT: ret +entry: + %0 = load i8, ptr @src, align 1 + %1 = load ptr, ptr @ptr, align 8 + store i8 %0, ptr %1, align 1 + ret void +} + +declare void @func(...) + +define dso_local ptr @externfuncaddr() { +; CHECK-LABEL: externfuncaddr: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: adr x16, :got_auth:func +; CHECK-NEXT: ldr x0, [x16] +; CHECK-NEXT: autia x0, x16 +; CHECK-NEXT: ret +; +; CHECK-GLOBISEL-LABEL: externfuncaddr: +; CHECK-GLOBISEL: // %bb.0: // %entry +; CHECK-GLOBISEL-NEXT: adr x16, :got_auth:func +; CHECK-GLOBISEL-NEXT: ldr x0, [x16] +; CHECK-GLOBISEL-NEXT: autia x0, x16 +; CHECK-GLOBISEL-NEXT: ret +entry: + ret ptr @func +} + +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +!1 = !{i32 1, !"aarch64-elf-pauthabi-version", i32 128} diff --git a/llvm/test/MC/AArch64/arm64-elf-relocs.s b/llvm/test/MC/AArch64/arm64-elf-relocs.s index b2d6d9fe9ae4..3e7bd1492016 100644 --- a/llvm/test/MC/AArch64/arm64-elf-relocs.s +++ b/llvm/test/MC/AArch64/arm64-elf-relocs.s @@ -331,6 +331,19 @@ trickQuestion: // CHECK-OBJ-LP64: R_AARCH64_GOT_LD_PREL19 sym // CHECK-OBJ-LP64: R_AARCH64_GOT_LD_PREL19 sym + adr x24, #:got_auth:sym + adr x24, :got_auth:sym + ldr x24, #:got_auth:sym + ldr x24, :got_auth:sym +// CHECK: adr x24, :got_auth:sym +// CHECK: adr x24, :got_auth:sym +// CHECK: ldr x24, :got_auth:sym +// CHECK: ldr x24, :got_auth:sym +// CHECK-OBJ-LP64: R_AARCH64_AUTH_GOT_ADR_PREL21 sym +// CHECK-OBJ-LP64: R_AARCH64_AUTH_GOT_ADR_PREL21 sym +// CHECK-OBJ-LP64: R_AARCH64_AUTH_GOT_LD_PREL19 sym +// CHECK-OBJ-LP64: R_AARCH64_AUTH_GOT_LD_PREL19 sym + // GOT relocations referencing local symbols are not converted to reference // STT_SECTION symbols. https://github.com/llvm/llvm-project/issues/63418 ldr x0, [x0, :got_lo12:local0] diff --git a/llvm/test/MC/AArch64/ilp32-diagnostics.s b/llvm/test/MC/AArch64/ilp32-diagnostics.s index f2d0c8d2e37d..472c140ea36a 100644 --- a/llvm/test/MC/AArch64/ilp32-diagnostics.s +++ b/llvm/test/MC/AArch64/ilp32-diagnostics.s @@ -110,4 +110,12 @@ ldr x24, [x23, :gottprel_lo12:sym] // CHECK-ERROR: error: ILP32 64-bit load/store relocation not supported (LP64 eqv: TLSIE_LD64_GOTTPREL_LO12_NC) +// CHECK-ERROR: ^ + + ldr x24, :got_auth:sym +// CHECK-ERROR: error: ILP32 LDR AUTH relocation not supported (LP64 eqv: AUTH_GOT_LD_PREL19) +// CHECK-ERROR: ^ + + adr x24, :got_auth:sym +// CHECK-ERROR: error: ILP32 ADR AUTH relocation not supported (LP64 eqv: AUTH_GOT_ADR_PREL21) // CHECK-ERROR: ^ From edb2275daf6ac0fefbe2f9d0cd7b08ba5a36ba8b Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Thu, 18 Apr 2024 22:43:28 +0300 Subject: [PATCH 9/9] [PAC][lld][AArch64][ELF] Support signed GOT with tiny code model Support `R_AARCH64_AUTH_GOT_ADR_PREL21` and `R_AARCH64_AUTH_GOT_LD_PREL19` GOT-generating relocations. --- lld/ELF/Arch/AArch64.cpp | 5 ++ lld/ELF/InputSection.cpp | 1 + lld/ELF/Relocations.cpp | 17 ++--- lld/ELF/Relocations.h | 1 + lld/test/ELF/aarch64-auth-got-relocations.s | 73 +++++++++++++++++++++ 5 files changed, 89 insertions(+), 8 deletions(-) diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index 661799f51661..d10f8177c60d 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -172,6 +172,9 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s, case R_AARCH64_AUTH_GOT_LO12_NC: case R_AARCH64_AUTH_GOT_ADD_LO12_NC: return R_AARCH64_AUTH_GOT; + case R_AARCH64_AUTH_GOT_LD_PREL19: + case R_AARCH64_AUTH_GOT_ADR_PREL21: + return R_AARCH64_AUTH_GOT_PC; case R_AARCH64_LD64_GOTPAGE_LO15: return R_AARCH64_GOT_PAGE; case R_AARCH64_ADR_GOT_PAGE: @@ -449,6 +452,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel, write32AArch64Addr(loc, val >> 12); break; case R_AARCH64_ADR_PREL_LO21: + case R_AARCH64_AUTH_GOT_ADR_PREL21: checkInt(loc, val, 21, rel); write32AArch64Addr(loc, val); break; @@ -468,6 +472,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel, break; case R_AARCH64_CONDBR19: case R_AARCH64_LD_PREL_LO19: + case R_AARCH64_AUTH_GOT_LD_PREL19: checkAlignment(loc, val, 4, rel); checkInt(loc, val, 21, rel); or32le(loc, (val & 0x1FFFFC) << 3); diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index f31feeb1d17e..0ecbc928bff8 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -725,6 +725,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, case R_AARCH64_GOT_PAGE: return sym.getGotVA() + a - getAArch64Page(in.got->getVA()); case R_GOT_PC: + case R_AARCH64_AUTH_GOT_PC: case R_RELAX_TLS_GD_TO_IE: return sym.getGotVA() + a - p; case R_GOTPLT_GOTREL: diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index ebb55c1d9bd6..550d1a538281 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -209,11 +209,11 @@ static bool needsPlt(RelExpr expr) { } bool lld::elf::needsGot(RelExpr expr) { - return oneof( - expr); + return oneof(expr); } // True if this expression is of the form Sym - X, where X is a position in the @@ -1000,8 +1000,8 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type, R_GOTONLY_PC, R_GOTPLTONLY_PC, R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT, R_GOTPLT_GOTREL, R_GOTPLT_PC, R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD, R_AARCH64_GOT_PAGE, - R_AARCH64_AUTH_GOT, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT, - R_LOONGARCH_GOT_PAGE_PC>(e)) + R_AARCH64_AUTH_GOT, R_AARCH64_AUTH_GOT_PC, R_LOONGARCH_PLT_PAGE_PC, + R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC>(e)) return true; // These never do, except if the entire file is position dependent or if @@ -1114,7 +1114,8 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset, // Many LoongArch TLS relocs reuse the R_LOONGARCH_GOT type, in which // case the NEEDS_GOT flag shouldn't get set. bool needsGotAuth = - (expr == R_AARCH64_AUTH_GOT || expr == R_AARCH64_AUTH_GOT_PAGE_PC); + (expr == R_AARCH64_AUTH_GOT || expr == R_AARCH64_AUTH_GOT_PC || + expr == R_AARCH64_AUTH_GOT_PAGE_PC); if (!sym.hasFlag(NEEDS_GOT)) { sym.setFlags(NEEDS_GOT); if (needsGotAuth) diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index 19521ab6eac2..692476a98d78 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -86,6 +86,7 @@ enum RelExpr { R_AARCH64_AUTH_GOT_PAGE_PC, R_AARCH64_GOT_PAGE, R_AARCH64_AUTH_GOT, + R_AARCH64_AUTH_GOT_PC, R_AARCH64_PAGE_PC, R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC, R_AARCH64_TLSDESC_PAGE, diff --git a/lld/test/ELF/aarch64-auth-got-relocations.s b/lld/test/ELF/aarch64-auth-got-relocations.s index f04e3d953388..c43f1ca251a9 100644 --- a/lld/test/ELF/aarch64-auth-got-relocations.s +++ b/lld/test/ELF/aarch64-auth-got-relocations.s @@ -78,6 +78,79 @@ _start: adrp x1, :got_auth:zed add x1, x1, :got_auth_lo12:zed +#--- ok-tiny.s + +# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux ok-tiny.s -o ok-tiny.o + +# RUN: ld.lld ok-tiny.o a.so -pie -o external-tiny +# RUN: llvm-readelf -r -S -x .got external-tiny | FileCheck %s --check-prefix=EXTERNAL-TINY + +# RUN: ld.lld ok-tiny.o a.o -pie -o local-tiny +# RUN: llvm-readelf -r -S -x .got -s local-tiny | FileCheck %s --check-prefix=LOCAL-TINY + +# EXTERNAL-TINY: Offset Info Type Symbol's Value Symbol's Name + Addend +# EXTERNAL-TINY-NEXT: 0000000000020380 000000010000e201 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 bar + 0 +# EXTERNAL-TINY-NEXT: 0000000000020388 000000020000e201 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 zed + 0 + +## Symbol's values for bar and zed are equal since they contain no content (see Inputs/shared.s) +# LOCAL-TINY: Offset Info Type Symbol's Value Symbol's Name + Addend +# LOCAL-TINY-NEXT: 0000000000020320 0000000000000411 R_AARCH64_AUTH_RELATIVE 10260 +# LOCAL-TINY-NEXT: 0000000000020328 0000000000000411 R_AARCH64_AUTH_RELATIVE 10260 + +# EXTERNAL-TINY: Hex dump of section '.got': +# EXTERNAL-TINY-NEXT: 0x00020380 00000000 00000080 00000000 000000a0 +# ^^ +# 0b10000000 bit 63 address diversity = true, bits 61..60 key = IA +# ^^ +# 0b10100000 bit 63 address diversity = true, bits 61..60 key = DA + +# LOCAL-TINY: Symbol table '.symtab' contains {{.*}} entries: +# LOCAL-TINY: Num: Value Size Type Bind Vis Ndx Name +# LOCAL-TINY: 0000000000010260 0 FUNC GLOBAL DEFAULT 6 bar +# LOCAL-TINY: 0000000000010260 0 NOTYPE GLOBAL DEFAULT 6 zed + +# LOCAL-TINY: Hex dump of section '.got': +# LOCAL-TINY-NEXT: 0x00020320 00000000 00000080 00000000 000000a0 +# ^^ +# 0b10000000 bit 63 address diversity = true, bits 61..60 key = IA +# ^^ +# 0b10100000 bit 63 address diversity = true, bits 61..60 key = DA + +# RUN: llvm-objdump -d external-tiny | FileCheck %s --check-prefix=EXTERNAL-TINY-ASM + +# EXTERNAL-TINY-ASM: <_start>: +# EXTERNAL-TINY-ASM-NEXT: adr x0, 0x20380 +# EXTERNAL-TINY-ASM-NEXT: ldr x1, [x0] +# EXTERNAL-TINY-ASM-NEXT: adr x0, 0x20380 +# EXTERNAL-TINY-ASM-NEXT: ldr x1, 0x20380 +# EXTERNAL-TINY-ASM-NEXT: adr x0, 0x20388 +# EXTERNAL-TINY-ASM-NEXT: ldr x1, [x0] +# EXTERNAL-TINY-ASM-NEXT: adr x0, 0x20388 +# EXTERNAL-TINY-ASM-NEXT: ldr x1, 0x20388 + +# RUN: llvm-objdump -d local-tiny | FileCheck %s --check-prefix=LOCAL-TINY-ASM + +# LOCAL-TINY-ASM: <_start>: +# LOCAL-TINY-ASM-NEXT: adr x0, 0x20320 +# LOCAL-TINY-ASM-NEXT: ldr x1, [x0] +# LOCAL-TINY-ASM-NEXT: adr x0, 0x20320 +# LOCAL-TINY-ASM-NEXT: ldr x1, 0x20320 +# LOCAL-TINY-ASM-NEXT: adr x0, 0x20328 +# LOCAL-TINY-ASM-NEXT: ldr x1, [x0] +# LOCAL-TINY-ASM-NEXT: adr x0, 0x20328 +# LOCAL-TINY-ASM-NEXT: ldr x1, 0x20328 + +.globl _start +_start: + adr x0, :got_auth:bar + ldr x1, [x0] + adr x0, :got_auth:bar + ldr x1, :got_auth:bar + adr x0, :got_auth:zed + ldr x1, [x0] + adr x0, :got_auth:zed + ldr x1, :got_auth:zed + #--- err.s # RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux err.s -o err.o