The BPF ISA doesn't have a no-operation instruction, but in practice the Linux kernel verifier performs some optimizations that rely on these instructions to be encoded in a particular way. As it turns out, we were using the "wrong" instruction in GCC.
This patch makes GCC to generate the expected instruction for NOP (a `ja 0') and also adds a test to make sure this is the case. Tested in bpf-unknown-none targets. 2020-09-14 Jose E. Marchesi <jose.march...@oracle.com> gcc/ * config/bpf/bpf.md ("nop"): Re-define as `ja 0'. gcc/testsuite/ * gcc.target/bpf/nop-1.c: New test. --- gcc/config/bpf/bpf.md | 7 ++++++- gcc/testsuite/gcc.target/bpf/nop-1.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/bpf/nop-1.c diff --git a/gcc/config/bpf/bpf.md b/gcc/config/bpf/bpf.md index 41bb4fcd9a7..769d8ea0096 100644 --- a/gcc/config/bpf/bpf.md +++ b/gcc/config/bpf/bpf.md @@ -82,10 +82,15 @@ (define_mode_attr msuffix [(SI "32") (DI "")]) ;;;; NOPs +;; The Linux kernel verifier performs some optimizations that rely on +;; nop instructions to be encoded as `ja 0', i.e. a jump to offset 0, +;; which actually means to jump to the next instruction, since in BPF +;; offsets are expressed in 64-bit words _minus one_. + (define_insn "nop" [(const_int 0)] "" - "mov\t%%r0,%%r0" + "ja\t0" [(set_attr "type" "alu")]) ;;;; Arithmetic/Logical diff --git a/gcc/testsuite/gcc.target/bpf/nop-1.c b/gcc/testsuite/gcc.target/bpf/nop-1.c new file mode 100644 index 00000000000..c4d274f6bad --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/nop-1.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-std=gnu99 --patchable-function-entry=2,1" } */ + +/* The purpose of this test is to make sure the right instruction is + generated for NOPs. See bpf.md for a description on why this is + important. */ + +int +foo () +{ + return 0; +} + +/* { dg-final { scan-assembler "foo:\n\t*ja\t0" } } */ -- 2.25.0.2.g232378479e