Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -2030,6 +2030,10 @@ def ffixed_x20 : Flag<["-"], "ffixed-x20">, Group, HelpText<"Reserve the x20 register (AArch64 only)">; +def msign_return_address : Joined<["-"], "msign-return-address=">, + Flags<[CC1Option]>, Group, + HelpText<"Select return address signing scope">, Values<"none,all,non-leaf">; + def msimd128 : Flag<["-"], "msimd128">, Group; def mno_simd128 : Flag<["-"], "mno-simd128">, Group; def mnontrapping_fptoint : Flag<["-"], "mnontrapping-fptoint">, Group; Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -108,6 +108,12 @@ Embed_Marker // Embed a marker as a placeholder for bitcode. }; + enum SignReturnAddressScope { + None, // No signing for any function + NonLeaf, // Sign the return address of functions that spill LR + All // Sign the return address of all functions + }; + /// The code model to use (-mcmodel). std::string CodeModel; Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -339,6 +339,7 @@ /// Whether to emit an address-significance table into the object file. CODEGENOPT(Addrsig, 1, 0) +ENUM_CODEGENOPT(SignReturnAddress, SignReturnAddressScope, 2, None) #undef CODEGENOPT #undef ENUM_CODEGENOPT Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -4969,6 +4969,23 @@ } bool doesReturnSlotInterfereWithArgs() const override { return false; } + + void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &CGM) const override { + const FunctionDecl *FD = dyn_cast_or_null(D); + if (!FD) + return; + llvm::Function *Fn = cast(GV); + + auto Kind = CGM.getCodeGenOpts().getSignReturnAddress(); + if (Kind == CodeGenOptions::SignReturnAddressScope::None) + return; + + Fn->addFnAttr("sign-return-address", + Kind == CodeGenOptions::SignReturnAddressScope::All + ? "all" + : "non-leaf"); + } }; class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo { Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -4073,6 +4073,11 @@ options::OPT_mno_stack_arg_probe, true)) CmdArgs.push_back(Args.MakeArgString("-mno-stack-arg-probe")); + if (Arg *A = Args.getLastArg(options::OPT_msign_return_address)) { + CmdArgs.push_back( + Args.MakeArgString(Twine("-msign-return-address=") + A->getValue())); + } + if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it, options::OPT_mno_restrict_it)) { if (A->getOption().matches(options::OPT_mrestrict_it)) { Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -1125,6 +1125,19 @@ Opts.Addrsig = Args.hasArg(OPT_faddrsig); + if (Arg *A = Args.getLastArg(OPT_msign_return_address)) { + StringRef SignScope = A->getValue(); + if (SignScope.equals_lower("none")) + Opts.setSignReturnAddress(CodeGenOptions::SignReturnAddressScope::None); + else if (SignScope.equals_lower("all")) + Opts.setSignReturnAddress(CodeGenOptions::SignReturnAddressScope::All); + else if (SignScope.equals_lower("non-leaf")) + Opts.setSignReturnAddress(CodeGenOptions::SignReturnAddressScope::NonLeaf); + else + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) + << A->getValue(); + } + return Success; } Index: test/CodeGen/aarch64-sign-return-address.c =================================================================== --- /dev/null +++ test/CodeGen/aarch64-sign-return-address.c @@ -0,0 +1,14 @@ +// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -msign-return-address=none %s | FileCheck %s --check-prefix=CHECK-NONE +// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -msign-return-address=non-leaf %s | FileCheck %s --check-prefix=CHECK-PARTIAL +// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -msign-return-address=all %s | FileCheck %s --check-prefix=CHECK-ALL + +// CHECK-NONE: @foo() #[[ATTR:[0-9]*]] +// CHECK-NONE-NOT: attributes #[[ATTR]] = { {{.*}} "sign-return-address"={{.*}} }} + +// CHECK-PARTIAL: @foo() #[[ATTR:[0-9]*]] +// CHECK-PARTIAL: attributes #[[ATTR]] = { {{.*}} "sign-return-address"="non-leaf" {{.*}}} + +// CHECK-ALL: @foo() #[[ATTR:[0-9]*]] +// CHECK-ALL: attributes #[[ATTR]] = { {{.*}} "sign-return-address"="all" {{.*}} } + +void foo() {}