GCC 内置函数 - 2003 年与 2019 年的行为
GCC builtin functions - 2003 vs 2019 behaviour
在 GCC 简介 一书的第 14 页,Brian Gough,由于没有为 gcc 提供 libm
库,作者想显示 linker 错误,函数 sqrt
的代码位于:
$ gcc -Wall calc.c -o calc
/tmp/ccbR6Ojm.o: In function ‘main’:
/tmp/ccbR6Ojm.o(.text+0x19): undefined reference to ‘sqrt’
文件calc.c
(调用函数sqrt
的地方)是这样的:
#include <math.h>
#include <stdio.h>
int main (void)
{
double x = sqrt (2.0);
printf ("The square root of 2.0 is %f\n", x);
return 0;
}
这本书是 2003 年的。
在我当前的 Ubuntu Linux 18 上,我无法重现 link 错误:它 link 并且有效,打印出正确的结果:
$ ./calc
1.414214
我发现 ldd calc
libm.so
共享库不会在运行时调用。当然这里也不涉及静态库libm.a
。
那么gcc是如何处理函数sqrt
的呢?我发现在这种情况下它使用 sqrt
GCC 内置函数。
它的代码在编译时被插入到 calc.o
目标文件中。所以没有 "undefined reference" 错误。
第一个问题:这就是整个故事,还是我遗漏了什么?
第二个问题:为什么这种关于 GCC 内置函数的行为在 2003 年(本书撰写时)和现在之间变化如此之大? (实际上使整个示例无效,在我看来)
第三个问题:为什么作者在他的例子中(例如$ gcc -Wall calc.c -lm -o cal
)暗示将使用静态库libc.a
,而实际上在 Linux 中,该语法调用动态库 libm.so
?这是否特定于 Linux 而不是 GNU GCC?我错过了什么?
我认为这是由于优化了一个常量值。现代 GCC 可以计算 sqrt (2.0)
的精确值。如果你强制它不使用 built-ins 和 -fno-builtin
,它仍然无法使用 link。此外,如果您稍微更改代码以使 sqrt()
的参数不是文字,它将无法 link:
#include <math.h>
#include <stdio.h>
double t = 2.0;
int main (void)
{
double x = sqrt (t);
printf ("The square root of 2.0 is %f\n", x);
return 0;
}
这会产生 link 错误:
> gcc -o test test.c
/usr/bin/ld: /tmp/ccLjHnQx.o: in function `main':
test.c:(.text+0x11): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
关于你的第 3 个问题,-lm
并不意味着静态库,AFAIK。
在 GCC 简介 一书的第 14 页,Brian Gough,由于没有为 gcc 提供 libm
库,作者想显示 linker 错误,函数 sqrt
的代码位于:
$ gcc -Wall calc.c -o calc
/tmp/ccbR6Ojm.o: In function ‘main’:
/tmp/ccbR6Ojm.o(.text+0x19): undefined reference to ‘sqrt’
文件calc.c
(调用函数sqrt
的地方)是这样的:
#include <math.h>
#include <stdio.h>
int main (void)
{
double x = sqrt (2.0);
printf ("The square root of 2.0 is %f\n", x);
return 0;
}
这本书是 2003 年的。 在我当前的 Ubuntu Linux 18 上,我无法重现 link 错误:它 link 并且有效,打印出正确的结果:
$ ./calc
1.414214
我发现 ldd calc
libm.so
共享库不会在运行时调用。当然这里也不涉及静态库libm.a
。
那么gcc是如何处理函数sqrt
的呢?我发现在这种情况下它使用 sqrt
GCC 内置函数。
它的代码在编译时被插入到 calc.o
目标文件中。所以没有 "undefined reference" 错误。
第一个问题:这就是整个故事,还是我遗漏了什么?
第二个问题:为什么这种关于 GCC 内置函数的行为在 2003 年(本书撰写时)和现在之间变化如此之大? (实际上使整个示例无效,在我看来)
第三个问题:为什么作者在他的例子中(例如$ gcc -Wall calc.c -lm -o cal
)暗示将使用静态库libc.a
,而实际上在 Linux 中,该语法调用动态库 libm.so
?这是否特定于 Linux 而不是 GNU GCC?我错过了什么?
我认为这是由于优化了一个常量值。现代 GCC 可以计算 sqrt (2.0)
的精确值。如果你强制它不使用 built-ins 和 -fno-builtin
,它仍然无法使用 link。此外,如果您稍微更改代码以使 sqrt()
的参数不是文字,它将无法 link:
#include <math.h>
#include <stdio.h>
double t = 2.0;
int main (void)
{
double x = sqrt (t);
printf ("The square root of 2.0 is %f\n", x);
return 0;
}
这会产生 link 错误:
> gcc -o test test.c
/usr/bin/ld: /tmp/ccLjHnQx.o: in function `main':
test.c:(.text+0x11): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
关于你的第 3 个问题,-lm
并不意味着静态库,AFAIK。