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

            Bug ID: 128011
           Summary: [RISC-V] Zicfilp: lpad emitted after
                    patchable-function-entry NOPs
           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: jianhao.xu at seu dot edu.cn
  Target Milestone: ---
              Host: any
            Target: riscv64-*-*, riscv64-linux-gnu
             Build: any

Summary
-------
Under `-march=*_zicfilp -fcf-protection=branch` and
`-fpatchable-function-entry=N,0`,
GCC emits the patchable NOP sled before the landing pad instruction (`lpad 0`).

In `gcc/varasm.cc:assemble_start_function`, post-label patch areas are output
via `targetm.asm_out.print_patchable_function_entry`. Unlike x86
(`i386.cc:10865`)
and AArch64 (`aarch64.cc:26376`), the RISC-V target does not define
`TARGET_ASM_PRINT_PATCHABLE_FUNCTION_ENTRY`. It falls back to
`default_print_patchable_function_entry` (targhooks.cc), which immediately
emits the `.LPFE0` NOPs into asm.

`pass_insert_landing_pad` (`gcc/config/riscv/riscv-zicfilp.cc:136`) inserts
`lpad` as an RTL insn at `BB_HEAD (bb)` of the entry block. When RTL is
assembled in `final()`, `lpad 0` is emitted after the `.LPFE0` NOP sled.

Per the RISC-V Zicfilp specification, an indirect jump (`jalr`) sets
`ELP = LP_EXPECTED`. The first instruction at the target MUST be `lpad`.
Hitting a NOP causes a synchronous Software-check exception (Cause 18,
xtval = 2), breaking any indirect call to a patchable function.

Reproducer
----------
$ cat trigger.c
int target(int x) {
    return x * 2;
}

Compile flag: -O2 -march=rv64gc_zicfilp -fcf-protection=branch
-fpatchable-function-entry=2,0 -S

$ cat trigger.s
target:
.LPFE0:
        nop
        nop
.LFB0:
        .cfi_startproc
        lpad    0
        slli    a0,a0,1
        ret

Reply via email to