[PATCH v2] bpf: accept any spelling of the addr_space_cast address spaces
Vineet Gupta
vineet.gupta@linux.dev
Thu Oct 15 16:51:01 GMT 2026
On 10/15/26 8:59 PM, Jose E. Marchesi wrote:
> Hi Vineet.
>
> Thanks for the new version of the patch.
> OK for master.
Pushed.
Thx,
-Vineet
>> Building the kernel's BPF arena selftests fails to assemble:
>>
>> progs/verifier_arena.c:525: Error: unrecognized instruction \
>> `r1 =addr_space_cast(r1,0x0,0x1)'
>> progs/verifier_arena.c:525: Error: expected ',', got 'x'
>>
>> (this is with an in-works local copy of gcc with addr_space_cast()
>> support).
>>
>> gas matches the address space characters as literal `0' and `1' and
>> trips over the hex form.
>>
>> Introduce a %DIGIT tag for a constant the opcode already encodes, and
>> parse the operand as a number so the two are compared by value.
>>
>> gas/
>> * config/tc-bpf.c: Include safe-ctype.h.
>> (md_assemble): Handle the %DIGIT tag.
>> * testsuite/gas/bpf/ascast.s: Test the hex spelling.
>> * testsuite/gas/bpf/ascast-pseudoc.s: Likewise.
>> * testsuite/gas/bpf/ascast.d: Adjust.
>> * testsuite/gas/bpf/ascast-pseudoc.d: Likewise.
>> * testsuite/gas/bpf/ascast-be.d: Likewise.
>> * testsuite/gas/bpf/ascast-be-pseudoc.d: Likewise.
>> * testsuite/gas/bpf/ascast-v1.d: Likewise.
>>
>> include/
>> * opcode/bpf.h (struct bpf_opcode): Document the %DIGIT tag.
>>
>> opcodes/
>> * bpf-dis.c: Include safe-ctype.h.
>> (print_insn_bpf): Handle the %DIGIT tag.
>> * bpf-opc.c (bpf_opcodes): Use %DIGIT for the address spaces of
>> addrc.
>>
>> Signed-off-by: Vineet Gupta <vineet.gupta@linux.dev>
>> ---
>> Changes in v2:
>> - Describe the new tag as %DIGIT rather than %N (Jose)
>> - Link to v1: https://inbox.sourceware.org/binutils/20261015083524.3948689-1-vineet.gupta@linux.dev/
>>
>> gas/config/tc-bpf.c | 20 ++++++++++++++++++++
>> gas/testsuite/gas/bpf/ascast-be-pseudoc.d | 2 ++
>> gas/testsuite/gas/bpf/ascast-be.d | 2 ++
>> gas/testsuite/gas/bpf/ascast-pseudoc.d | 2 ++
>> gas/testsuite/gas/bpf/ascast-pseudoc.s | 2 ++
>> gas/testsuite/gas/bpf/ascast-v1.d | 2 ++
>> gas/testsuite/gas/bpf/ascast.d | 2 ++
>> gas/testsuite/gas/bpf/ascast.s | 2 ++
>> include/opcode/bpf.h | 3 +++
>> opcodes/bpf-dis.c | 14 ++++++++++++++
>> opcodes/bpf-opc.c | 8 ++++----
>> 11 files changed, 55 insertions(+), 4 deletions(-)
>>
>> diff --git a/gas/config/tc-bpf.c b/gas/config/tc-bpf.c
>> index 3fda7f2dfd8d..3d2f79de3ca4 100644
>> --- a/gas/config/tc-bpf.c
>> +++ b/gas/config/tc-bpf.c
>> @@ -27,6 +27,7 @@
>> #include "elf/bpf.h"
>> #include "dwarf2dbg.h"
>> #include "libiberty.h"
>> +#include "safe-ctype.h"
>> #include <ctype.h>
>>
>> /* Data structure representing a parsed BPF instruction. */
>> @@ -1727,6 +1728,25 @@ md_assemble (char *str ATTRIBUTE_UNUSED)
>> insn.size = 16;
>> p += 4;
>> }
>> + else if (ISDIGIT (p[1]))
>> + {
>> + /* %DIGIT is a constant the opcode already encodes, such
>> + as either address space of an addr_space_cast.
>> + Compare values rather than characters, so that every
>> + spelling of the constant is accepted: the kernel
>> + writes those address spaces as 0x0 and 0x1. */
>> + char *p_end, *s_end;
>> + uint64_t want = strtoull (p + 1, &p_end, 0);
>> + uint64_t got = strtoull (s, &s_end, 0);
>> +
>> + if (s_end == s || got != want)
>> + {
>> + PARSE_ERROR ("expected %lu", (unsigned long) want);
>> + break;
>> + }
>> + p = p_end;
>> + s = s_end;
>> + }
>> else
>> as_fatal (_("invalid %%-tag in BPF opcode '%s'\n"), template);
>> }
>> diff --git a/gas/testsuite/gas/bpf/ascast-be-pseudoc.d b/gas/testsuite/gas/bpf/ascast-be-pseudoc.d
>> index d66820f8abd5..28b09b1196b8 100644
>> --- a/gas/testsuite/gas/bpf/ascast-be-pseudoc.d
>> +++ b/gas/testsuite/gas/bpf/ascast-be-pseudoc.d
>> @@ -12,3 +12,5 @@ Disassembly of section .text:
>> 8: bf 01 00 01 00 01 00 00 r0 = addr_space_cast\(r1, 1, 0\)
>> 10: bf 92 00 01 00 00 00 01 r9 = addr_space_cast\(r2, 0, 1\)
>> 18: bf 23 00 00 00 00 00 00 r2=r3
>> + 20: bf 34 00 01 00 00 00 01 r3 = addr_space_cast\(r4, 0, 1\)
>> + 28: bf 56 00 01 00 01 00 00 r5 = addr_space_cast\(r6, 1, 0\)
>> diff --git a/gas/testsuite/gas/bpf/ascast-be.d b/gas/testsuite/gas/bpf/ascast-be.d
>> index e2816ced1337..10b0e974e029 100644
>> --- a/gas/testsuite/gas/bpf/ascast-be.d
>> +++ b/gas/testsuite/gas/bpf/ascast-be.d
>> @@ -12,3 +12,5 @@ Disassembly of section .text:
>> 8: bf 01 00 01 00 01 00 00 addrc %r0,%r1,1,0
>> 10: bf 92 00 01 00 00 00 01 addrc %r9,%r2,0,1
>> 18: bf 23 00 00 00 00 00 00 mov %r2,%r3
>> + 20: bf 34 00 01 00 00 00 01 addrc %r3,%r4,0,1
>> + 28: bf 56 00 01 00 01 00 00 addrc %r5,%r6,1,0
>> diff --git a/gas/testsuite/gas/bpf/ascast-pseudoc.d b/gas/testsuite/gas/bpf/ascast-pseudoc.d
>> index 07cf304a4bd8..d24be737f83b 100644
>> --- a/gas/testsuite/gas/bpf/ascast-pseudoc.d
>> +++ b/gas/testsuite/gas/bpf/ascast-pseudoc.d
>> @@ -12,3 +12,5 @@ Disassembly of section .text:
>> 8: bf 10 01 00 00 00 01 00 r0 = addr_space_cast\(r1, 1, 0\)
>> 10: bf 29 01 00 01 00 00 00 r9 = addr_space_cast\(r2, 0, 1\)
>> 18: bf 32 00 00 00 00 00 00 r2=r3
>> + 20: bf 43 01 00 01 00 00 00 r3 = addr_space_cast\(r4, 0, 1\)
>> + 28: bf 65 01 00 00 00 01 00 r5 = addr_space_cast\(r6, 1, 0\)
>> diff --git a/gas/testsuite/gas/bpf/ascast-pseudoc.s b/gas/testsuite/gas/bpf/ascast-pseudoc.s
>> index 0d0c35a278f8..f5ddec9e9a33 100644
>> --- a/gas/testsuite/gas/bpf/ascast-pseudoc.s
>> +++ b/gas/testsuite/gas/bpf/ascast-pseudoc.s
>> @@ -4,3 +4,5 @@
>> r0 = addr_space_cast(r1, 1, 0)
>> r9 = addr_space_cast(r2, 0, 1)
>> r2 = r3
>> + r3 = addr_space_cast(r4, 0x0, 0x1)
>> + r5 = addr_space_cast(r6, 0x1, 0x0)
>> diff --git a/gas/testsuite/gas/bpf/ascast-v1.d b/gas/testsuite/gas/bpf/ascast-v1.d
>> index d1b0f5c659e8..ae343f55ae79 100644
>> --- a/gas/testsuite/gas/bpf/ascast-v1.d
>> +++ b/gas/testsuite/gas/bpf/ascast-v1.d
>> @@ -12,3 +12,5 @@ Disassembly of section .text:
>> 8: bf 10 01 00 00 00 01 00 addrc %r0,%r1,1,0
>> 10: bf 29 01 00 01 00 00 00 addrc %r9,%r2,0,1
>> 18: bf 32 00 00 00 00 00 00 mov %r2,%r3
>> + 20: bf 43 01 00 01 00 00 00 addrc %r3,%r4,0,1
>> + 28: bf 65 01 00 00 00 01 00 addrc %r5,%r6,1,0
>> diff --git a/gas/testsuite/gas/bpf/ascast.d b/gas/testsuite/gas/bpf/ascast.d
>> index 9e29fde286c5..5b21fa35d60b 100644
>> --- a/gas/testsuite/gas/bpf/ascast.d
>> +++ b/gas/testsuite/gas/bpf/ascast.d
>> @@ -12,3 +12,5 @@ Disassembly of section .text:
>> 8: bf 10 01 00 00 00 01 00 addrc %r0,%r1,1,0
>> 10: bf 29 01 00 01 00 00 00 addrc %r9,%r2,0,1
>> 18: bf 32 00 00 00 00 00 00 mov %r2,%r3
>> + 20: bf 43 01 00 01 00 00 00 addrc %r3,%r4,0,1
>> + 28: bf 65 01 00 00 00 01 00 addrc %r5,%r6,1,0
>> diff --git a/gas/testsuite/gas/bpf/ascast.s b/gas/testsuite/gas/bpf/ascast.s
>> index dc34b6822700..d6cae704a9aa 100644
>> --- a/gas/testsuite/gas/bpf/ascast.s
>> +++ b/gas/testsuite/gas/bpf/ascast.s
>> @@ -4,3 +4,5 @@
>> addrc %r0, %r1, 1, 0
>> addrc %r9, %r2, 0, 1
>> mov %r2, %r3
>> + addrc %r3, %r4, 0x0, 0x1
>> + addrc %r5, %r6, 0x1, 0x0
>> diff --git a/include/opcode/bpf.h b/include/opcode/bpf.h
>> index c5cfd98df879..b4a303bb768d 100644
>> --- a/include/opcode/bpf.h
>> +++ b/include/opcode/bpf.h
>> @@ -279,6 +279,9 @@ struct bpf_opcode
>> %w - expect zero or more white spaces and print a single space.
>> %W - expect one or more white spaces and print a single space.
>> %t - expect the end of a mnemonic, and print nothing.
>> + %DIGIT - a decimal constant that the opcode already encodes; expect
>> + any spelling of its value, e.g. `0x1' for %1, and print
>> + the digits.
>>
>> %t consumes no input. It only asserts that the mnemonic just
>> matched ends there, that is, that the input does not continue it
>> diff --git a/opcodes/bpf-dis.c b/opcodes/bpf-dis.c
>> index 41f6b3f0c236..26d586a44649 100644
>> --- a/opcodes/bpf-dis.c
>> +++ b/opcodes/bpf-dis.c
>> @@ -22,6 +22,7 @@
>> #include "sysdep.h"
>> #include "disassemble.h"
>> #include "libiberty.h"
>> +#include "safe-ctype.h"
>> #include "opintl.h"
>> #include "opcode/bpf.h"
>> #include "elf-bfd.h"
>> @@ -290,6 +291,19 @@ print_insn_bpf (bfd_vma pc, disassemble_info *info)
>> insn_size = 16;
>> p += 4;
>> }
>> + else if (ISDIGIT (*(p + 1)))
>> + {
>> + /* %DIGIT is a constant the opcode itself encodes; print
>> + the number without its tag. */
>> + p += 1;
>> + while (ISDIGIT (*p))
>> + {
>> + (*info->fprintf_styled_func) (info->stream,
>> + dis_style_immediate,
>> + "%c", *p);
>> + p += 1;
>> + }
>> + }
>> else
>> {
>> /* xgettext:c-format */
>> diff --git a/opcodes/bpf-opc.c b/opcodes/bpf-opc.c
>> index 0b5e7e9b1d7f..05503c338ad7 100644
>> --- a/opcodes/bpf-opc.c
>> +++ b/opcodes/bpf-opc.c
>> @@ -93,12 +93,12 @@ const struct bpf_opcode bpf_opcodes[] =
>> BPF_V4, BPF_CODE|BPF_OFFSET16, BPF_CLASS_ALU64|BPF_CODE_MOV|BPF_SRC_X|BPF_OFFSET16_MOVS16},
>> {BPF_INSN_MOVS32R, "movs%W%dr , %sr , 32", "%dr%w=%w( s32 )%w%sr",
>> BPF_V4, BPF_CODE|BPF_OFFSET16, BPF_CLASS_ALU64|BPF_CODE_MOV|BPF_SRC_X|BPF_OFFSET16_MOVS32},
>> - {BPF_INSN_ASCASTK, "addrc%W%dr , %sr , 0 , 1",
>> - "%dr%w=%waddr_space_cast ( %sr ,%w0 ,%w1 )",
>> + {BPF_INSN_ASCASTK, "addrc%W%dr , %sr , %0 , %1",
>> + "%dr%w=%waddr_space_cast ( %sr ,%w%0 ,%w%1 )",
>> BPF_V1, BPF_CODE|BPF_OFFSET16|BPF_IMM32,
>> BPF_CLASS_ALU64|BPF_CODE_MOV|BPF_SRC_X|BPF_OFFSET16_ASCAST|BPF_IMM32_ASCAST_K},
>> - {BPF_INSN_ASCASTU, "addrc%W%dr , %sr , 1 , 0",
>> - "%dr%w=%waddr_space_cast ( %sr ,%w1 ,%w0 )",
>> + {BPF_INSN_ASCASTU, "addrc%W%dr , %sr , %1 , %0",
>> + "%dr%w=%waddr_space_cast ( %sr ,%w%1 ,%w%0 )",
>> BPF_V1, BPF_CODE|BPF_OFFSET16|BPF_IMM32,
>> BPF_CLASS_ALU64|BPF_CODE_MOV|BPF_SRC_X|BPF_OFFSET16_ASCAST|BPF_IMM32_ASCAST_U},
>> {BPF_INSN_MOVR, "mov%W%dr , %sr", "%dr = %sr",
More information about the bpf
mailing list