You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
NOTE: We probably need cpu v5 or other flags to enable this feature.
We can add it later when necessary.
This patch adds jump table support. A new insn 'gotox <reg>' is
added to allow goto through a register. The register represents
the address in the current section. The function is a concrete
example with bpf selftest progs/user_ringbuf_success.c.
Compilation command line to generate .s file:
=============================================
clang -g -Wall -Werror -D__TARGET_ARCH_x86 -mlittle-endian \
-I/home/yhs/work/bpf-next/tools/testing/selftests/bpf/tools/include \
-I/home/yhs/work/bpf-next/tools/testing/selftests/bpf \
-I/home/yhs/work/bpf-next/tools/include/uapi \
-I/home/yhs/work/bpf-next/tools/testing/selftests/usr/include -std=gnu11 \
-fno-strict-aliasing -Wno-compare-distinct-pointer-types \
-idirafter /home/yhs/work/llvm-project/llvm/build.21/Release/lib/clang/21/include \
-idirafter /usr/local/include -idirafter /usr/include \
-DENABLE_ATOMICS_TESTS -O2 -S progs/user_ringbuf_success.c \
-o /home/yhs/work/bpf-next/tools/testing/selftests/bpf/user_ringbuf_success.bpf.o.s \
--target=bpf -mcpu=v3
The related assembly:
read_protocol_msg:
...
r3 <<= 3
r1 = .LJTI1_0 ll
r1 += r3
r1 = *(u64 *)(r1 + 0)
gotox r1
LBB1_4:
r1 = *(u64 *)(r0 + 8)
goto LBB1_5
LBB1_7:
r1 = *(u64 *)(r0 + 8)
goto LBB1_8
LBB1_9:
w1 = *(u32 *)(r0 + 8)
r1 <<= 32
r1 s>>= 32
r2 = kern_mutated ll
r3 = *(u64 *)(r2 + 0)
r3 *= r1
*(u64 *)(r2 + 0) = r3
goto LBB1_11
LBB1_6:
w1 = *(u32 *)(r0 + 8)
r1 <<= 32
r1 s>>= 32
LBB1_5:
...
.section .rodata,"a",@progbits
.p2align 3, 0x0
.LJTI1_0:
.quad LBB1_4
.quad LBB1_6
.quad LBB1_7
.quad LBB1_9
...
publish_next_kern_msg:
...
r6 <<= 3
r1 = .LJTI6_0 ll
r1 += r6
r1 = *(u64 *)(r1 + 0)
gotox r1
LBB6_3:
...
LBB6_5:
...
LBB6_6:
...
LBB6_4:
...
.section .rodata,"a",@progbits
.p2align 3, 0x0
.LJTI6_0:
.quad LBB6_3
.quad LBB6_4
.quad LBB6_5
.quad LBB6_6
You can see in the above .LJTI1_0 and .LJTI6_0 are actually jump table targets
and these two jump tables are used in insns so they can get proper jump
table target with gotox insn.
Now let us look at sections in .o file
=======================================
For example,
[ 6] .rodata PROGBITS 0000000000000000 000740 0000d6 00 A 0 0 8
[ 7] .rel.rodata REL 0000000000000000 003860 000080 10 I 39 6 8
[ 8] .llvm_jump_table_sizes LLVM_JT_SIZES 0000000000000000 000816 000010 00 0 0 1
[ 9] .rel.llvm_jump_table_sizes REL 0000000000000000 0038e0 000010 10 I 39 8 8
...
[14] .llvm_jump_table_sizes LLVM_JT_SIZES 0000000000000000 000958 000010 00 0 0 1
[15] .rel.llvm_jump_table_sizes REL 0000000000000000 003970 000010 10 I 39 14 8
With llvm-readelf dump section 8 and 14:
$ llvm-readelf -x 8 user_ringbuf_success.bpf.o
Hex dump of section '.llvm_jump_table_sizes':
0x00000000 00000000 00000000 04000000 00000000 ................
$ llvm-readelf -x 14 user_ringbuf_success.bpf.o
Hex dump of section '.llvm_jump_table_sizes':
0x00000000 20000000 00000000 04000000 00000000 ...............
You can see. There are two jump tables:
jump table 1: offset 0, size 4 (4 labels)
jump table 2: offset 0x20, size 4 (4 labels)
Check sections 9 and 15, we can find the corresponding section:
Relocation section '.rel.llvm_jump_table_sizes' at offset 0x38e0 contains 1 entries:
Offset Info Type Symbol's Value Symbol's Name
0000000000000000 0000000a00000002 R_BPF_64_ABS64 0000000000000000 .rodata
Relocation section '.rel.llvm_jump_table_sizes' at offset 0x3970 contains 1 entries:
Offset Info Type Symbol's Value Symbol's Name
0000000000000000 0000000a00000002 R_BPF_64_ABS64 0000000000000000 .rodata
and confirmed that the relocation is against '.rodata'.
Dump .rodata section:
0x00000000 a8000000 00000000 10010000 00000000 ................
0x00000010 b8000000 00000000 c8000000 00000000 ................
0x00000020 28040000 00000000 00050000 00000000 (...............
0x00000030 70040000 00000000 b8040000 00000000 p...............
0x00000040 44726169 6e207265 7475726e 65643a20 Drain returned:
So we can get two jump tables:
.rodata offset 0, # of lables 4:
0x00000000 a8000000 00000000 10010000 00000000 ................
0x00000010 b8000000 00000000 c8000000 00000000 ................
.rodata offset 0x200, # of lables 4:
0x00000020 28040000 00000000 00050000 00000000 (...............
0x00000030 70040000 00000000 b8040000 00000000 p...............
This way, you just need to scan related code section. As long as it
matches one of jump tables (.rodata relocation, offset also matching),
you do not need to care about gotox at all in libbpf.
An option -bpf-min-jump-table-entries is implemented to control the minimum
number of entries to use a jump table on BPF. The default value 4, but it
can be changed with the following clang option
clang ... -mllvm -bpf-min-jump-table-entries=6
where the number of jump table cases needs to be >= 6 in order to
use jump table.
0 commit comments