https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128284

            Bug ID: 128284
           Summary: [AArch64] Guarded Control Stack aarch64_gcsss1/gcsss2
                    RTL patterns miss memory clobber
           Product: gcc
           Version: 16.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: 220245569 at seu dot edu.cn
                CC: 220255623 at seu dot edu.cn, jianhao.xu at seu dot edu.cn
  Target Milestone: ---
            Target: aarch64-*-*

Summary
-------
In `gcc/config/aarch64/aarch64.md:8926-8937`, the Armv9.4-A Guarded Control
Stack switch patterns `aarch64_gcsss1` and `aarch64_gcsss2` (backing the ACLE
`__gcsss` intrinsic) are defined as `UNSPEC_VOLATILE` without a memory clobber:

  (define_insn "aarch64_gcsss1"
    [(unspec_volatile [(match_operand:DI 0 "register_operand" "r")]
UNSPECV_GCSSS1)]
    "TARGET_GCS"
    "sys\t#3, c7, c7, #2, %0 // gcsss1"
  )

Architecturally, `GCSSS1` validates and consumes the cap token at
`*new_gcs_cap`
and `GCSSS2` writes an in-progress/switched token into GCS memory (which is
readable by normal load instructions). Because `gcc/cse.cc:6181-6216` does not
invalidate memory on `UNSPEC_VOLATILE` unless `(clobber (mem:BLK (scratch)))`
is present, RTL `cse1` deletes any post-`__gcsss` reload from `*new_gcs_cap`
and
reuses the pre-switch value.

Reproducer
----------
$ cat trigger.c
#include <arm_acle.h>
#include <stdint.h>

uint64_t check_gcs_switch(uint64_t *new_gcs_cap) {
    uint64_t cap_before = *new_gcs_cap;
    void *old_gcs = __gcsss((void *)new_gcs_cap);
    (void)old_gcs;
    return cap_before ^ *new_gcs_cap;
}

Compile flag: aarch64-linux-gnu-gcc -ffreestanding -O2 -march=armv9.4-a+gcs -S
trigger.c

$ cat trigger.s
check_gcs_switch:
        sys     #3, c7, c7, #2, x0 // gcsss1
        mov     x0, 0
        sysl    x0, #3, c7, c7, #3 // gcsss2
        mov     x0, 0                   # cse1 folded cap_before ^ *new_gcs_cap
to 0!
        ret

Suggested Fix
-------------
Add `(clobber (mem:BLK (scratch)))` to `define_insn "aarch64_gcsss1"` and
`define_insn "aarch64_gcsss2"` in `gcc/config/aarch64/aarch64.md:8926-8937`.

Reply via email to