From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2098) id D6F7A3858D32; Mon, 23 Jan 2023 11:12:47 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D6F7A3858D32 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1674472367; bh=AF1Aufic9Ky0oxoun+OEA1Hf05OHtS32PXXcVwreb/U=; h=From:To:Subject:Date:From; b=m22Ilfg19F06yqLeQwDVsWLZwKemumlEYl5Hth+227FiYMh3h0unwnzDMLAO46ACM m7a1MRPgzsuDbG/Xq2SqXHcSyH102mSWQv86n1wOFAE8emNIy/NCIkvEkGgTD2X9Ng K0Gw2t7xMgosdHf8EzsUVt97rstEGLcKJWRgkI1c= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: SRINATH PARVATHANENI To: gcc-cvs@gcc.gnu.org Subject: [gcc r13-5303] arm: Add support for dwarf debug directives and pseudo hard-register for PAC feature. X-Act-Checkin: gcc X-Git-Author: Srinath Parvathaneni X-Git-Refname: refs/heads/master X-Git-Oldrev: 3a0dd2cc28ee2833dc5bf1d4fb6d746a8c55ca4d X-Git-Newrev: 273874e925a544d96b8a9999d4c870c1f5191eeb Message-Id: <20230123111247.D6F7A3858D32@sourceware.org> Date: Mon, 23 Jan 2023 11:12:47 +0000 (GMT) List-Id: https://gcc.gnu.org/g:273874e925a544d96b8a9999d4c870c1f5191eeb commit r13-5303-g273874e925a544d96b8a9999d4c870c1f5191eeb Author: Srinath Parvathaneni Date: Mon Jan 23 11:07:29 2023 +0000 arm: Add support for dwarf debug directives and pseudo hard-register for PAC feature. This patch teaches the DWARF support in gcc about RA_AUTH_CODE pseudo hard-register and also updates the ".save", ".cfi_register", ".cfi_offset", ".cfi_restore" directives accordingly. This patch also adds support to emit ".pacspval" directive when "pac ip, lr, sp" instruction in generated in the assembly. RA_AUTH_CODE register number is 107 and it's dwarf register number is 143. Applying this patch on top of PACBTI series posted here https://gcc.gnu.org/pipermail/gcc-patches/2022-August/599658.html and when compiling the following test.c with "-march=armv8.1-m.main+mve+pacbti -mbranch-protection=pac-ret -mthumb -mfloat-abi=hard fasynchronous-unwind-tables -g -O0 -S" command line options, the assembly output after this patch looks like below: $cat test.c void fun1(int a); void fun(int a,...) { fun1(a); } int main() { fun (10); return 0; } $ arm-none-eabi-gcc -march=armv8.1-m.main+mve+pacbti -mbranch-protection=pac-ret -mthumb -mfloat-abi=hard -fasynchronous-unwind-tables -g -O0 -S test.s Assembly output: ... fun: ... .pacspval pac ip, lr, sp .cfi_register 143, 12 push {r3, r7, ip, lr} .save {r3, r7, ra_auth_code, lr} ... .cfi_offset 143, -24 ... .cfi_restore 143 ... aut ip, lr, sp bx lr ... main: ... .pacspval pac ip, lr, sp .cfi_register 143, 12 push {r3, r7, ip, lr} .save {r3, r7, ra_auth_code, lr} ... .cfi_offset 143, -8 ... .cfi_restore 143 ... aut ip, lr, sp bx lr ... gcc/ChangeLog: 2023-01-11 Srinath Parvathaneni * config/arm/aout.h (ra_auth_code): Add entry in enum. * config/arm/arm.cc (emit_multi_reg_push): Add RA_AUTH_CODE register to dwarf frame expression. (arm_emit_multi_reg_pop): Restore RA_AUTH_CODE register. (arm_expand_prologue): Update frame related information and reg notes for pac/pacbit insn. (arm_regno_class): Check for pac pseudo reigster. (arm_dbx_register_number): Assign ra_auth_code register number in dwarf. (arm_init_machine_status): Set pacspval_needed to zero. (arm_debugger_regno): Check for PAC register. (arm_unwind_emit_sequence): Print .save directive with ra_auth_code register. (arm_unwind_emit_set): Add entry for IP_REGNUM in switch case. (arm_unwind_emit): Update REG_CFA_REGISTER case._ * config/arm/arm.h (FIRST_PSEUDO_REGISTER): Modify. (DWARF_PAC_REGNUM): Define. (IS_PAC_REGNUM): Likewise. (enum reg_class): Add PAC_REG entry. (machine_function): Add pacbti_needed state to structure. * config/arm/arm.md (RA_AUTH_CODE): Define. gcc/testsuite/ChangeLog: 2023-01-11 Srinath Parvathaneni * g++.target/arm/pac-1.C: New test. * gcc.target/arm/pac-15.c: Likewise. Diff: --- gcc/config/arm/aout.h | 3 +- gcc/config/arm/arm.cc | 86 +++++++++++++++++++++++++++++------ gcc/config/arm/arm.h | 24 +++++++--- gcc/config/arm/arm.md | 1 + gcc/testsuite/g++.target/arm/pac-1.C | 35 ++++++++++++++ gcc/testsuite/gcc.target/arm/pac-15.c | 32 +++++++++++++ 6 files changed, 160 insertions(+), 21 deletions(-) diff --git a/gcc/config/arm/aout.h b/gcc/config/arm/aout.h index b8f8eb084c0..57c3b9b7b8b 100644 --- a/gcc/config/arm/aout.h +++ b/gcc/config/arm/aout.h @@ -74,7 +74,8 @@ "wr8", "wr9", "wr10", "wr11", \ "wr12", "wr13", "wr14", "wr15", \ "wcgr0", "wcgr1", "wcgr2", "wcgr3", \ - "cc", "vfpcc", "sfp", "afp", "apsrq", "apsrge", "p0" \ + "cc", "vfpcc", "sfp", "afp", "apsrq", "apsrge", "p0", \ + "ra_auth_code" \ } #endif diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc index fb52048860a..efc48349dd3 100644 --- a/gcc/config/arm/arm.cc +++ b/gcc/config/arm/arm.cc @@ -22272,7 +22272,33 @@ emit_multi_reg_push (unsigned long mask, unsigned long dwarf_regs_mask) { if (mask & (1 << i)) { - reg = gen_rtx_REG (SImode, i); + /* NOTE: Dwarf code emitter handle reg-reg copies correctly and in the + following example reg-reg copy of SP to IP register is handled + through .cfi_def_cfa_register directive and the .cfi_offset + directive for IP register is skipped by dwarf code emitter. + Example: + mov ip, sp + .cfi_def_cfa_register 12 + push {fp, ip, lr, pc} + .cfi_offset 11, -16 + .cfi_offset 13, -12 + .cfi_offset 14, -8 + + Where as Arm-specific .save directive handling is different to that + of dwarf code emitter and it doesn't consider reg-reg copies while + updating the register list. When PACBTI is enabled we manually + updated the .save directive register list to use "ra_auth_code" + (pseduo register 143) instead of IP register as shown in following + pseduo code. + Example: + pacbti ip, lr, sp + .cfi_register 143, 12 + push {r3, r7, ip, lr} + .save {r3, r7, ra_auth_code, lr} + */ + rtx dwarf_reg = reg = gen_rtx_REG (SImode, i); + if (arm_current_function_pac_enabled_p () && i == IP_REGNUM) + dwarf_reg = gen_rtx_REG (SImode, RA_AUTH_CODE); XVECEXP (par, 0, 0) = gen_rtx_SET (gen_frame_mem @@ -22290,7 +22316,7 @@ emit_multi_reg_push (unsigned long mask, unsigned long dwarf_regs_mask) if (dwarf_regs_mask & (1 << i)) { tmp = gen_rtx_SET (gen_frame_mem (SImode, stack_pointer_rtx), - reg); + dwarf_reg); RTX_FRAME_RELATED_P (tmp) = 1; XVECEXP (dwarf, 0, dwarf_par_index++) = tmp; } @@ -22303,7 +22329,9 @@ emit_multi_reg_push (unsigned long mask, unsigned long dwarf_regs_mask) { if (mask & (1 << i)) { - reg = gen_rtx_REG (SImode, i); + rtx dwarf_reg = reg = gen_rtx_REG (SImode, i); + if (arm_current_function_pac_enabled_p () && i == IP_REGNUM) + dwarf_reg = gen_rtx_REG (SImode, RA_AUTH_CODE); XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg); @@ -22314,7 +22342,7 @@ emit_multi_reg_push (unsigned long mask, unsigned long dwarf_regs_mask) (SImode, plus_constant (Pmode, stack_pointer_rtx, 4 * j)), - reg); + dwarf_reg); RTX_FRAME_RELATED_P (tmp) = 1; XVECEXP (dwarf, 0, dwarf_par_index++) = tmp; } @@ -22399,7 +22427,9 @@ arm_emit_multi_reg_pop (unsigned long saved_regs_mask) for (j = 0, i = 0; j < num_regs; i++) if (saved_regs_mask & (1 << i)) { - reg = gen_rtx_REG (SImode, i); + rtx dwarf_reg = reg = gen_rtx_REG (SImode, i); + if (arm_current_function_pac_enabled_p () && i == IP_REGNUM) + dwarf_reg = gen_rtx_REG (SImode, RA_AUTH_CODE); if ((num_regs == 1) && emit_update && !return_in_pc) { /* Emit single load with writeback. */ @@ -22407,7 +22437,8 @@ arm_emit_multi_reg_pop (unsigned long saved_regs_mask) gen_rtx_POST_INC (Pmode, stack_pointer_rtx)); tmp = emit_insn (gen_rtx_SET (reg, tmp)); - REG_NOTES (tmp) = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf); + REG_NOTES (tmp) = alloc_reg_note (REG_CFA_RESTORE, dwarf_reg, + dwarf); return; } @@ -22421,7 +22452,7 @@ arm_emit_multi_reg_pop (unsigned long saved_regs_mask) /* We need to maintain a sequence for DWARF info too. As dwarf info should not have PC, skip PC. */ if (i != PC_REGNUM) - dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf); + dwarf = alloc_reg_note (REG_CFA_RESTORE, dwarf_reg, dwarf); j++; } @@ -23603,6 +23634,8 @@ arm_expand_prologue (void) -fp_offset)); RTX_FRAME_RELATED_P (insn) = 1; add_reg_note (insn, REG_FRAME_RELATED_EXPR, dwarf); + if (arm_current_function_pac_enabled_p ()) + cfun->machine->pacspval_needed = 1; } else { @@ -23638,6 +23671,8 @@ arm_expand_prologue (void) RTX_FRAME_RELATED_P (insn) = 1; fp_offset = args_to_push; args_to_push = 0; + if (arm_current_function_pac_enabled_p ()) + cfun->machine->pacspval_needed = 1; } } @@ -23647,9 +23682,13 @@ arm_expand_prologue (void) one will be added before the push of the clobbered IP (if necessary) by the bti pass. */ if (aarch_bti_enabled () && !clobber_ip) - emit_insn (gen_pacbti_nop ()); + insn = emit_insn (gen_pacbti_nop ()); else - emit_insn (gen_pac_nop ()); + insn = emit_insn (gen_pac_nop ()); + + rtx dwarf = gen_rtx_SET (ip_rtx, gen_rtx_REG (SImode, RA_AUTH_CODE)); + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_REGISTER, dwarf); } if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM) @@ -25731,6 +25770,9 @@ arm_regno_class (int regno) if (IS_VPR_REGNUM (regno)) return VPR_REG; + if (IS_PAC_REGNUM (regno)) + return PAC_REG; + if (TARGET_THUMB1) { if (regno == STACK_POINTER_REGNUM) @@ -26891,6 +26933,7 @@ arm_init_machine_status (void) machine->func_type = ARM_FT_UNKNOWN; #endif machine->static_chain_stack_bytes = -1; + machine->pacspval_needed = 0; return machine; } @@ -29700,6 +29743,9 @@ arm_debugger_regno (unsigned int regno) if (IS_IWMMXT_REGNUM (regno)) return 112 + regno - FIRST_IWMMXT_REGNUM; + if (IS_PAC_REGNUM (regno)) + return DWARF_PAC_REGNUM; + return DWARF_FRAME_REGISTERS; } @@ -29793,7 +29839,7 @@ arm_unwind_emit_sequence (FILE * out_file, rtx p) gcc_assert (nregs); reg = REGNO (SET_SRC (XVECEXP (p, 0, 1))); - if (reg < 16) + if (reg < 16 || IS_PAC_REGNUM (reg)) { /* For -Os dummy registers can be pushed at the beginning to avoid separate stack pointer adjustment. */ @@ -29850,6 +29896,8 @@ arm_unwind_emit_sequence (FILE * out_file, rtx p) double precision register names. */ if (IS_VFP_REGNUM (reg)) asm_fprintf (out_file, "d%d", (reg - FIRST_VFP_REGNUM) / 2); + else if (IS_PAC_REGNUM (reg)) + asm_fprintf (asm_out_file, "ra_auth_code"); else asm_fprintf (out_file, "%r", reg); @@ -29944,7 +29992,7 @@ arm_unwind_emit_set (FILE * out_file, rtx p) /* Move from sp to reg. */ asm_fprintf (out_file, "\t.movsp %r\n", REGNO (e0)); } - else if (GET_CODE (e1) == PLUS + else if (GET_CODE (e1) == PLUS && REG_P (XEXP (e1, 0)) && REGNO (XEXP (e1, 0)) == SP_REGNUM && CONST_INT_P (XEXP (e1, 1))) @@ -29953,6 +30001,11 @@ arm_unwind_emit_set (FILE * out_file, rtx p) asm_fprintf (out_file, "\t.movsp %r, #%d\n", REGNO (e0), (int)INTVAL(XEXP (e1, 1))); } + else if (REGNO (e0) == IP_REGNUM && arm_current_function_pac_enabled_p ()) + { + if (cfun->machine->pacspval_needed) + asm_fprintf (out_file, "\t.pacspval\n"); + } else abort (); break; @@ -30007,10 +30060,15 @@ arm_unwind_emit (FILE * out_file, rtx_insn *insn) src = SET_SRC (pat); dest = SET_DEST (pat); - gcc_assert (src == stack_pointer_rtx); + gcc_assert (src == stack_pointer_rtx + || IS_PAC_REGNUM (REGNO (src))); reg = REGNO (dest); - asm_fprintf (out_file, "\t.unwind_raw 0, 0x%x @ vsp = r%d\n", - reg + 0x90, reg); + + if (IS_PAC_REGNUM (REGNO (src))) + arm_unwind_emit_set (out_file, PATTERN (insn)); + else + asm_fprintf (out_file, "\t.unwind_raw 0, 0x%x @ vsp = r%d\n", + reg + 0x90, reg); } handled_one = true; break; diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 97e2fda7464..632728371d5 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -816,7 +816,8 @@ extern const int arm_arch_cde_coproc_bits[]; s16-s31 S VFP variable (aka d8-d15). vfpcc Not a real register. Represents the VFP condition code flags. - vpr Used to represent MVE VPR predication. */ + vpr Used to represent MVE VPR predication. + ra_auth_code Pseudo register to save PAC. */ /* The stack backtrace structure is as follows: fp points to here: | save code pointer | [fp] @@ -857,7 +858,7 @@ extern const int arm_arch_cde_coproc_bits[]; 1,1,1,1,1,1,1,1, \ 1,1,1,1, \ /* Specials. */ \ - 1,1,1,1,1,1,1 \ + 1,1,1,1,1,1,1,1 \ } /* 1 for registers not available across function calls. @@ -887,7 +888,7 @@ extern const int arm_arch_cde_coproc_bits[]; 1,1,1,1,1,1,1,1, \ 1,1,1,1, \ /* Specials. */ \ - 1,1,1,1,1,1,1 \ + 1,1,1,1,1,1,1,1 \ } #ifndef SUBTARGET_CONDITIONAL_REGISTER_USAGE @@ -1063,10 +1064,12 @@ extern const int arm_arch_cde_coproc_bits[]; && (LAST_VFP_REGNUM - (REGNUM) >= 2 * (N) - 1)) /* The number of hard registers is 16 ARM + 1 CC + 1 SFP + 1 AFP - + 1 APSRQ + 1 APSRGE + 1 VPR. */ + + 1 APSRQ + 1 APSRGE + 1 VPR + 1 Pseudo register to save PAC. */ /* Intel Wireless MMX Technology registers add 16 + 4 more. */ /* VFP (VFP3) adds 32 (64) + 1 VFPCC. */ -#define FIRST_PSEUDO_REGISTER 107 +#define FIRST_PSEUDO_REGISTER 108 + +#define DWARF_PAC_REGNUM 143 #define DEBUGGER_REGNO(REGNO) arm_debugger_regno (REGNO) @@ -1253,12 +1256,15 @@ extern int arm_regs_in_sequence[]; CC_REGNUM, VFPCC_REGNUM, \ FRAME_POINTER_REGNUM, ARG_POINTER_REGNUM, \ SP_REGNUM, PC_REGNUM, APSRQ_REGNUM, \ - APSRGE_REGNUM, VPR_REGNUM \ + APSRGE_REGNUM, VPR_REGNUM, RA_AUTH_CODE \ } #define IS_VPR_REGNUM(REGNUM) \ ((REGNUM) == VPR_REGNUM) +#define IS_PAC_REGNUM(REGNUM) \ + ((REGNUM) == RA_AUTH_CODE) + /* Use different register alloc ordering for Thumb. */ #define ADJUST_REG_ALLOC_ORDER arm_order_regs_for_local_alloc () @@ -1297,6 +1303,7 @@ enum reg_class SFP_REG, AFP_REG, VPR_REG, + PAC_REG, GENERAL_AND_VPR_REGS, ALL_REGS, LIM_REG_CLASSES @@ -1327,6 +1334,7 @@ enum reg_class "SFP_REG", \ "AFP_REG", \ "VPR_REG", \ + "PAC_REG", \ "GENERAL_AND_VPR_REGS", \ "ALL_REGS" \ } @@ -1356,6 +1364,7 @@ enum reg_class { 0x00000000, 0x00000000, 0x00000000, 0x00000040 }, /* SFP_REG */ \ { 0x00000000, 0x00000000, 0x00000000, 0x00000080 }, /* AFP_REG */ \ { 0x00000000, 0x00000000, 0x00000000, 0x00000400 }, /* VPR_REG. */ \ + { 0x00000000, 0x00000000, 0x00000000, 0x00000800 }, /* PAC_REG. */ \ { 0x00005FFF, 0x00000000, 0x00000000, 0x00000400 }, /* GENERAL_AND_VPR_REGS. */ \ { 0xFFFF7FFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000040F } /* ALL_REGS. */ \ } @@ -1621,6 +1630,9 @@ typedef struct GTY(()) machine_function /* The number of bytes used to store the static chain register on the stack, above the stack frame. */ int static_chain_stack_bytes; + /* Set to 1 when pointer authentication operation uses value of SP other + than the incoming stack pointer value. */ + int pacspval_needed; } machine_function; #endif diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 3b95f47cc0a..cbfc4543531 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -42,6 +42,7 @@ (APSRQ_REGNUM 104) ; Q bit pseudo register (APSRGE_REGNUM 105) ; GE bits pseudo register (VPR_REGNUM 106) ; Vector Predication Register - MVE register. + (RA_AUTH_CODE 107) ; Pseudo register to save PAC. ] ) ;; 3rd operand to select_dominance_cc_mode diff --git a/gcc/testsuite/g++.target/arm/pac-1.C b/gcc/testsuite/g++.target/arm/pac-1.C new file mode 100644 index 00000000000..f671a27b048 --- /dev/null +++ b/gcc/testsuite/g++.target/arm/pac-1.C @@ -0,0 +1,35 @@ +/* Check that GCC does .save and .cfi_offset directives with RA_AUTH_CODE pseudo hard-register. */ +/* { dg-do compile } */ +/* { dg-skip-if "avoid conflicting multilib options" { *-*-* } { "-marm" "-mcpu=*" } } */ +/* { dg-options "-march=armv8.1-m.main+mve+pacbti -mbranch-protection=pac-ret -mthumb -mfloat-abi=hard -g -O0" } */ + +__attribute__((noinline)) void +fn1 (int a, int b, int c) +{ + if (a != b + c) + __builtin_abort (); + else + throw b+c; +} + +int main () +{ + int a = 120; + try + { + fn1 (a, 40, 80); + } + catch (int x) + { + if (x != a) + __builtin_abort (); + else + return 0; + } +} + +/* { dg-final { scan-assembler-times "pac ip, lr, sp" 2 } } */ +/* { dg-final { scan-assembler-times "\.cfi_register 143, 12" 2 } } */ +/* { dg-final { scan-assembler-times "\.save {r7, ra_auth_code, lr}" 1 } } */ +/* { dg-final { scan-assembler-times "\.cfi_offset 143, -8" 2 } } */ +/* { dg-final { scan-assembler-times "\.save {r4, r7, ra_auth_code, lr}" 1 } } */ diff --git a/gcc/testsuite/gcc.target/arm/pac-15.c b/gcc/testsuite/gcc.target/arm/pac-15.c new file mode 100644 index 00000000000..e1054902955 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/pac-15.c @@ -0,0 +1,32 @@ +/* Check that GCC does .save and .cfi_offset directives with RA_AUTH_CODE pseudo hard-register. */ +/* { dg-do compile } */ +/* { dg-require-effective-target mbranch_protection_ok } */ +/* { dg-skip-if "avoid conflicting multilib options" { *-*-* } { "-marm" "-mcpu=*" } } */ +/* { dg-options "-march=armv8.1-m.main+mve+pacbti -mbranch-protection=pac-ret -mthumb -mfloat-abi=hard -fasynchronous-unwind-tables -g -O0" } */ + +#include "stdio.h" + +__attribute__((noinline)) int +fn1 (int a) +{ + const char *fmt = "branch-protection"; + int fun1(int x,const char *fmt,int c,int d) + { + printf("string = %s\n",fmt); + return x+c+d; + } + return fun1(a,fmt,10,10); +} + +int main (void) +{ + return fn1 (40); +} + +/* { dg-final { scan-assembler-times "\.pacspval" 1 } } */ +/* { dg-final { scan-assembler-times "pac ip, lr, sp" 3 } } */ +/* { dg-final { scan-assembler-times "\.cfi_register 143, 12" 3 } } */ +/* { dg-final { scan-assembler-times "\.save {r7, ra_auth_code, lr}" 2 } } */ +/* { dg-final { scan-assembler-times "\.cfi_offset 143, -8" 2 } } */ +/* { dg-final { scan-assembler-times "\.save {r3, r7, ra_auth_code, lr}" 1 } } */ +/* { dg-final { scan-assembler-times "\.cfi_offset 143, -12" 1 } } */