函数符号编译后带有“.part”后缀

函数符号编译后带有“.part”后缀

当交叉编译Linux内核3.18.10时,编译器会.part.<N>在一些符号末尾添加后缀(请参见下面的示例)。<N>使用不同的 defconfig 时,数字会发生变化。有谁知道编译器在什么条件下在符号末尾添加部分后缀?

$ arm-none-linux-gnueabi-readelf -a vmlinux | grep do_kernel_fault
给出
c03a48f8 116 FUNC LOCAL DEFAULT 2 __do_kernel_fault.part.10

答案1

以 结尾的符号.part是真正的功能符号,而不是某种功能装饰。更准确地说,以 结尾的函数.part是 GCC 从更大的函数生成的函数。

有时,GCC 评估大函数的控制流的某些部分可以很容易地内联,但内联整个大函数是不行的。因此,它拆分函数,将大部分放在自己的函数中,该函数接收原始函数名称加.part+作为名称.<some number>,并将其余部分内联到其他函数中。

这是 GCC 源代码中描述的优化的一部分,位于gcc/ipa-split.c.至少在 gcc-4.8.3 中(可能还有更高版本,我现在无法检查),它说:

/* The purpose of this pass is to split function bodies to improve
   inlining.  I.e. for function of the form:

   func (...)
     {
       if (cheap_test)
   something_small
       else
   something_big
     }

   Produce:

   func.part (...)
     {
  something_big
     }

   func (...)
     {
       if (cheap_test)
   something_small
       else
   func.part (...);
     }

   When func becomes inlinable and when cheap_test is often true, inlining func,
   but not fund.part leads to performance improvement similar as inlining
   original func while the code size growth is smaller.

   The pass is organized in three stages:
   1) Collect local info about basic block into BB_INFO structure and
      compute function body estimated size and time.
   2) Via DFS walk find all possible basic blocks where we can split
      and chose best one.
   3) If split point is found, split at the specified BB by creating a clone
      and updating function to call it.  

   The decisions what functions to split are in execute_split_functions
   and consider_split.  

   There are several possible future improvements for this pass including:

   1) Splitting to break up large functions
   2) Splitting to reduce stack frame usage
   3) Allow split part of function to use values computed in the header part.
      The values needs to be passed to split function, perhaps via same
      interface as for nested functions or as argument.
   4) Support for simple rematerialization.  I.e. when split part use
      value computed in header from function parameter in very cheap way, we
      can just recompute it.
   5) Support splitting of nested functions.
   6) Support non-SSA arguments.  
   7) There is nothing preventing us from producing multiple parts of single function
      when needed or splitting also the parts.  */

正如您可能已经猜到的,这个过程完全由编译器控制。新的符号名称由clone_function_name中的函数生成gcc/cgraphclones.c。后面添加的数字.part没有特殊含义,只是为了防止名字冲突。这是一个简单的计数器,每次 GCC 从某个现有函数创建新函数(GCC 开发者称之为“克隆”)时,该计数器就会递增。

您可以使用该选项-fdisable-ipa-fnsplit来阻止编译器应用此优化,或-fenable-ipa-fnsplit启用它。默认情况下,它在优化级别应用-O2-O3否则禁用。

相关内容