glibc 中 "cold" 函数的源代码在哪里?

Where is source code for "cold" functions located in glibc?

我在 C:

中有一个 hello world 程序
#include <stdio.h>

int main() {
    printf("Hello world!\n");
    return 0;
}

编译它gcc -static hello.c -o hello

readelf -a --wide hello 中我发现了一些带有 cold postfix

的函数
__assert_fail_base.cold
_nl_load_domain.cold
_IO_new_fclose.cold
_IO_fflush.cold
_IO_puts.cold
_IO_wfile_underflow.cold
_IO_new_file_underflow.cold
_IO_fputs.cold
_IO_fwrite.cold
_IO_getdelim.cold
__printf_fp_l.cold
__printf_fphex.cold
read_encoded_value_with_base.cold
base_of_encoded_value.cold
execute_cfa_program.cold
uw_frame_state_for.cold
uw_install_context_1.cold
execute_stack_op.cold
uw_update_context_1.cold
uw_init_context_1.cold
uw_update_context.cold
_Unwind_RaiseException_Phase2.cold
_Unwind_GetGR.cold
_Unwind_SetGR.cold
_Unwind_Resume.cold
_Unwind_Resume_or_Rethrow.cold
size_of_encoded_value.cold
base_from_object.cold
base_from_cb_data.cold
read_encoded_value_with_base.cold
_Unwind_IteratePhdrCallback.cold
search_object.cold
base_of_encoded_value.cold
read_encoded_value_with_base.cold

来自 here:

The cold attribute on functions is used to inform the compiler that the function is unlikely to be executed. The function is optimized for size rather than speed and on many targets it is placed into a special subsection of the text section so all cold functions appear close together, improving code locality of non-cold parts of program. The paths leading to calls of cold functions within code are marked as unlikely by the branch prediction mechanism. It is thus useful to mark functions used to handle unlikely conditions, such as perror, as cold to improve optimization of hot functions that do call marked functions in rare occasions.

When profile feedback is available, via -fprofile-use, cold functions are automatically detected and this attribute is ignored.

根据我 download glibc 并切换到指向我的版本 git rev-list -n 1 $(git tag | grep 2.31-0ubuntu9.7) 的提交 160f6c36a374841ee6e2bf2ee0ba05b70634978e,但是在所有这些操作之后我找不到上面标有属性.

我知道 glibc 会生成一些系统调用,但我在 glibc/sysdeps/unix/syscalls.list.

中找不到任何对我来说有趣的函数

我还从 libc.a:

中提取了 cold 函数
cd /usr/lib/x86_64-linux-gnu/
readelf -a --wide libc.a | egrep '\.cold' | awk '{print $NF}' > libc.a.cold

并将它们与 readelf -a --wide hello | egrep '\.cold' | awk '{print $NF}' > hello.readelf 进行比较:

grep -f libc.a.cold hello.readelf

这些是匹配的函数:

__assert_fail_base.cold
_nl_load_domain.cold
_IO_new_fclose.cold
_IO_fflush.cold
_IO_puts.cold
_IO_wfile_underflow.cold
_IO_new_file_underflow.cold
_IO_fputs.cold
_IO_fwrite.cold
_IO_getdelim.cold
__printf_fp_l.cold
__printf_fphex.cold

并且 grep -f libc.a.cold hello.readelf -v 我发现了无与伦比的功能:

read_encoded_value_with_base.cold
base_of_encoded_value.cold
execute_cfa_program.cold
uw_frame_state_for.cold
uw_install_context_1.cold
execute_stack_op.cold
uw_update_context_1.cold
uw_init_context_1.cold
uw_update_context.cold
_Unwind_RaiseException_Phase2.cold
_Unwind_GetGR.cold
_Unwind_SetGR.cold
_Unwind_Resume.cold
_Unwind_Resume_or_Rethrow.cold
size_of_encoded_value.cold
base_from_object.cold
base_from_cb_data.cold
read_encoded_value_with_base.cold
_Unwind_IteratePhdrCallback.cold
search_object.cold
base_of_encoded_value.cold
read_encoded_value_with_base.cold

问题:

  1. 谁能帮我弄清楚在哪里可以找到 cold 函数的源代码?
  2. 来自 libc.ahello 二进制文件的不匹配函数的源代码在哪里,它们是从哪个库加载的?

版本:

where I can find a source code of cold functions?

在 glibc 源代码中。

I cannot find any functions from above marked with cold atribute

这很奇怪,简单 grep -R 就足够了,但您可能对代码索引感兴趣 - clangd、GLOBAL 标签、ctags 等。您可以对 the_silver_searcher 感兴趣,以便更快 grep.

$ git clone git://git.launchpad.net/ubuntu/+source/glibc
Cloning into 'glibc'...
...
$ cd glibc/
$ grep -R --include '*.c' __assert_fail_base
assert/assert.c:__assert_fail_base (const char *fmt, const char *assertion, const char *file,
assert/assert.c:  __assert_fail_base (_("%s%s%s:%u: %s%sAssertion `%s' failed.\n%n"),
assert/assert-perr.c:  __assert_fail_base (_("%s%s%s:%u: %s%sUnexpected error: %s.\n%n"),

所以__assert_fail_base定义在assert/assert.c中。您可以为每个函数重复该过程。

但在 google 中键入函数或在 github 上找到项目并在那里搜索要简单得多。还有 https://code.woboq.org/ ,这使得任务变得微不足道。

Where is located source code of unmatched functions from libc.a and hello binary and from which library they loads?

里面看起来像 libgcc and the Unwind most probably in gcc libstdc++

函数不一定必须使用 __attribute__((cold)) 标记为冷函数才能让 GCC 意识到它们是“冷的”。当启用适当的优化时,GCC 可以并且将自行完成此操作。

特别是从 GCC 的优化文档中引用:

-freorder-blocks-and-partition

In addition to reordering basic blocks in the compiled function, in order to reduce number of taken branches, partitions hot and cold basic blocks into separate sections of the assembly and .o files, to improve paging and cache locality performance.

This optimization is automatically turned off in the presence of exception handling or unwind tables (on targets using setjump/longjump or target specific scheme), for linkonce sections, for functions with a user-defined section attribute and on any architecture that does not support named sections. When -fsplit-stack is used this option is not enabled by default (to avoid linker errors), but may be enabled explicitly (if using a working linker).

Enabled for x86 at levels -O2, -O3, -Os.

如您所见,此优化在 -O2-O3-Os 上默认启用。

何时可以应用这种自动优化的一个简单示例将是如下情况:

void parent_function(int x) {
    if (__builtin_expect(x == 1337, 1)) {
        some_function(123);
    } else {
        some_function(456);
    }

    // ...
}

GCC可以将some_function(甚至parent_function)拆分为some_functionsome_function.cold,简化了函数的内部逻辑。因此,在您的情况下,您在编译后的二进制文件中看到的那些 .cold 函数实际上 不是 在源代码中定义的,而是由 GCC 自动生成的。