glibc使用内核函数

Joh*_*nas 2 c

我试图从glibc源代码中了解此方法:

    26 #if LIBM_SVID_COMPAT
    27 /* wrapper sqrtf */
    28 float
    29 __sqrtf (float x)
    30 {
    31   if (__builtin_expect (isless (x, 0.0f), 0) && _LIB_VERSION     != _IEEE_)
    32     return __kernel_standard_f (x, x, 126); /*    sqrt(negative) */
    33 
    34   return __ieee754_sqrtf (x);
    35 }
    36 libm_alias_float (__sqrt, sqrt)
    37 #endif
Run Code Online (Sandbox Code Playgroud)

据我了解,如果程序没有sqrt从glibc中找到该函数的有效实现,它将从内核调用硬件函数,即特定的机器函数。这是正确的吗?
还有,这libm_alias_float (__sqrt, sqrt)是什么意思?

zwo*_*wol 6

GNU C库的数学功能在“ glibc”源代码树中完全实现。他们什么都不依赖操作系统内核。在此上下文中,“内核”一词指的是计算内核,这是某些数学算法的核心,您可能想用手工优化的汇编语言编写该部分。

该函数__kernel_standard_f名称错误。它包含用于处理数学函数错误的通用代码。最好将其命名为__math_domain_error。在这种情况下,当其参数为负数时__sqrtf调用__kernel_standard_f__kernel_standard_f然后将注意设置errnoEDOM,可能会调用SVID matherr回调,并返回NaN。(神秘代码126告诉__kernel_standard_f哪个函数调用它,以及为什么。它的实现__kernel_standard_fsysdeps/ieee754/k_standardf.c和中sysdeps/ieee754/k_standard.c。)

条件_LIB_VERSION != _IEEE_与是否启用POSIX和/或SVID数学错误处理有关;现代数学算法实际上只希望在结果中查找NaN而不需要设置errno或调用库浪费时间matherr,因此有一种机制可以将后两者关闭。

如果参数__sqrtf否定的,则尾部的呼叫__ieee754_sqrtf,其执行平方根的实际计算。glibc源代码树中有此功能的几种替代实现。其通用的仅C版本在中sysdeps/ieee754/flt-32/e_sqrtf.c。(即使按照glibc的标准,实现数学功能的文件的名称也是神秘的。我不必费力去理解它们,我只是做find sysdeps -name '*sqrtf*'任何事情。)此函数从检测否定参数(也为零,无穷大)的逻辑开始,和NaN)并返回适当的值,但它不会触及errno。如果您想了解用于计算平方根的数学技术,请查看此文件。

如果您find自己运行上述命令,则会发现其他几个名为的文件e_sqrtf.c。这些都在以特定CPU命名的目录中,这些CPU的浮点单元具有对计算平方根的硬件支持,因此例如sysdeps/x86_64/fpu/e_sqrt.c读取

double
__ieee754_sqrt (double x)
{
  double res;

  asm ("sqrtsd %1, %0" : "=x" (res) : "xm" (x));

  return res;
}
Run Code Online (Sandbox Code Playgroud)

因为x86 sqrtsd指令可以完成全部工作。

当为其中一个CPU进行构建时,Glibc的构建过程将选择这些文件之一,而不是通用C版本。这种机制很复杂,没有完整记录,但是glibc手册的“维护”附录,特别是其“源布局”和“移植”部分,对它进行了详尽的介绍。


libm_alias_float (__sqrt, sqrt)安排__sqrtf也有名字sqrtf,但作为弱别名。为了符合标准,这是必需的。如果您需要更多详细信息,请问一个单独的问题。