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