On 14/09/2022 15:20, Andrea Corallo via Gcc-patches wrote:
Hi all,

this patch enables address return signature and verification based on
Armv8.1-M Pointer Authentication [1].

To sign the return address, we use the PAC R12, LR, SP instruction
upon function entry.  This is signing LR using SP and storing the
result in R12.  R12 will be pushed into the stack.

During function epilogue R12 will be popped and AUT R12, LR, SP will
be used to verify that the content of LR is still valid before return.

Here an example of PAC instrumented function prologue and epilogue:

void foo (void);

int main()
{
   foo ();
   return 0;
}

Compiled with '-march=armv8.1-m.main -mbranch-protection=pac-ret
-mthumb' translates into:

main:
        pac     ip, lr, sp
        push    {r3, r7, ip, lr}
        add     r7, sp, #0
        bl      foo
        movs    r3, #0
        mov     r0, r3
        pop     {r3, r7, ip, lr}
        aut     ip, lr, sp
        bx      lr

The patch also takes care of generating a PACBTI instruction in place
of the sequence BTI+PAC when Branch Target Identification is enabled
contextually.

Ex. the previous example compiled with '-march=armv8.1-m.main
-mbranch-protection=pac-ret+bti -mthumb' translates into:

main:
        pacbti  ip, lr, sp
        push    {r3, r7, ip, lr}
        add     r7, sp, #0
        bl      foo
        movs    r3, #0
        mov     r0, r3
        pop     {r3, r7, ip, lr}
        aut     ip, lr, sp
        bx      lr

As part of previous upstream suggestions a test for varargs has been
added and '-mtpcs-frame' is deemed being incompatible with this return
signing address feature being introduced.

[1] 
<https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/armv8-1-m-pointer-authentication-and-branch-target-identification-extension>

gcc/Changelog

2021-11-03  Andrea Corallo  <andrea.cora...@arm.com>

        * config/arm/arm.c: (arm_compute_frame_layout)
        (arm_expand_prologue, thumb2_expand_return, arm_expand_epilogue)
        (arm_conditional_register_usage): Update for pac codegen.
        (arm_current_function_pac_enabled_p): New function.
        * config/arm/arm.md (pac_ip_lr_sp, pacbti_ip_lr_sp, aut_ip_lr_sp):
        Add new patterns.
        * config/arm/unspecs.md (UNSPEC_PAC_IP_LR_SP)
        (UNSPEC_PACBTI_IP_LR_SP, UNSPEC_AUT_IP_LR_SP): Add unspecs.

gcc/testsuite/Changelog

2021-11-03  Andrea Corallo  <andrea.cora...@arm.com>

        * gcc.target/arm/pac.h : New file.
        * gcc.target/arm/pac-1.c : New test case.
        * gcc.target/arm/pac-2.c : Likewise.
        * gcc.target/arm/pac-3.c : Likewise.
        * gcc.target/arm/pac-4.c : Likewise.
        * gcc.target/arm/pac-5.c : Likewise.
        * gcc.target/arm/pac-6.c : Likewise.
        * gcc.target/arm/pac-7.c : Likewise.
        * gcc.target/arm/pac-8.c : Likewise.


+ if (arm_current_function_pac_enabled_p () && !(arm_arch7 && arm_arch_cmse)) + error ("This architecture does not support branch protection instructions");

This test feels wrong. What does having cmse give us? I suspect you want a test that ensures we have at least v8-m.main so that the NOP instructions are correctly defined as NOPs (or, in this case, PACBTI instructions) rather than unpredictable; but if that's the case then I think you really want to write the test that way here (perhaps in a macro) and then move this test into that so that it becomes self-documenting - but don't we have a v8-m.main test anyway?


+         if (arm_current_function_pac_enabled_p ())
+           {
+              gcc_assert (!(saved_regs_mask & (1 << PC_REGNUM)));
+             arm_emit_multi_reg_pop (saved_regs_mask);
+             emit_insn (gen_aut_nop ());
+             emit_jump_insn (simple_return_rtx);
+           }

The assert is using indents that are just spaces, but the other lines use tabs. Please use tabs everywhere rather than mixing like this.

+/* Return TRUE if return address signing mechanism is enabled.  */
+bool
+arm_current_function_pac_enabled_p (void)
+{
+  return aarch_ra_sign_scope == AARCH_FUNCTION_ALL
+    || (aarch_ra_sign_scope == AARCH_FUNCTION_NON_LEAF
+       && !crtl->is_leaf);
+}

This is a case where you should use parenthesis around the expression so that the continuation lines are correctly indented.

@@ -11518,7 +11518,7 @@ (define_expand "prologue"
      arm_expand_prologue ();
    else
      thumb1_expand_prologue ();
-  DONE;
+   DONE;
   "
 )

Although this is a trivial cleanup, it has nothing to do with this patch. Please remove.

+  "arm_arch7 && arm_arch_cmse"

See my comments earlier about this test; the same applies here.

+       (unspec:SI [(reg:SI SP_REGNUM) (reg:SI LR_REGNUM)]
+                   UNSPEC_PAC_NOP))]
+
Again you have a mix of lines indented with tabs and lines indented with just spaces. Similarly with pacbti_nop and aut_nop.

Do you have a test for the nested functions case (I can't see it, but perhaps I've missed it somewhere)?

R.

Reply via email to