Re: GCC and binutils support for BPF V4 instructions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





On 7/29/23 9:54 PM, Jose E. Marchesi wrote:

On Sat, Jul 29, 2023 at 1:29 AM Jose E. Marchesi
<jose.marchesi@xxxxxxxxxx> wrote:


On Fri, Jul 28, 2023 at 11:01 AM Jose E. Marchesi
<jose.marchesi@xxxxxxxxxx> wrote:


On 7/28/23 9:41 AM, Jose E. Marchesi wrote:
Hello.
Just a heads up regarding the new BPF V4 instructions and their
support
in the GNU Toolchain.
V4 sdiv/smod instructions
    Binutils has been updated to use the V4 encoding of these
    instructions, which used to be part of the xbpf testing dialect used
    in GCC.  GCC generates these instructions for signed division when
    -mcpu=v4 or higher.
V4 sign-extending register move instructions
V4 signed load instructions
V4 byte swap instructions
    Supported in assembler, disassembler and linker.  GCC generates
these
    instructions when -mcpu=v4 or higher.
V4 32-bit unconditional jump instruction
    Supported in assembler and disassembler.  GCC doesn't generate
that
    instruction.
    However, the assembler has been expanded in order to perform the
    following relaxations when the disp16 field of a jump instruction is
    known at assembly time, and is overflown, unless -mno-relax is
    specified:
      JA disp16  -> JAL disp32
      Jxx disp16 -> Jxx +1; JA +1; JAL disp32
    Where Jxx is one of the conditional jump instructions such as
jeq,
    jlt, etc.

Sounds great. The above 'JA/Jxx disp16' transformation matches
what llvm did as well.

Not by chance ;)

Now what is pending in binutils is to relax these jumps in the linker as
well.  But it is very low priority, compared to get these kernel
selftests building and running.  So it will happen, but probably not
anytime soon.

By the way, for doing things like that (further object transformations
by linkers and the like) we will need to have the ELF files annotated
with:

- The BPF cpu version the object was compiled for: v1, v2, v3, v4, and

- Individual flags specifying the BPF cpu capabilities (alu32, bswap,
   jmp32, etc) required/expected by the code in the object.

Note it is interesting to being able to denote both, for flexibility.

There are 32 bits available for machine-specific flags in e_flags, which
are commonly used for this purpose by other arches.  For BPF I would
suggest something like:

#define EF_BPF_ALU32  0x00000001
#define EF_BPF_JMP32  0x00000002
#define EF_BPF_BSWAP  0x00000004
#define EF_BPF_SDIV   0x00000008
#define EF_BPF_CPUVER 0x00FF0000

Interesting idea. I don't mind, but what are we going to do with this info?
I cannot think of anything useful libbpf could do with it.
For other archs such flags make sense, since disasm of everything
to discover properties is hard. For BPF we will parse all insns anyway,
so additional info in ELF doesn't give any additional insight.

I mainly had link-time relaxation in mind.  The linker needs to know
what instructions are available (JMP32 or not) in order to decide what
to relax, and to what.

But the assembler has little choice when the jump target is >16bits.
It can use jmp32 or error.

When the assembler sees a jump instruction:

    goto EXPR

there are several possibilities:

1. EXPR consists on a literal number like 1, -10 or 0xff, or an
    expression that can be resolved during the first assembler pass (like
    8 * 64).  The numerical result is interpreted as number of 64-bit
    words minus one.  In this case, the assembler can immediately decide
    whether the operand is >16 bits, relaxing to the jmp32 jump if cpu >=
    v4 and unless -mno-relax is passed in the command line.

2. EXPR is a symbolic expression involving a symbol that can be resolved
    during the second assembler pass.  For example, `foo + 10'.  In this
    case, there are two possibilities:

    2.1. The symbol is an absolute symbol.  In this case the value is
         interpreted as-such and no conversion is done by the assembler.
         So if for example the user invokes the assembler passing
         `--defsym foo=10', the assembled instruction is `ja 20'.

    2.2. The symbol is a PC-relative or section-relative symbol.  In this
         case the value is interpreted as a byte offset (the assembler
         takes care to transform offsets relative to the current section
         into PC-relative offsets whenever necessary).  This is the case
         of labels.  For these symbols, the BPF assembler converts the
         value from bytes to number of 64-bit words minus one.  So for
         example for `ja done' where `done' has the value 256 bytes, the
         assembled instruction is `ja 31'.

3. EXPR is a symbolic expression involving a symbol that cannot be
    resolved during the second assembler pass.  In this case, a
    relocation for the 16-bit immediate field in the instruction is
    generated in the assembled object.  There is no R_BPF_64_16
    relocation defined by BPF as of yet, so we are using
    R_BPF_GNU_64_16=256, which as we agreed uses a high relocation number
    to avoid collisions.  Since gas is a standalone assembler, it seems
    sensible to emit a relocation rather than erroing out in these
    situations.  ld knows how to handle these relocs when linking BPF
    objects together.

I guess you're proposing to encode this e_flags in the text of asm ?
Special asm directive that will force asm to error or use jmp32?

GAS uses command-line options for that.

When GCC is invoked with -mcpu=v3, for example, it passes the
corresponding option to the assembler so it expects a BPF V3 assembly
program. In that scenario, if the user does a jump to an address that is
16bit in an inline asm, the assembler will error out,
because relaxing to jmp32 is not a possibility in V3.  Ditto for
compiler options like -msdiv or -mjmp32, that both clang and GCC
support.

I don't know how clang configures its integrated assembler... I guess by
calling some function.  But it is the same principle: if you tell clang
to generate v3 bpf and you include a header that uses a v4 instruction
(or overflown jump that would require relaxation) in inline asm, you
want an error.

If -mcpu=<version> is specified in the clang command line,
then the cpu <version> will be encoded in IR and will be
passed to the integrated assembler. And if you specify
-mcpu=v3 in the command line and your code has
cpu v4 inline assembly code, the compiler will error out.


Also as you mention the disassembler can look in the object to determine
which instructions shall be recognized and with insructions shall be
reported as <unknown>.  Right now it is necessary to pass an explicit
option to the assembler, and the default is v4.

Disambiguating between unknown and exact insn kinda makes sense for disasm.
For assembler it's kinda weird. If text says 'sdiv' the asm should emit
binary code for it regardless of asm directive.

Unless configured to not do so?  See above.

It seems e_flags can only be emitted by assembler.
Like if it needs to use jmp32 it will add EF_BPF_JMP32.

Yep.

Still feels that we can live without these flags, but not a bad
addition.

The individual flags... I am not sure, other arches have them, but maybe
having them in BPF doesn't make much sense and it is not worth the extra
complication and wasted bits in e_flags.  How realistic is to expect
that some kernel may support a particular version of the BPF ISA, and
also have support for some particular instruction from a later ISA as
the result of a backport or something?  Not for me to judge... I was
already bitten by my utter ignorance on kernel business when I added
that silly useless -mkernel=VERSION option to GCC 8-)

What I am pretty sure is that we will need something like EF_BPF_CPUVER
if we are ever gonna support relaxation in any linker external to
libbpf, and also to detect (and error/warn) when several objects with
different BPF versions are linked together.

As far as flag names, let's use EF_ prefix. I think it's more canonical.
And single 0xF is probably enough for cpu ver.

Agreed.




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux