带有LLVM的eBPF组件
目录
从C到目标文件
深入说明
eBPF与LLVM循序渐进
从C编译到eBPF程序集
组装到ELF目标文件
llvm-objdump的人性化输出
内联汇编
结论
此职位作为草稿留了很长时间。它的大部分内容是在2017年12月编写的。我希望它能在今天发布,尽管Cilium指南也涵盖了该功能。
eBPF(扩展的Berkeley数据包过滤器)相对于旧BPF版本(对于经典BPF而言,是cBPF)最有用的发展之一就是基于clang和LLVM的后端的可用性,从而可以从C源代码生成eBPF字节码。1个
从C到目标文件
例如,可以从以下代码编译返回零的简单eBPF程序:
$ cat my_bpf_program.c
int func()
{return 0;
}
命令行如下所示:
$ clang -target bpf -Wall -O2 -c my_bpf_program.c -o my_bpf_objfile.o
注意:某些程序比本示例更先进,可能需要将该-mcpu
选项传递 给llc
,并使用更接近以下命令的内容:
$ clang -O2 -emit-llvm -c my_bpf_program.c -o - | \llc -march=bpf -mcpu=probe -filetype=obj -o my_bpf_objfile.o
这将以ELF格式创建一个目标文件,其中包含已编译的字节码。默认情况下,代码在.text
ELF部分下。让我们转储它:
$ readelf -x .text my_bpf_objfile.oHex dump of section '.text':0x00000000 b7000000 00000000 95000000 00000000 ................
有效!我们在这里有两个eBPF指令:
b7 0 0 0000 00000000 # r0 = 0
95 0 0 0000 00000000 # exit and return r0
如果您不熟悉eBPF汇编语法,则可能对此简短参考资料 (或 完整的文档,但内容密集)感兴趣 。
深入说明
从C编译为eBPF字节码作为目标文件非常有用。生成的ELF文件可直接用于将程序附加到各种钩子上:TC,XDP,kprobes等。将高级程序作为字节码编写将非常耗时,并且在2020年我完成对本文的编辑时,将更加复杂诸如 CO-RE之类的功能 根本无法手动完成。Clang和LLVM是eBPF工作流程的组成部分。
但是,对于需要测试非常特定的eBPF指令序列或微调程序特定方面的人员来说,这可能不是一个方便的解决方案。如果我想修改说明怎么办?如果我想在程序末尾添加第三条eBPF指令,以便在程序退出后为寄存器r0设置另一个值,该怎么办?当然,这个例子没有用,但是我仍然可以尝试一下!
为此,我们可以:
从头开始用eBPF字节码编写一个eBPF程序。这是完全可行的,但可能又长又乏味,而且绝对不友好。为了保持与tc之类工具的兼容性,无论如何该程序都必须转换为目标文件,这为该过程增加了额外的步骤。
使用汇编语言从头开始编写程序,至少不要以字节码编写程序,然后使用专用的汇编器对其进行编译(例如:
ebpf_asm
在Python中,由Solarflare编写 )。
作为LLVM近期改进的一部分,出现了另一个解决方案,我们还可以:
- 从C编译为eBPF汇编语言。编辑程序集,然后将其作为字节码组装到目标文件中。
Clang和LLVM现在可以做到这一点!在一侧生成程序的可读版本,然后在另一侧进行组装。奖励: llvm-objdump
甚至可以用来转储包含在目标文件中的程序。
eBPF与LLVM循序渐进
要使用本节中介绍的所有clang和LLVM功能,您需要在6.0版或更高版本中使用这些工具。当我开始起草本文时,它是开发分支,但是到我完成它时,版本10已经发布了,因此应该没有问题。
从C编译到eBPF程序集
让我们用clang编译从C到eBPF程序集的程序。实际上,这与通常使用C源代码为处理器生成汇编程序的方式相同,只是您告诉clang目标是 bpf
。2
$ cat bpf.c
int func()
{return 0;
}$ clang -target bpf -S -o bpf.s bpf.c
$ cat bpf.s.text.globl func # -- Begin function func.p2align 3
func: # @func
# %bb.0:r1 = 0*(u32 *)(r10 - 4) = r1r0 = r1exit# -- End function
太好了,现在让我们对其进行修改并在底部添加我们的说明!
$ sed -i '$a \\tr0 = 3' bpf.s
$ cat bpf.s.text.globl func # -- Begin function func.p2align 3
func: # @func
# %bb.0:r1 = 0*(u32 *)(r10 - 4) = r1r0 = r1exit# -- End functionr0 = 3
组装到ELF目标文件
我们可以将该文件汇编为包含该程序字节码的ELF目标文件。它需要llvm-mc
处理机器代码并与LLVM一起提供的工具。
$ llvm-mc -triple bpf -filetype=obj -o bpf.o foo.s
我们有ELF文件!让我们转储字节码:
$ readelf -x .text my_bpf_objfile.oHex dump of section '.text':0x00000000 b7010000 00000000 631afcff 00000000 ........c.......0x00000010 bf100000 00000000 95000000 00000000 ................0x00000020 b7000000 03000000 b7000000 03000000 ................
相对于程序的原始版本,前两个说明没有变化。第三条指令对应于我们添加到汇编文件中的内容:它将3加载到寄存器r0中。我们已成功编辑了说明。例如,我们现在可以使用将程序加载到内核中bpftool
。任务完成!
llvm-objdump的人性化输出
请注意,LLVM还提供了一种以人类可读的方式转储eBPF对象文件的方法(如果我没有记错的话,从4.0版开始)。这可以通过以下方式完成llvm-objdump
:
$ llvm-objdump -d bpf.obpf.o: file format ELF64-BPFDisassembly of section .text:
func:0: b7 01 00 00 00 00 00 00 r1 = 01: 63 1a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r12: bf 10 00 00 00 00 00 00 r0 = r13: 95 00 00 00 00 00 00 00 exit4: b7 00 00 00 03 00 00 00 r0 = 3
我们获得了LLVM使用的语法的汇编指令(我们需要编写或编辑eBPF汇编的语法,因此这很有用)。注意我们在程序末尾添加的无效指令。
除了字节码和汇编指令外,LLVM还可以嵌入调试符号,以便将其转储以进行检查。具体来说,我们可以将C指令与字节码同时使用。记住原始程序是很方便的,但是最重要的是了解C指令如何映射到eBPF代码非常有帮助。嵌入指令是通过从C编译并-g
传递给clang的标志来完成的。试一试吧:
$ clang -target bpf -g -S -o bpf.s bpf.c
$ llvm-mc -triple bpf -filetype=obj -o bpf.o bpf.s
$ llvm-objdump -S bpf.obpf.o: file format ELF64-BPFDisassembly of section .text:
func:
; int func() {0: b7 01 00 00 00 00 00 00 r1 = 01: 63 1a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r1
; return 0;2: bf 10 00 00 00 00 00 00 r0 = r13: 95 00 00 00 00 00 00 00 exit
请注意,我们传递-g
给clang
,并且还更改了传递给的命令(现在 -S
改为-d
)llvm-objdump
。该return 0;
指令出现,并映射(放置在eBPF程序中的相关指令上方)。好的。
内联汇编
由于clang和LLVM知道如何生成和编译eBPF程序集,因此存在另一种处理指令的方法。现在可以直接在C程序中内联使用eBPF程序集,再次在字节码中生成特定序列。请参阅以下示例,该示例在某种程度上受到Cilium的BPF和XDP参考指南中示例的启发。
$ cat inline_asm.c
int func()
{unsigned long long foobar = 2, r3 = 3, *foobar_addr = &foobar;asm volatile("lock *(u64 *)(%0+0) += %1" :"=r"(foobar_addr) :"r"(r3), "0"(foobar_addr));return foobar;
}$ clang -target bpf -Wall -O2 -c inline_asm.c -o inline_asm.o
$ llvm-objdump -d inline_asm.o
inline_asm.o: file format ELF64-BPFDisassembly of section .text:
func:0: b7 01 00 00 02 00 00 00 r1 = 21: 7b 1a f8 ff 00 00 00 00 *(u64 *)(r10 - 8) = r12: b7 01 00 00 03 00 00 00 r1 = 33: bf a2 00 00 00 00 00 00 r2 = r104: 07 02 00 00 f8 ff ff ff r2 += -85: db 12 00 00 00 00 00 00 lock *(u64 *)(r2 + 0) += r16: 79 a0 f8 ff 00 00 00 00 r0 = *(u64 *)(r10 - 8)7: 95 00 00 00 00 00 00 00 exit
它在r2指向的地址上产生值的原子增量。因为指令是用C源代码编写的,所以我们不需要中间步骤就可以进行汇编。
我们应该使用内联汇编还是中间编译?我认为这两种方法都很有用:在C源文件中以汇编形式插入几个指令,或者创建用于测试特定指令序列的小型程序。在Netronome,我们经常将后者用于单元测试,以检查nfp驱动程序的eBPF硬件卸载功能。
结论
简而言之,您无需将eBPF程序从C编译为ELF目标文件,而是可以将其编译为汇编语言,根据需要进行编辑,然后将此版本汇编为最终目标文件。为此,您需要6.0版或更高版本中的clang和LLVM,命令为:
$ clang -target bpf -S -o bpf.s bpf.c
$ llvm-mc -triple bpf -filetype=obj -o bpf.o foo.s
并以人类可读的格式转储该文件:
$ llvm-objdump -d bpf.o
$ llvm-objdump -S bpf.o # add C code, if -g was passed to clang
此外,该asm
关键字可用于在C程序中内联包括eBPF汇编程序。
LLVM中的eBPF程序集支持允许编写所需的任何eBPF指令序列。包括错误的程序。不要忘记:即使编译,它仍然必须通过验证程序。祝好运并玩得开心点!
当我完成本文时,现在也有一个GCC后端,但似乎没有clang / LLVM版本完整,后者显然仍然是产生eBPF字节码的参考工具。 ↩
有关目标以及与默认目标的区别的更多信息,请参见Cilium的BPF和XDP参考指南
bpf
。 ↩
带有LLVM的eBPF组件相关推荐
- 工作118:封装一个带有对话框的button组件
buttondialog.vue <!--定义一个有按钮的对话框 相当于dialog和按钮组合使用--> <template><!-- 有按钮的对话框 这个位置的代码会被 ...
- LLVM 核心类简明示例
<带有LLVM的eBPF组件> <The LLVM Compiler Infrastructure | LLVM编译器基础设施> <LLVM每日谈 | 知乎> &l ...
- react内联样式_React样式化的组件:内联样式+ 3种其他CSS样式化方法(带有示例)...
react内联样式 There's no one right way to style your React components. It all depends on how complex you ...
- eBPF.io eBPF文档:扩展的数据包过滤器(BPF)
目录 什么是eBPF? 安全 跟踪和分析 联网 可观察性与监控 什么是eBPF.io? eBPF简介 挂钩概述 eBPF程序如何编写? 加载程序和验证架构 地图 辅助呼叫 尾部和函数调用 eBP ...
- Cilium 1.7发布:Hubble UI、全集群网络策略、基于eBPF的Direct Server Return以及更多
在这里,我们要向大家高兴地宣布,Cilium 1.7版本正式发布了!在本轮更新周期当中,由141位开发者组成的项目社区共完成了1551项提交,而且很多朋友是第一次为Cilium项目提交贡献. Hubb ...
- 大规模微服务利器:eBPF + Kubernetes
hi, 大家好,微服务,云原生近来大热,在企业积极进行数字化转型,全面提升效率的今天,几乎无人否认云原生代表着云计算的"下一个时代",IT大厂们都不约而同的将其视为未来云应用的发展 ...
- 初识 eBPF(功能、原理、及一些应用)
非常棒的一些材料 当eBPF遇上Linux内核网络 什么是 eBPF? 待看 基于eBPF监控和排查云原生环境中的磁盘IO性能问题 深度解密基于 eBPF 的 Kubernetes 问题排查全景图 e ...
- 大规模微服务利器:eBPF 与 Kubernetes
Daniel 是 eBPF 两位 maintainer 之一,目前在 eBPF commits 榜单上排名第一,也是 Cilium 的核心开发者之一. 本文内容的时间跨度有 8 年,覆盖了 eBPF ...
- 初步了解React Native的新组件库firstBorn
first-born is a React Native UI Component Framework, which follows the design methodology Atomic Des ...
最新文章
- 数组中的第k个最大元素—leetcode215
- java floatmath_《Java1.doc
- redis value多大会影响性能_选择合适Redis数据结构,减少80%的内存占用
- java计算距离_java实现计算地理坐标之间的距离
- (3)分布式下的爬虫Scrapy应该如何做-递归爬取方式,数据输出方式以及数据库链接...
- 计算机知识点汇总职高,计算机辅导(知识点汇总) - 慈溪职高 网站首页.doc
- /usr/include/features.h:356:25: 致命错误: sys/cdefs.h:没有那个文件或目录
- 发电机变压器运行状态(温度电压电流)监控系统解决方案
- 国产CAM究竟水平如何?看完测试我震惊了
- Android之离线词典
- Spotfire 常用数据类型
- 【单例模式、多例模式、枚举、工厂模式】
- Linux面试题及答案
- 第一P2P收购中国典当联盟发力供应链金融模式
- poi操作word,写入一个图片,并且设置其大小,以及图片和base64之间的互相转换,以及表格内容替换和插入
- win7系统盘瘦身秘诀
- 中国移动--九天毕昇平台使用测试(薅Telsa V100)
- 询问HTG:添加PDF打印机,隐藏Windows登录名和共享USB HDD
- 谷粒商城项目笔记总结(2/2)
- STM32系列单片机USB下载程序(ISP编程)
热门文章
- React-native集成tfs自动发版问题
- pyspark对应的scala代码PythonRDD类
- 【FZU2178】礼物分配
- 一站式WPF--依赖属性(DependencyProperty)
- Android新手入门2016(14)--FragmentTabHost实现选项卡和菜单
- 15-传智书城后台程序设计
- mysql 分区 key 写法_MySQL KEY分区
- html 导出excel 乱码问题,Asp导出Excel乱码怎么办
- python数据预测_使用Python预测缺失值
- java做的web系统 m1 读卡器 结合_IE浏览器接入IC卡读写器实现M1卡的读写功能