diff --git a/gcc/config/aarch64/aarch64-builtins.c b/gcc/config/aarch64/aarch64-builtins.c index 8cced94567008e28b1761ec8771589a3925f2904..d676f36c157c486cc9cbe6bffe0a7389ba0ccdd8 100644 --- a/gcc/config/aarch64/aarch64-builtins.c +++ b/gcc/config/aarch64/aarch64-builtins.c @@ -398,6 +398,8 @@ enum aarch64_builtins /* ARMv8.3-A Pointer Authentication Builtins. */ AARCH64_PAUTH_BUILTIN_AUTIA1716, AARCH64_PAUTH_BUILTIN_PACIA1716, + AARCH64_PAUTH_BUILTIN_AUTIB1716, + AARCH64_PAUTH_BUILTIN_PACIB1716, AARCH64_PAUTH_BUILTIN_XPACLRI, AARCH64_BUILTIN_MAX }; @@ -971,6 +973,14 @@ aarch64_init_pauth_hint_builtins (void) = add_builtin_function ("__builtin_aarch64_pacia1716", ftype_pointer_auth, AARCH64_PAUTH_BUILTIN_PACIA1716, BUILT_IN_MD, NULL, NULL_TREE); + aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_AUTIB1716] + = add_builtin_function ("__builtin_aarch64_autib1716", ftype_pointer_auth, + AARCH64_PAUTH_BUILTIN_AUTIB1716, BUILT_IN_MD, NULL, + NULL_TREE); + aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_PACIB1716] + = add_builtin_function ("__builtin_aarch64_pacib1716", ftype_pointer_auth, + AARCH64_PAUTH_BUILTIN_PACIB1716, BUILT_IN_MD, NULL, + NULL_TREE); aarch64_builtin_decls[AARCH64_PAUTH_BUILTIN_XPACLRI] = add_builtin_function ("__builtin_aarch64_xpaclri", ftype_pointer_strip, AARCH64_PAUTH_BUILTIN_XPACLRI, BUILT_IN_MD, NULL, @@ -1360,6 +1370,8 @@ aarch64_expand_builtin (tree exp, case AARCH64_PAUTH_BUILTIN_AUTIA1716: case AARCH64_PAUTH_BUILTIN_PACIA1716: + case AARCH64_PAUTH_BUILTIN_AUTIB1716: + case AARCH64_PAUTH_BUILTIN_PACIB1716: case AARCH64_PAUTH_BUILTIN_XPACLRI: arg0 = CALL_EXPR_ARG (exp, 0); op0 = force_reg (Pmode, expand_normal (arg0)); @@ -1383,8 +1395,24 @@ aarch64_expand_builtin (tree exp, { tree arg1 = CALL_EXPR_ARG (exp, 1); rtx op1 = force_reg (Pmode, expand_normal (arg1)); - icode = (fcode == AARCH64_PAUTH_BUILTIN_PACIA1716 - ? CODE_FOR_paci1716 : CODE_FOR_auti1716); + switch (fcode) + { + case AARCH64_PAUTH_BUILTIN_AUTIA1716: + icode = CODE_FOR_autia1716; + break; + case AARCH64_PAUTH_BUILTIN_AUTIB1716: + icode = CODE_FOR_autib1716; + break; + case AARCH64_PAUTH_BUILTIN_PACIA1716: + icode = CODE_FOR_pacia1716; + break; + case AARCH64_PAUTH_BUILTIN_PACIB1716: + icode = CODE_FOR_pacib1716; + break; + default: + icode = 0; + gcc_unreachable (); + } rtx x16_reg = gen_rtx_REG (Pmode, R16_REGNUM); rtx x17_reg = gen_rtx_REG (Pmode, R17_REGNUM); diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 1fe1a50d52aeb3719cf30c4a2af41abb8dd7233d..2893cdc0cc023ba4275be859e199da3a85ddc308 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -392,8 +392,17 @@ enum simd_immediate_check { AARCH64_CHECK_MOV = AARCH64_CHECK_ORR | AARCH64_CHECK_BIC }; +/* The key type that -msign-return-address should use. */ +enum aarch64_key_type { + AARCH64_KEY_A, + AARCH64_KEY_B +}; + +extern enum aarch64_key_type aarch64_ra_sign_key; + extern struct tune_params aarch64_tune_params; +void aarch64_post_cfi_startproc (void); poly_int64 aarch64_initial_elimination_offset (unsigned, unsigned); int aarch64_get_condition_code (rtx); bool aarch64_address_valid_for_prefetch_p (rtx, bool); diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 0c833a8fdfde0fde0e7c1f01cbdbdef4c2fb0009..8ab21e7bc37c7d5ffba1a365345f70d9f501b3ac 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -489,6 +489,9 @@ extern unsigned aarch64_architecture_version; #define ASM_DECLARE_FUNCTION_NAME(STR, NAME, DECL) \ aarch64_declare_function_name (STR, NAME, DECL) +/* Output assembly strings after .cfi_startproc is emitted. */ +#define ASM_POST_CFI_STARTPROC aarch64_post_cfi_startproc + /* For EH returns X4 contains the stack adjustment. */ #define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, R4_REGNUM) #define EH_RETURN_HANDLER_RTX aarch64_eh_return_handler_rtx () diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 121348dbd909f42717efea163ea6b7c545f5b1c7..9129b2000bb60ab411c278c866b8eca83a2eeadd 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -1091,6 +1091,8 @@ static const struct processor *selected_arch; static const struct processor *selected_cpu; static const struct processor *selected_tune; +enum aarch64_key_type aarch64_ra_sign_key = AARCH64_KEY_A; + /* The current tuning set. */ struct tune_params aarch64_tune_params = generic_tunings; @@ -1151,6 +1153,7 @@ aarch64_handle_standard_branch_protection (char* str ATTRIBUTE_UNUSED, char* rest ATTRIBUTE_UNUSED) { aarch64_ra_sign_scope = AARCH64_FUNCTION_NON_LEAF; + aarch64_ra_sign_key = AARCH64_KEY_A; if (rest) { error ("unexpected %<%s%> after %<%s%>", rest, str); @@ -1164,6 +1167,7 @@ aarch64_handle_pac_ret_protection (char* str ATTRIBUTE_UNUSED, char* rest ATTRIBUTE_UNUSED) { aarch64_ra_sign_scope = AARCH64_FUNCTION_NON_LEAF; + aarch64_ra_sign_key = AARCH64_KEY_A; return AARCH64_PARSE_OK; } @@ -1175,8 +1179,17 @@ aarch64_handle_pac_ret_leaf (char* str ATTRIBUTE_UNUSED, return AARCH64_PARSE_OK; } +static enum aarch64_parse_opt_result +aarch64_handle_pac_ret_b_key (char* str ATTRIBUTE_UNUSED, + char* rest ATTRIBUTE_UNUSED) +{ + aarch64_ra_sign_key = AARCH64_KEY_B; + return AARCH64_PARSE_OK; +} + static const struct aarch64_branch_protec_type aarch64_pac_ret_subtypes[] = { { "leaf", aarch64_handle_pac_ret_leaf, NULL, 0 }, + { "b-key", aarch64_handle_pac_ret_b_key, NULL, 0 }, { NULL, NULL, NULL, 0 } }; @@ -4590,11 +4603,10 @@ aarch64_gen_load_pair (machine_mode mode, rtx reg1, rtx mem1, rtx reg2, bool aarch64_return_address_signing_enabled (void) { - /* This function should only be called after frame laid out. */ - gcc_assert (cfun->machine->frame.laid_out); - /* If signing scope is AARCH64_FUNCTION_NON_LEAF, we only sign a leaf function - if it's LR is pushed onto stack. */ + if its LR is pushed onto stack. */ + if (aarch64_ra_sign_scope == AARCH64_FUNCTION_NONE) + return false; return (aarch64_ra_sign_scope == AARCH64_FUNCTION_ALL || (aarch64_ra_sign_scope == AARCH64_FUNCTION_NON_LEAF && cfun->machine->frame.reg_offset[LR_REGNUM] >= 0)); @@ -5344,7 +5356,17 @@ aarch64_expand_prologue (void) /* Sign return address for functions. */ if (aarch64_return_address_signing_enabled ()) { - insn = emit_insn (gen_pacisp ()); + switch (aarch64_ra_sign_key) + { + case AARCH64_KEY_A: + insn = emit_insn (gen_paciasp ()); + break; + case AARCH64_KEY_B: + insn = emit_insn (gen_pacibsp ()); + break; + default: + gcc_unreachable (); + } add_reg_note (insn, REG_CFA_TOGGLE_RA_MANGLE, const0_rtx); RTX_FRAME_RELATED_P (insn) = 1; } @@ -5576,7 +5598,17 @@ aarch64_expand_epilogue (bool for_sibcall) if (aarch64_return_address_signing_enabled () && (for_sibcall || !TARGET_ARMV8_3 || crtl->calls_eh_return)) { - insn = emit_insn (gen_autisp ()); + switch (aarch64_ra_sign_key) + { + case AARCH64_KEY_A: + insn = emit_insn (gen_autiasp ()); + break; + case AARCH64_KEY_B: + insn = emit_insn (gen_autibsp ()); + break; + default: + gcc_unreachable (); + } add_reg_note (insn, REG_CFA_TOGGLE_RA_MANGLE, const0_rtx); RTX_FRAME_RELATED_P (insn) = 1; } @@ -11265,11 +11297,6 @@ aarch64_validate_mcpu (const char *str, const struct processor **res, return false; } -/* Parses CONST_STR for branch protection features specified in - aarch64_branch_protec_types, and set any global variables required. Returns - the parsing result and assigns LAST_STR to the last processed token from - CONST_STR so that it can be used for error reporting. */ - static enum aarch64_parse_opt_result aarch64_parse_branch_protection (const char *const_str, char** last_str) @@ -11898,8 +11925,7 @@ aarch64_handle_attr_cpu (const char *str) attribute"); break; case AARCH64_PARSE_INVALID_ARG: - error ("invalid protection type (\"%s\") in % pragma or attribute", err_str); + error ("invalid protection type (\"%s\") in % pragma or attribute", err_str); aarch64_print_hint_for_core (str); break; case AARCH64_PARSE_OK: @@ -14820,6 +14846,18 @@ aarch64_declare_function_name (FILE *stream, const char* name, ASM_OUTPUT_LABEL (stream, name); } +/* Triggered after a .cfi_startproc directive is emitted into the assembly file. + Used to output the .cfi_b_key_frame directive when signing the current + function with the B key. */ + +void +aarch64_post_cfi_startproc (FILE *f, tree ignored ATTRIBUTE_UNUSED) +{ + if (aarch64_return_address_signing_enabled () + && aarch64_ra_sign_key == AARCH64_KEY_B) + asm_fprintf (f, "\t.cfi_b_key_frame\n"); +} + /* Implements TARGET_ASM_FILE_START. Output the assembly header. */ static void @@ -18543,6 +18581,9 @@ aarch64_libgcc_floating_mode_supported_p #define TARGET_RUN_TARGET_SELFTESTS selftest::aarch64_run_selftests #endif /* #if CHECKING_P */ +#undef TARGET_ASM_POST_CFI_STARTPROC +#define TARGET_ASM_POST_CFI_STARTPROC aarch64_post_cfi_startproc + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-aarch64.h" diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index ada623bb6f11172f9500bf6104781f05b6d60e50..84d5015761404b8cf73eff5a7d7cee09657a4d4f 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -118,8 +118,10 @@ ) (define_c_enum "unspec" [ - UNSPEC_AUTI1716 - UNSPEC_AUTISP + UNSPEC_AUTIA1716 + UNSPEC_AUTIB1716 + UNSPEC_AUTIASP + UNSPEC_AUTIBSP UNSPEC_CASESI UNSPEC_CRC32B UNSPEC_CRC32CB @@ -162,8 +164,10 @@ UNSPEC_LD4_LANE UNSPEC_MB UNSPEC_NOP - UNSPEC_PACI1716 - UNSPEC_PACISP + UNSPEC_PACIA1716 + UNSPEC_PACIB1716 + UNSPEC_PACIASP + UNSPEC_PACIBSP UNSPEC_PRLG_STK UNSPEC_REV UNSPEC_RBIT @@ -711,8 +715,12 @@ if (aarch64_return_address_signing_enabled () && TARGET_ARMV8_3 && !crtl->calls_eh_return) - return "retaa"; - + { + if (aarch64_ra_sign_key == AARCH64_KEY_B) + return "retab"; + else + return "retaa"; + } return "ret"; } [(set_attr "type" "branch")] @@ -6481,7 +6489,13 @@ [(set (reg:DI R30_REGNUM) (unspec:DI [(reg:DI R30_REGNUM) (reg:DI SP_REGNUM)] PAUTH_LR_SP))] "" - "hint\t // asp"; + { + enum aarch64_key_type key = ; + if (key == AARCH64_KEY_B) + return "hint\t // sp"; + else + return "hint\t // sp"; + } ) ;; Signing/Authenticating X17 using X16 as the salt. @@ -6490,7 +6504,13 @@ [(set (reg:DI R17_REGNUM) (unspec:DI [(reg:DI R17_REGNUM) (reg:DI R16_REGNUM)] PAUTH_17_16))] "" - "hint\t // a1716"; + { + enum aarch64_key_type key = ; + if (key == AARCH64_KEY_B) + return "hint\t // 1716"; + else + return "hint\t // 1716"; + } ) ;; Stripping the signature in R30. diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md index 524e4e6929bc9a7136966987600de2513748c20b..799f9d5267a9e5d69df8149255a0114648821103 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -1482,9 +1482,11 @@ (define_int_iterator FMAXMIN_UNS [UNSPEC_FMAX UNSPEC_FMIN UNSPEC_FMAXNM UNSPEC_FMINNM]) -(define_int_iterator PAUTH_LR_SP [UNSPEC_PACISP UNSPEC_AUTISP]) +(define_int_iterator PAUTH_LR_SP [UNSPEC_PACIASP UNSPEC_AUTIASP + UNSPEC_PACIBSP UNSPEC_AUTIBSP]) -(define_int_iterator PAUTH_17_16 [UNSPEC_PACI1716 UNSPEC_AUTI1716]) +(define_int_iterator PAUTH_17_16 [UNSPEC_PACIA1716 UNSPEC_AUTIA1716 + UNSPEC_PACIB1716 UNSPEC_AUTIB1716]) (define_int_iterator VQDMULH [UNSPEC_SQDMULH UNSPEC_SQRDMULH]) @@ -1755,16 +1757,35 @@ (UNSPEC_FCVTZU "fcvtzu")]) ;; Pointer authentication mnemonic prefix. -(define_int_attr pauth_mnem_prefix [(UNSPEC_PACISP "paci") - (UNSPEC_AUTISP "auti") - (UNSPEC_PACI1716 "paci") - (UNSPEC_AUTI1716 "auti")]) +(define_int_attr pauth_mnem_prefix [(UNSPEC_PACIASP "pacia") + (UNSPEC_PACIBSP "pacib") + (UNSPEC_PACIA1716 "pacia") + (UNSPEC_PACIB1716 "pacib") + (UNSPEC_AUTIASP "autia") + (UNSPEC_AUTIBSP "autib") + (UNSPEC_AUTIA1716 "autia") + (UNSPEC_AUTIB1716 "autib")]) + +(define_int_attr pauth_key [(UNSPEC_PACIASP "AARCH64_KEY_A") + (UNSPEC_PACIBSP "AARCH64_KEY_B") + (UNSPEC_PACIA1716 "AARCH64_KEY_A") + (UNSPEC_PACIB1716 "AARCH64_KEY_B") + (UNSPEC_AUTIASP "AARCH64_KEY_A") + (UNSPEC_AUTIBSP "AARCH64_KEY_B") + (UNSPEC_AUTIA1716 "AARCH64_KEY_A") + (UNSPEC_AUTIB1716 "AARCH64_KEY_B")]) ;; Pointer authentication HINT number for NOP space instructions using A Key. -(define_int_attr pauth_hint_num_a [(UNSPEC_PACISP "25") - (UNSPEC_AUTISP "29") - (UNSPEC_PACI1716 "8") - (UNSPEC_AUTI1716 "12")]) +(define_int_attr pauth_hint_num_a [(UNSPEC_PACIASP "25") + (UNSPEC_AUTIASP "29") + (UNSPEC_PACIA1716 "8") + (UNSPEC_AUTIA1716 "12")]) + +;; Pointer authentication HINT number for NOP space instructions using B Key. +(define_int_attr pauth_hint_num_b [(UNSPEC_PACIBSP "27") + (UNSPEC_AUTIBSP "31") + (UNSPEC_PACIB1716 "10") + (UNSPEC_AUTIB1716 "14")]) (define_int_attr perm_insn [(UNSPEC_ZIP1 "zip") (UNSPEC_ZIP2 "zip") (UNSPEC_TRN1 "trn") (UNSPEC_TRN2 "trn") diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 7fcfbaa67bb7fa6e5808c0469efc1fdc6c7cdcdf..202d5213c3c349525acb182d0b7f1c6fcbdadf6d 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -622,7 +622,8 @@ Objective-C and Objective-C++ Dialects}. -mlow-precision-recip-sqrt -mlow-precision-sqrt -mlow-precision-div @gol -mpc-relative-literal-loads @gol -msign-return-address=@var{scope} @gol --mbranch-protection=@var{none}|@var{standard}|@var{pac-ret}[+@var{leaf}] @gol +-mbranch-protection=@var{none}|@var{standard}|@var{pac-ret}[+@var{leaf} ++@var{b-key}] @gol -march=@var{name} -mcpu=@var{name} -mtune=@var{name} @gol -moverride=@var{string} -mverbose-cost-dump -mtrack-speculation} @@ -15222,16 +15223,19 @@ accessed using a single instruction and emitted after each function. This limits the maximum size of functions to 1MB. This is enabled by default for @option{-mcmodel=tiny}. -@item -mbranch-protection=@var{none}|@var{standard}|@var{pac-ret}[+@var{leaf}] +@item -mbranch-protection=@var{none}|@var{standard}|@var{pac-ret}[+@var{leaf} ++@var{b-key}] @opindex mbranch-protection Select the branch protection features to use. -@samp{none} is the default and turns off all types of branch protection. -@samp{standard} turns on all types of branch protection features. See -@samp{pac-ret} for how this affects return address-signing. -@samp{pac-ret[+@var{leaf}]} turns on return address signing by signing functions -that save the return address to memory (non-leaf functions will practically -always do this) using the a-key. The optional argument @samp{leaf} can be used -to extend the signing to include the leaf functions. +@samp{none} is the default and this turn off all types of branch protection. +@samp{standard} turns on all types of branch protection features to their +respective standard levels. +@samp{pac-ret[+@var{leaf}+@var{b-key}]} turns on return address signing with by +signing functions that save the return address to memory (non-leaf functions +will practically always do this) using the a-key. The optional argument +@samp{leaf} can be used to extend the signing to include the leaf functions. +The optional argument @samp{b-key} can be used to sign the functions with the +B-key instead of the A-key. @item -msve-vector-bits=@var{bits} @opindex msve-vector-bits diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c b/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c index 0140bee194f5a3ec53e794984c2f9b0e96bdbb63..0f52b91d0bb07e6695bde8e6540b19fa2774d17f 100644 --- a/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c +++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_1.c @@ -48,5 +48,5 @@ func4 (long offset, void *handler, int *ptr, int imm1, int imm2) return; } -/* { dg-final { scan-assembler-times "autiasp" 4 } } */ -/* { dg-final { scan-assembler-times "paciasp" 4 } } */ +/* { dg-final { scan-assembler-times "hint\t29 // autiasp" 4 } } */ +/* { dg-final { scan-assembler-times "hint\t25 // paciasp" 4 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_2.c b/gcc/testsuite/gcc.target/aarch64/return_address_sign_2.c index a4bc5b4533382d3d21085a763028576f72531ed7..d5d10aafa563b0a1f3bd0732ee5a45edd53a4d4c 100644 --- a/gcc/testsuite/gcc.target/aarch64/return_address_sign_2.c +++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_2.c @@ -14,5 +14,5 @@ func1 (int a, int b, int c) /* retaa */ } -/* { dg-final { scan-assembler-times "paciasp" 1 } } */ +/* { dg-final { scan-assembler-times "hint\t25 // paciasp" 1 } } */ /* { dg-final { scan-assembler-times "retaa" 1 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_ab_exception.cpp b/gcc/testsuite/gcc.target/aarch64/return_address_sign_ab_exception.cpp new file mode 100644 index 0000000000000000000000000000000000000000..41f0c47860c13fa689fb7c599321b44a09b35596 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_ab_exception.cpp @@ -0,0 +1,29 @@ +/* { dg-do run } */ +/* { dg-options "--save-temps" } */ + +__attribute__((target("branch-protection=pac-ret+leaf"))) +int foo_a () { + throw 22; +} + +__attribute__((target("branch-protection=pac-ret+leaf+b-key"))) +int foo_b () { + throw 22; +} + +int main (int argc, char** argv) { + try { + foo_a () + } catch (...) { + try { + foo_b (); + } catch (...) { + return 0; + } + } + return 1; +} + +/* { dg-final { scan-assembler-times "\t\thint 25" 1 } } */ +/* { dg-final { scan-assembler-times "\t\thint 27" 1 } } */ +/* { dg-final { scan-assembler-times "\t\t.cfi_b_key_frame" 1 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_1.c b/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_1.c new file mode 100644 index 0000000000000000000000000000000000000000..b2e70922b7fdd1c0921d686f98e1e173d8ad83e5 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_1.c @@ -0,0 +1,52 @@ +/* Testing return address signing where no combined instructions used. */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mbranch-protection=pac-ret+leaf+b-key" } */ +/* { dg-require-effective-target lp64 } */ + +int foo (int); + +/* sibcall only. */ +int __attribute__ ((target ("arch=armv8.3-a"))) +func1 (int a, int b) +{ + /* pacibsp */ + return foo (a + b); + /* autibsp */ +} + +/* non-leaf function with sibcall. */ +int __attribute__ ((target ("arch=armv8.3-a"))) +func2 (int a, int b) +{ + /* pacibsp */ + if (a < b) + return b; + + a = foo (b); + + return foo (a); + /* autibsp */ +} + +/* non-leaf function, legacy arch. */ +int __attribute__ ((target ("arch=armv8.2-a"))) +func3 (int a, int b, int c) +{ + /* pacibsp */ + return a + foo (b) + c; + /* autibsp */ +} + +/* eh_return. */ +void __attribute__ ((target ("arch=armv8.3-a"))) +func4 (long offset, void *handler, int *ptr, int imm1, int imm2) +{ + /* pacibsp */ + *ptr = imm1 + foo (imm1) + imm2; + __builtin_eh_return (offset, handler); + /* autibsp */ + return; +} + +/* { dg-final { scan-assembler-times "hint\t27 // pacibsp" 4 } } */ +/* { dg-final { scan-assembler-times "hint\t31 // autibsp" 4 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_2.c b/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_2.c new file mode 100644 index 0000000000000000000000000000000000000000..7ba2a36ebaab14e46bcc8e553a2c250c8fadf66f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_2.c @@ -0,0 +1,18 @@ +/* Testing return address signing where combined instructions used. */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mbranch-protection=pac-ret+leaf+b-key" } */ +/* { dg-require-effective-target lp64 } */ + +int foo (int); +int bar (int, int); + +int __attribute__ ((target ("arch=armv8.3-a"))) +func1 (int a, int b, int c) +{ + /* pacibsp */ + return a + foo (b) + c; + /* retab */ +} + +/* { dg-final { scan-assembler-times "hint\t27 // pacibsp" 1 } } */ +/* { dg-final { scan-assembler-times "retab" 1 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_3.c b/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_3.c new file mode 100644 index 0000000000000000000000000000000000000000..111a30e0bfd246ffa3c2765955cd6d3463a7a715 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_3.c @@ -0,0 +1,22 @@ +/* Testing the disable of return address signing. */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mbranch-protection=pac-ret+leaf+b-key" } */ +/* { dg-require-effective-target lp64 } */ + +int bar (int, int); + +int __attribute__ ((target ("arch=armv8.3-a, branch-protection=pac-ret+b-key"))) +func1_leaf (int a, int b, int c, int d) +{ + return a + b + c + d; +} + +int __attribute__ ((target ("arch=armv8.3-a, branch-protection=none"))) +func2_none (int a, int b, int c, int d) +{ + return c + bar (a, b) + d; +} + +/* { dg-final { scan-assembler-not "pacibsp" } } */ +/* { dg-final { scan-assembler-not "autibsp" } } */ +/* { dg-final { scan-assembler-not "retab" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_exception.cpp b/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_exception.cpp new file mode 100644 index 0000000000000000000000000000000000000000..44dcfee245e05c832f72cc58cf00ee6e726ed5b0 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_b_exception.cpp @@ -0,0 +1,17 @@ +/* { dg-do run } */ +/* { dg-options "-mbranch-protection=pac-ret+leaf+b-key"} */ + +int foo () { + throw 22; +} + +int main (int argc, char** argv) { + try { + foo() + } catch (...) { + return 0; + } + return 1; +} + +/* { dg-final { scan-assembler-times ".cfi_b_key_frame" 2 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/return_address_sign_builtin.c b/gcc/testsuite/gcc.target/aarch64/return_address_sign_builtin.c new file mode 100644 index 0000000000000000000000000000000000000000..f21064dda52f68c168147698265571cd85764712 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/return_address_sign_builtin.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-mbranch-protection=pac-ret+leaf+b-key" } */ + +/* The correct pauth instruction should be generated no matter the return + address signing key/scope specified in the options. */ + +int foo() { + /* { dg-final { scan-assembler-times "hint\t8 // pacia1716" 1 } } */ + __builtin_aarch64_pacia1716(0, 0); + /* { dg-final { scan-assembler-times "hint\t10 // pacib1716" 1 } } */ + __builtin_aarch64_pacib1716(0, 0); + /* { dg-final { scan-assembler-times "hint\t12 // autia1716" 1 } } */ + __builtin_aarch64_autia1716(0, 0); + /* { dg-final { scan-assembler-times "hint\t14 // autib1716" 1 } } */ + __builtin_aarch64_autib1716(0, 0); +} diff --git a/libgcc/config/aarch64/aarch64-unwind.h b/libgcc/config/aarch64/aarch64-unwind.h index ff05226f49cba67cf909c1edac8bd8c25f6f71d8..5e7bf64e4a7983ff38c7456bc918a016a21e5bcd 100644 --- a/libgcc/config/aarch64/aarch64-unwind.h +++ b/libgcc/config/aarch64/aarch64-unwind.h @@ -35,6 +35,23 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define MD_FROB_UPDATE_CONTEXT(context, fs) \ aarch64_frob_update_context (context, fs) +static inline int +aarch64_cie_signed_with_b_key (struct _Unwind_Context *context) +{ + const struct dwarf_fde *fde = _Unwind_Find_FDE (context->bases.func, + &context->bases); + if (fde != NULL) + { + const struct dwarf_cie *cie = get_cie (fde); + if (cie != NULL) + { + char *aug_str = cie->augmentation; + return strchr (aug_str, 'B') == NULL ? 0 : 1; + } + } + return 0; +} + /* Do AArch64 private extraction on ADDR based on context info CONTEXT and unwind frame info FS. If ADDR is signed, we do address authentication on it using CFA of current frame. */ @@ -43,9 +60,11 @@ static inline void * aarch64_post_extract_frame_addr (struct _Unwind_Context *context, _Unwind_FrameState *fs, void *addr) { - if (fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset & 0x1) + if (context->flags & RA_SIGNED_BIT) { _Unwind_Word salt = (_Unwind_Word) context->cfa; + if (aarch64_cie_signed_with_b_key (context) != 0) + return __builtin_aarch64_autib1716 (addr, salt); return __builtin_aarch64_autia1716 (addr, salt); } else @@ -62,9 +81,14 @@ aarch64_post_frob_eh_handler_addr (struct _Unwind_Context *current, ATTRIBUTE_UNUSED, void *handler_addr) { - if (current->flags & RA_A_SIGNED_BIT) - return __builtin_aarch64_pacia1716 (handler_addr, + if (current->flags & RA_SIGNED_BIT) + { + if (aarch64_cie_signed_with_b_key (current)) + return __builtin_aarch64_pacib1716 (handler_addr, + (_Unwind_Word) current->cfa); + return __builtin_aarch64_pacia1716 (handler_addr, (_Unwind_Word) current->cfa); + } else return handler_addr; } @@ -79,7 +103,7 @@ aarch64_frob_update_context (struct _Unwind_Context *context, { if (fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset & 0x1) /* The flag is used for re-authenticating EH handler's address. */ - context->flags |= RA_A_SIGNED_BIT; + context->flags |= RA_SIGNED_BIT; return; } diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c index 0d52b7a4cefb35efc744b9a2c374460ce37ab470..9b454270ffd4cf188ab18c6b2261343166e64331 100644 --- a/libgcc/unwind-dw2-fde.c +++ b/libgcc/unwind-dw2-fde.c @@ -334,6 +334,9 @@ get_cie_encoding (const struct dwarf_cie *cie) /* LSDA encoding. */ else if (*aug == 'L') p++; + /* aarch64 b-key pointer authentication. */ + else if (*aug == 'B') + p++; /* Otherwise end of string, or unknown augmentation. */ else return DW_EH_PE_absptr; diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c index de9310f524fc1f5103b6df2e024c50454a53a1c0..f2b1cfd246197977837ee4ee5311781df1bf5a05 100644 --- a/libgcc/unwind-dw2.c +++ b/libgcc/unwind-dw2.c @@ -136,8 +136,9 @@ struct _Unwind_Context #define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1) /* Context which has version/args_size/by_value fields. */ #define EXTENDED_CONTEXT_BIT ((~(_Unwind_Word) 0 >> 2) + 1) - /* Bit reserved on AArch64, return address has been signed with A key. */ -#define RA_A_SIGNED_BIT ((~(_Unwind_Word) 0 >> 3) + 1) + /* Bit reserved on AArch64, return address has been signed with A or B + key. */ +#define RA_SIGNED_BIT ((~(_Unwind_Word) 0 >> 3) + 1) _Unwind_Word flags; /* 0 for now, can be increased when further fields are added to struct _Unwind_Context. */ @@ -502,6 +503,11 @@ extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context, fs->signal_frame = 1; aug += 1; } + /* aarch64 B-key pointer authentication. */ + else if (aug[0] == 'B') + { + aug += 1; + } /* Otherwise we have an unknown augmentation string. Bail unless we saw a 'z' prefix. */