我编写了一个BPF目标文件,其中包括一个部分和一个静态内联函数,其定义如下:
static inline __attribute__((always_inline)) bpf_call_func(...);
__section("entry") bpf_func(...); // called bpf_call_func
效果很好,当我使用 llvm-objdump 时,它显示
bpf_call_func
已经被内联了。
但是当我在同一个目标文件中定义另一个部分并调用
bpf_call_func
static inline __attribute__((always_inline)) bpf_call_func(...);
__section("entry") bpf_func(...); // called bpf_call_func
__section("entry2") bpf_func2(...); // called bpf_call_func
llvm-objdump 显示
bpf_call_func
没有内联到 bpf_func
和 bpf_func2
中。它只是在.text
部分定义,bpf_func
和bpf_func2
使用call
指令来调用bpf_call_func
。
bpf_call_func
大约有 600 条指令。 bpf_func
和 bpf_func
大约有 250 条指令。
我查看了 gcc 手册,它说:
请注意,函数定义中的某些用法可能使其不适合内联替换。这些用法包括:可变参数函数、alloca 的使用、计算 goto 的使用(请参阅作为值的标签)、非局部 goto 的使用、嵌套函数的使用、setjmp 的使用、__builtin_longjmp 的使用以及 __builtin_return 或 __builtin_apply_args 的使用。当无法替换标记为内联的函数时,使用 -Winline 会发出警告,并给出失败的原因。
但我不知道哪个条件符合我的情况。
我想知道为什么当两个部分调用它时
bpf_call_func
不内联?
和bpf_call_func
的指令编号有关系吗?
据我所知,没有办法真正强制 clang 内联函数,这是 clang 的always_inline 参考:
内联启发法被禁用,并且无论优化级别如何,始终尝试内联。
不保证内联替换实际发生。
这似乎是一件铿锵的事情,因为GCC声明它将始终像属性建议的那样内联,或者抛出错误(对于单元内的调用):
始终内联
通常,除非指定优化,否则函数不会内联。对于声明为内联的函数,此属性内联函数独立于任何其他适用于内联的限制。未能内联此类函数将被诊断为错误。请注意,如果间接调用此类函数,编译器可能会或可能不会内联它,具体取决于优化级别,并且可能会或可能不会诊断内联间接调用的失败。
GCC 提供了一个
-Winline
标志,因此编译器会警告未内联的函数,但 clang 会忽略这一点:
-Winline
此诊断标志的存在是为了兼容 GCC,在 Clang 中没有任何作用。
因此,clang 似乎将always_inline 属性视为提示,并且很乐意在没有错误或警告的情况下不内联函数。在你的情况下,它可能决定你的内联函数太大。
公平地说,除非您需要支持低于 4.16 的内核,否则这并不重要,因为 eBPF 现在支持函数调用。