[llvm] [RFC][BPF] Support Jump Table (PR #133856)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 3 09:09:06 PDT 2025
yonghong-song wrote:
> Thanks @yonghong-song, that size/offset section is really useful! This looks sufficient for me to continue with a PoC.
>
> > you do not need to care about gotox at all.
>
> Unfortunately, I do, this is required for verification. For indirect jumps to work, two things should be verified:
You are right. Verification does need to connect jump table map and gotox insn.
When I say 'don't care gotox at all', I actually mean libbpf part where you need to go through various elf sections to connect them together.
>
> ```
> rX <- jump_table_x[i] # here jump_table_x[i] should be converted to M[i]
> ...
> gotox rX # here on load imm=fd(M)
> ```
>
> The `gotox` should reference an instance of an instruction set map `M` directly. This is required to 1) verify that we take each branch in `visit_insn` 2) verify the instruction when we symbolically run the verifier. In the latter case `gotox rX` is allowed iff `imm=M` and `rX` was loaded from the same map `M`.
>
> So, in order to construct a verifiable program, libbpf should:
>
> * find all jump tables, for each jump table `X`:
>
> * create an instruction set map `M(X)`
> * find all loads from table `X`, replace by a map value load from map `M(X)`
>
> * find all `gotox`, backtrack the register load from map `M(X)`, set `imm=M(X)` in the `gotox`
Backtrack certainly work. But maybe there is an alternative not to do backtrack.
For example,
r1 = .LJTI6_0 ll
<== we will know this is from a map (representing a jump table)
<== so mark r1 with some info like (jump_table_addr, offset 0)
r1 += r6
<== r1 still like jump_table_addr, need to ensure [r6, r6 + 8] is
within jump table range
r1 = *(u64 *)(r1 + 0)
<== r1 will be jump_table target, but still keep jump_table reference in r1.
gotox r1
<== goto jump_table_target (still has jump_table reference,
from verifier perspective, all jump table targets
in jump table should be verified).
>
>
> (Haven't checked yet for real, but this looks to be enough for "custom", e.g., user-defined, jump tables to work. Just declare it as `static const`, initialize with label addresses, and it will be present in `.rodata`. Maybe the only change that the corresponding `size` section should be pushed manually in this case?)
Your user-defined jump table may work. But it would be great if we can just allow the current common switch statements from code cleanness and developer productivity.
https://github.com/llvm/llvm-project/pull/133856
More information about the llvm-commits
mailing list