Compiling

函式符號編譯後獲得’.part’後綴

  • December 4, 2015

在交叉編譯 Linux 核心 3.18.10 時,編譯器會.part.<N>在一些符號的末尾添加一個後綴(參見下面的範例)。<N>使用不同的 defconfigs 時,數字會發生變化。有誰知道編譯器在什麼條件下在符號末尾添加部分後綴?

$ arm-none-linux-gnueabi-readelf -a vmlinux | grep do_kernel_fault

c03a48f8 116 FUNC LOCAL DEFAULT 2 __do_kernel_fault.part.10

結尾的符號.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_namein 中的函式生成gcc/cgraphclones.c。後面加的數字.part沒有特別的意義,只是用來防止名字衝突。這是一個簡單的計數器,每次 GCC 從某個現有函式(GCC 的開發人員稱之為“複製”)創建一個新函式時,它都會遞增。

您可以使用該選項-fdisable-ipa-fnsplit來阻止編譯器應用此優化,或-fenable-ipa-fnsplit啟用它。預設情況下,它在優化級別應用,-O2否則-O3禁用。

引用自:https://unix.stackexchange.com/questions/223013