来自bpf手册页:
eBPF程序可以用经过编译的受限C编写
(使用clang编译器)进入eBPF字节码。各种功能包括
从这个受限的C中省略,比如循环,全局变量,
变量函数、浮点数和将结构作为
函数参数。
但是手册页没有更新。我想知道当使用受限C编写eBPF程序时,到底什么是被禁止的?手册上说的是真的吗?
最佳答案
实际上,在ELF文件中“允许”什么并不重要。这句话的意思是,一旦编译成eBPF指令,您的C代码可能会生成被验证器拒绝的代码。例如,BPF程序中的循环在BPF程序中早就被拒绝了,因为无法保证它们会终止(唯一的解决方法是在编译时展开它们)。
所以你基本上可以在C中使用你想要的任何东西,并成功地生成一个ELF对象文件。但你想让它通过验证器。哪些组件肯定会导致验证者抱怨?让我们从手册页查看列表:
循环:Linux5.3版引入了对有界循环的支持,因此循环在某种程度上起作用。“有界循环”是指验证器有办法告诉它们最终将完成的循环:通常,for (i = 0; i < CONSTANT; i++)
类循环应该可以工作(假设i
在块中没有修改)。
全局变量:最近有一些支持全局变量的工作,但是它们是以特定的方式处理的(作为单条目映射),我并没有真正地对它们进行实验,所以我不知道这有多透明,也不知道是否可以在程序中简单地定义全局变量。请随意尝试:)。
变量函数:很确定这是不受支持的,我不知道这在eBPF中是如何翻译的。
浮点数:仍不支持。
将结构作为函数参数传递:不支持,但我认为将指针传递到结构应该可以工作。
如果你对这一级别的细节感兴趣,你真的应该看看Cilium's documentation on BPF。它并不完全是最新的(只缺少非常新的功能),但比手册页更完整和准确。尤其是,the LLVM section有一个在编译为eBPF的C程序中应该或不应该工作的项的列表。除了上述项目外,他们还引用了:
(所有函数都需要内联,没有函数调用)->这个已经过时了,BPF有函数调用。
没有共享库调用:这是真的。不能调用标准库中的函数或其他BPF程序中定义的函数。您只能调用在同一个BPF程序中定义的函数,或者在内核中实现的BPF帮助程序,或者执行“tail calls”。
例外:可以使用memset()
/memcpy()
/memmove()
/memcmp()
的LLVM内置函数(我认为它们几乎是您可以调用的唯一函数,而不是BPF帮助程序和其他BPF函数)。
不允许使用常量字符串或数组(因为它们在ELF文件中是如何处理的):我认为这在今天仍然有效?
BPF程序堆栈被限制为512字节,因此C程序不能导致试图使用更多字节的可执行文件。
列出了其他允许或良好的了解项目。我只能鼓励你潜入其中!