GCC内置函数-2003与2019行为

时间:2019-05-30 05:18:25

标签: gcc linker-errors built-in

Brian Gough 撰写的“ GCC简介 ”一书的第14页上,作者希望显示链接器错误,原因是没有为gcc提供libm库,函数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上,我无法重现链接错误:它可以链接并正常工作,并打印正确的结果:

$ ./calc
1.414214

我与ldd calc发现,libm.so共享库未在运行时调用。当然,这里也不涉及静态库libm.a。 那么gcc如何处理函数sqrt?我发现在这种情况下,它使用了sqrt GCC内置函数 。 其代码在编译时插入calc.o对象文件中。因此,没有“未定义的引用”错误。

第一个问题:整个故事还是我遗漏了什么?

第二个问题:为什么在2003年(撰写本书时)与现在之间有关GCC内置功能的这种行为发生了如此大的变化? (在我看来,实际上使整个示例无效)

第三个问题:作者为什么做他的示例(例如$ gcc -Wall calc.c -lm -o cal)暗示将使用静态库libc.a,而实际上在Linux中会调用语法动态库libm.so?这是特定于Linux而非GNU GCC吗?我在想什么?

1 个答案:

答案 0 :(得分:2)

我认为这是由于常数值的优化。现代GCC可以计算出sqrt (2.0)的精确值。如果您强制它不使用内置-fno-builtin的内置程序,它将仍然无法链接。另外,如果稍微更改代码以使sqrt()的参数不是文字的,它将无法链接:

#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;
}

这会产生链接错误:

> 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

关于第三个问题,-lm并不意味着静态库AFAIK。