On 19/08/2022 11:04, Srinath Parvathaneni via Gcc-patches wrote:
Hello,

This patch teaches the DWARF support in gcc about RA_AUTH_CODE pseudo 
hard-register and also
.save {ra_auth_code} and .cfi_offset ra_auth_code <offset> dwarf directives for 
the PAC feature
in Armv8.1-M architecture.

RA_AUTH_CODE register number is 107 and it's dwarf register number is 143.

When compiled with " -march=armv8.1-m.main -mbranch-protection=pac-ret+leaf+bti 
-mthumb
-mfloat-abi=soft -fasynchronous-unwind-tables -g -O2 -S" command line options, 
the assembly
output after this patch looks like below:

         ...
         .cfi_startproc
         pacbti  ip, lr, sp
         movs    r1, #40
         push    {ip, lr}
         .save {ra_auth_code, lr}
         .cfi_def_cfa_offset 8
         .cfi_offset 143, -8
         .cfi_offset 14, -4
         ...
         pop     {ip, lr}
         .cfi_restore 14
         .cfi_restore 143
         .cfi_def_cfa_offset 0
         movs    r0, #0
         aut     ip, lr, sp
         bx      lr
         .cfi_endproc
         ...

Regression tested on arm-none-eabi target and found no regressions.

Ok for master?

Regards,
Srinath.

gcc/ChangeLog:

2022-08-17  Srinath Parvathaneni  <srinath.parvathan...@arm.com>

         * config/arm/aout.h (ra_auth_code): Add to 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): Mark as frame related insn.
         (arm_regno_class): Check for pac pseudo reigster.
         (arm_dbx_register_number): Assign ra_auth_code register number in 
dwarf.
         (arm_unwind_emit_sequence): Print .save directive with ra_auth_code
         register.
         (arm_conditional_register_usage): Mark ra_auth_code in fixed reigsters.
         * config/arm/arm.h (FIRST_PSEUDO_REGISTER): Modify.
         (IS_PAC_Pseudo_REGNUM): Define.
         (enum reg_class): Add PAC_REG entry.
         * config/arm/arm.md (RA_AUTH_CODE): Define.

gcc/testsuite/ChangeLog:

2022-08-17  Srinath Parvathaneni  <srinath.parvathan...@arm.com>

         * g++.target/arm/pac-1.C: New test.
         * gcc.target/arm/pac-9.c: Likewise.

The general boiler-plate to add the RA register is OK, but the code that tweaks the generation of the push instructions is fixing the wrong problem. The dwarf code already knows how to to track reg->reg copies and put out the right frame information, but this isn't working because you've not augmented the PAC instruction correctly. What you need is a frame-related augmentation to that and that essentially does

        (set (IP_REGNUM) (RA_AUTH_CODE))

The generic dwarf code should then handle all the rest for emitting CFI directives.

The code in arm_unwind_emit_sequence (and technically in arm_unwind_emit_set as well, but we probably never reach that code as of today) then needs updating to handle the special cases when IP appears in the list of registers and PAC is enabled. That's a bit of a hack, but I can't immediately think of a better way of handling it.

R.


###############     Attachment also inlined for ease of reply    ###############


diff --git a/gcc/config/arm/aout.h b/gcc/config/arm/aout.h
index 
b918ad3782fbee82320febb8b6e72ad615780261..ffeed45a678f17c63d5b42c21f020ca416cbf23f
 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.h b/gcc/config/arm/arm.h
index 
3495ab857eac38ecdf37e55f1d201b1c35cbde0b..c77777067819f6785e44d30d8e5365505ab98682
 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,10 @@ 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 DBX_REGISTER_NUMBER(REGNO) arm_dbx_register_number (REGNO) @@ -1253,12 +1254,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_Pseudo_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 +1301,7 @@ enum reg_class
    SFP_REG,
    AFP_REG,
    VPR_REG,
+  PAC_REG,
    GENERAL_AND_VPR_REGS,
    ALL_REGS,
    LIM_REG_CLASSES
@@ -1327,6 +1332,7 @@ enum reg_class
    "SFP_REG",                \
    "AFP_REG",                \
    "VPR_REG",                \
+  "PAC_REG",         \
    "GENERAL_AND_VPR_REGS", \
    "ALL_REGS"                \
  }
@@ -1356,6 +1362,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.  */        
\
  }
diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc
index 
de5a679c92a4bf253a15a1ab9cd0ae99e7cd62ec..c1de53882c9db897cadffc37353ec3e2ff11b657
 100644
--- a/gcc/config/arm/arm.cc
+++ b/gcc/config/arm/arm.cc
@@ -22148,7 +22148,9 @@ emit_multi_reg_push (unsigned long mask, unsigned long 
dwarf_regs_mask)
      {
        if (mask & (1 << i))
        {
-         reg = gen_rtx_REG (SImode, i);
+         rtx reg1 = reg = gen_rtx_REG (SImode, i);
+         if (arm_current_function_pac_enabled_p () && i == IP_REGNUM)
+           reg1 = gen_rtx_REG (SImode, RA_AUTH_CODE);
XVECEXP (par, 0, 0)
            = gen_rtx_SET (gen_frame_mem
@@ -22165,8 +22167,12 @@ emit_multi_reg_push (unsigned long mask, unsigned long 
dwarf_regs_mask)
if (dwarf_regs_mask & (1 << i))
            {
+             /* Only the first register in the multi push instruction is stored
+                to frame memory here.
+               Eg: push {r7 ,r8, ip, lr}
+               Only r7 is stored to frame memory here.  */
              tmp = gen_rtx_SET (gen_frame_mem (SImode, stack_pointer_rtx),
-                                reg);
+                                reg1);
              RTX_FRAME_RELATED_P (tmp) = 1;
              XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
            }
@@ -22179,18 +22185,25 @@ emit_multi_reg_push (unsigned long mask, unsigned 
long dwarf_regs_mask)
      {
        if (mask & (1 << i))
        {
-         reg = gen_rtx_REG (SImode, i);
+         rtx reg1 = reg = gen_rtx_REG (SImode, i);
+         if (arm_current_function_pac_enabled_p () && i == IP_REGNUM)
+           reg1 = gen_rtx_REG (SImode, RA_AUTH_CODE);
XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg); if (dwarf_regs_mask & (1 << i))
            {
+             /* Except the first register in the multi push instruction all the
+                remaining registers are stored to frame memory here.
+                Eg: push {r7, r8, ip, lr}
+                r8, ip (ra_auth_code in case PACBTI enabled) and lr registers
+                are stored to frame memory here.  */
              tmp
                = gen_rtx_SET (gen_frame_mem
                               (SImode,
                                plus_constant (Pmode, stack_pointer_rtx,
                                               4 * j)),
-                              reg);
+                              reg1);
              RTX_FRAME_RELATED_P (tmp) = 1;
              XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
            }
@@ -22275,7 +22288,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 reg1 = reg = gen_rtx_REG (SImode, i);
+       if (arm_current_function_pac_enabled_p () && i == IP_REGNUM)
+         reg1 = gen_rtx_REG (SImode, RA_AUTH_CODE);
          if ((num_regs == 1) && emit_update && !return_in_pc)
            {
              /* Emit single load with writeback.  */
@@ -22283,7 +22298,7 @@ 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, reg1, dwarf);
              return;
            }
@@ -22297,7 +22312,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, reg1, dwarf);
j++;
        }
@@ -25592,6 +25607,9 @@ arm_regno_class (int regno)
    if (IS_VPR_REGNUM (regno))
      return VPR_REG;
+ if (IS_PAC_Pseudo_REGNUM (regno))
+    return PAC_REG;
+
    if (TARGET_THUMB1)
      {
        if (regno == STACK_POINTER_REGNUM)
@@ -29563,6 +29581,9 @@ arm_dbx_register_number (unsigned int regno)
    if (IS_IWMMXT_REGNUM (regno))
      return 112 + regno - FIRST_IWMMXT_REGNUM;
+ if (IS_PAC_Pseudo_REGNUM (regno))
+    return 143;
+
    return DWARF_FRAME_REGISTERS;
  }
@@ -29656,7 +29677,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_Pseudo_REGNUM (reg))
      {
        /* For -Os dummy registers can be pushed at the beginning to
         avoid separate stack pointer adjustment.  */
@@ -29713,6 +29734,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_Pseudo_REGNUM (reg))
+       asm_fprintf (asm_out_file, "ra_auth_code");
        else
        asm_fprintf (out_file, "%r", reg);
@@ -30580,6 +30603,9 @@ arm_conditional_register_usage (void)
        global_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1;
      }
+ if (TARGET_HAVE_PACBTI)
+    fixed_regs[RA_AUTH_CODE] = 0;
+
    /* The Q and GE bits are only accessed via special ACLE patterns.  */
    CLEAR_HARD_REG_BIT (operand_reg_set, APSRQ_REGNUM);
    CLEAR_HARD_REG_BIT (operand_reg_set, APSRGE_REGNUM);
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 
90c8c1d66f57e8cd2eca4ef63f2100c04c5c5982..96079e7d760823af46b86978e3d7dd2a0ba5ed29
 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 
0000000000000000000000000000000000000000..b447213ab4e1b72cacd483efece077fbbca3a608
--- /dev/null
+++ b/gcc/testsuite/g++.target/arm/pac-1.C
@@ -0,0 +1,33 @@
+/* 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 -mbranch-protection=pac-ret+leaf+bti -mthumb 
-mfloat-abi=soft --save-temps -g" } */
+
+__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 "\.save \{r7, ra_auth_code, lr\}" } } */
+/* { dg-final { scan-assembler "\.save \{r4, r7, ra_auth_code, lr\}" } } */
+/* { dg-final { scan-assembler "\.cfi_offset 143, \-8" } } */
diff --git a/gcc/testsuite/gcc.target/arm/pac-9.c 
b/gcc/testsuite/gcc.target/arm/pac-9.c
new file mode 100644
index 
0000000000000000000000000000000000000000..2a69db6e8e8a32090a6c16ccc66871946188f8d8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pac-9.c
@@ -0,0 +1,21 @@
+/* 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 -mbranch-protection=pac-ret+leaf+bti -mthumb 
-mfloat-abi=soft -fasynchronous-unwind-tables --save-temps -g" } */
+
+__attribute__((noinline)) void
+fn1 (int a, int b, int c)
+{
+  if (a != b + c)
+    __builtin_abort ();
+}
+
+int main ()
+{
+  fn1 (40, 40, 80);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "\.save \{r7, ra_auth_code, lr\}" } } */
+/* { dg-final { scan-assembler "\.save \{r3, r7, ra_auth_code, lr\}" } } */
+/* { dg-final { scan-assembler "\.cfi_offset 143, \-8" } } */



Reply via email to