Jun*_* Ou 6 linux assembly linux-kernel
我想学习linux ebpf vm,如果我写一个ebpf程序test.c,使用llvm:
clang -O2 -target bpf -o test.o test.c. 如何在经典bpf中获得像tcpdump -d这样的ebpf程序集,谢谢.
这取决于您“学习linux ebpf vm”的确切含义。
如果您想学习eBPF的指令(类汇编语言本身),则可以查看内核中的文档(非常密集)或bcc项目中语法的摘要版本。
如果您希望了解eBPF虚拟机的内部工作原理,则可以查看各种演示文稿(我推荐D. Borkmann的演示文稿),我在此博客文章中提供了一个列表;或者您可以直接在linux/kernel/bpf(特别是file core.c)下的内核源代码中阅读。或者,有一个更简单的用户空间实现可用。
现在,如果您想查看从C编译到eBPF的代码,这里有一些解决方案。
就我而言,我使用tc-bpf手册页中显示的命令进行编译:
__bcc() {
clang -O2 -emit-llvm -c $1 -o - | \
llc -march=bpf -filetype=obj -o "`basename $1 .c`.o"
}
alias bcc=__bcc
Run Code Online (Sandbox Code Playgroud)
该代码被转换为eBPF,并存储在生成的ELF文件的其中一个部分中。然后,我可以使用诸如objdump或的工具检查程序readelf。例如,如果我的程序在classifier部分中:
$ bcc return_zero.c
$ readelf -x classifier return_zero.o
Hex dump of section 'classifier':
0x00000000 b7000000 02000000 95000000 00000000 ................
Run Code Online (Sandbox Code Playgroud)
在上面的输出中,显示了两个指令(小字节序-以开头的第一个字段0x是节内的偏移量)。我们可以对此进行分析以形成说明并获得:
b7 0 0 0000 00000002 // Load 0x02 in register r0
95 0 0 0000 00000000 // Exit and return value in r0
Run Code Online (Sandbox Code Playgroud)
可以将加载的程序指令(然后可能附加到可用的BPF挂钩之一)以eBPF汇编指令或机器指令(如果程序已JIT编译)转储。bpftool依赖libbpf,是执行此类操作的必备工具。例如,可以使用以下命令查看当前正在加载的程序,并记录其ID:
# bpftool prog show
Run Code Online (Sandbox Code Playgroud)
然后转储给定ID的程序的指令非常简单:
# bpftool prog dump xlated id <id>
# bpftool prog dump jited id <id>
Run Code Online (Sandbox Code Playgroud)
分别用于eBPF或JITed(如果有)指令。如果需要,输出也可以格式化为JSON。
根据用于将BPF注入内核的工具的不同,通常可以转储内核内验证程序的输出,该输出包含大多数以人类友好的方式格式化的指令。
使用bcc工具集(与上一个命令不直接相关,也与旧的16位编译器完全不相关),可以通过使用 BPF对象实例的相关标志来获得此功能,而tc filter add dev eth0 bpf obj … verbose使用该verbose 关键字。
前面提到的用户空间实现(uBPF)具有您可能感兴趣的自己的汇编程序和反汇编程序:它将“人类友好”(add32 r0, r1等)指令作为输入,并分别转换为目标文件,反之亦然。
但是可能更有趣的是,LLVM本身支持调试信息以及BPF反汇编程序:到目前为止,它已被合并,其作者(A. Starovoitov)已在netdev上发送了有关它的电子邮件。邮件列表。这意味着使用clang / LLVM 4.0+,您应该能够使用它llvm-objdump -S -no-show-raw-insn my_file.o来获得格式正确的输出。