https://sourceware.org/bugzilla/show_bug.cgi?id=34558

            Bug ID: 34558
           Summary: BPF: gotol +N mis-assembled as goto with reloc against
                    undefined symbol `l`
           Product: binutils
           Version: 2.46.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: gas
          Assignee: unassigned at sourceware dot org
          Reporter: vineet.gupta at linux dot dev
  Target Milestone: 2.46
            Target: bpf

In the BPF pseudo-C assembly dialect (`-mdialect=pseudoc`), the 32-bit
unconditional jump `gotol` is mis-parsed when its operand carries an explicit
sign. Instead of the intended `JA|K|JMP32` (opcode `0x06`, displacement in the
32-bit `imm` field), gas emits `JA|K|JMP` (opcode `0x05`, displacement in the
16-bit `off` field) together with an `R_BPF_GNU_64_16` relocation against a
newly invented undefined global symbol named `l`.

The parser appears to match the shorter mnemonic `goto` first and then consume
the trailing `l` as the start of the operand expression, so `gotol +1` is
treated as `goto l+1`. This is confirmed byte-for-byte: assembling `gotol +1`
and `goto l+1` produces identical objects, both with an `R_BPF_GNU_64_16`
relocation against `l`.

With an unsigned literal (`gotol 1`) or a label (`gotol 1f`), the operand
`l 1` / `l 1f` is not a valid single expression, so the shorter match fails,
gas backtracks to `gotol`, and the correct `0x06` encoding is produced. Hence
only the signed forms are affected.

LLVM's assembler accepts `gotol +1` and `gotol 1` identically (both `0x06`),
and `llvm-objdump` prints the signed form `gotol +0x1`. So gas rejects — or
rather, silently miscompiles — the documented syntax that the other BPF
toolchain emits and accepts.

```asm
    .text

    /* 1. BAD: canonical spelling per the BPF ISA documentation.  */
    .globl  tc_signed_plus
tc_signed_plus:
    gotol   +1
    exit

    /* 2. BAD: same, negative displacement.  */
    .globl  tc_signed_minus
tc_signed_minus:
    gotol   -1
    exit

    /* 3. OK: unsigned literal.  */
    .globl  tc_unsigned
tc_unsigned:
    gotol   1
    exit

    /* 4. OK: label operand.  */
    .globl  tc_label
tc_label:
    gotol   1f
    exit
1:
    exit
```

```sh
bpf-unknown-none-as -mdialect=pseudoc -misa-spec=v4 gotol.s -o gotol.o
bpf-unknown-none-objdump -dr gotol.o
```

Found while enabling the Linux BPF selftests to build with `bpf-gcc`.
`tools/testing/selftests/bpf/progs/compute_live_registers.c` contains gotol +1

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Reply via email to