简体   繁体   中英

glibc uses kernel functions

I am trying to understand this method from the glibc source code:

    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

As far as I understand from here, if the program doesn't find a valid implementation for the sqrt function from glibc, it calls a hardware function, so a specific machine function, from the kernel. Is this right?
Also, what does libm_alias_float (__sqrt, sqrt) mean?

The GNU C Library's mathematical functions are fully implemented within the "glibc" source tree . They don't rely on the operating system kernel for anything. The word "kernel" in this context refers to a computational kernel — the core of some mathematical algorithm, the part you might want to write in hand-optimized assembly language.

The function __kernel_standard_f is badly named. It contains common code for handling errors in the math functions; it would be better to have named it something like __math_domain_error . In this case, __sqrtf calls __kernel_standard_f when its argument is negative; __kernel_standard_f will then take care of setting errno to EDOM , possibly calling the SVID matherr callback, and returning a NaN. (The mysterious code 126 tells __kernel_standard_f which function called it and why. The implementation of __kernel_standard_f is in sysdeps/ieee754/k_standardf.c and sysdeps/ieee754/k_standard.c .)

The condition _LIB_VERSION != _IEEE_ has to do with whether or not POSIX and/or SVID math error handling is enabled; modern mathematical algorithms would really rather just look for NaN in the result and not have the library waste time setting errno or calling matherr , so there's a mechanism to turn the latter two off.

If the argument to __sqrtf is not negative, it tail calls __ieee754_sqrtf , which performs the actual calculation of the square root. There are several alternative implementations of this function within the glibc source tree; its generic, C-only version is in sysdeps/ieee754/flt-32/e_sqrtf.c . (The names of the files that implement math functions are cryptic even by glibc's standards. I don't bother trying to understand them, I just do find sysdeps -name '*sqrtf*' or whatever.) This function also starts with logic to detect a negative argument (also zero, infinity, and NaN) and return the appropriate values, but it doesn't touch errno . If you want to understand the mathematical technique used to calculate square roots, this is the file to look at.

If you run the above find command yourself you will discover several other files named e_sqrtf.c ; these are all in directories named after specific CPUs, whose floating-point units have hardware support for computing square roots, so for instance sysdeps/x86_64/fpu/e_sqrt.c reads

double
__ieee754_sqrt (double x)
{
  double res;

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

  return res;
}

because the x86 sqrtsd instruction does the whole job.

Glibc's build process will select one of these files, instead of the generic C version, when building for one of these CPUs. This mechanism is complex and not completely documented, but the "Maintenance" appendix to the glibc manual , particularly its "Source Layout" and "Porting" sections, gives a decent overview of it.


libm_alias_float (__sqrt, sqrt) arranges for __sqrtf to also have the name sqrtf , but as a weak alias . This is necessary for standards compliance. Please ask a separate question if you want more detail.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM