[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