Different behavior of linkage between Clang and GCC.
Different behavior of linkage for C and C++#
For the following program:
#include <math.h>
#include <stdio.h>
int main() {
printf("e^{1} = %f\n", exp(1));
return 0;
}
If we compile the program with clang test.c -o test
, compilation failed with
the following error:
/tmp/test-32c2ea.o: In function `main':
test.c:(.text+0x18): undefined reference to `exp'
clang-11: error: linker command failed with exit code 1 (use -v to see invocation)
This is totally expected since we use exp()
function here, which is
implemented in the shared object libm.so
. For clang
, the linker will not
link against libm.so
by default. In order to compile the program, we need to
explicitly link libm.so
:
clang test.c -lm -o test
One explanation for the separation of libm.so and libc.so is that in the early days of computing, floating point calculation is expensive. People use various workarounds for floating point calculations. It makes no sense to integrate math functions into libc.so. It makes libc.so larger with little benefit. As computer hardware upgrades with time, the separation of libm and libc does not make much sense any more.
However, if we translate the above program to C++:
#include <iostream>
#include <cmath>
int main() {
std::cout << "e^{1} = " << std:: exp(1) << std::endl;
return 0;
}
we can actually compile the program without linking against libm
:
clang++ test.cc -o test
The output of command ldd test
is:
> ldd test
linux-vdso.so.1 => (0x00007ffd009a4000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00002b4d4d13c000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00002b4d4d51f000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00002b4d4d828000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00002b4d4da40000)
/lib64/ld-linux-x86-64.so.2 (0x00002b4d4cf14000)
libm.so
is actually implicitly linked. According to post here,
for C++ programs, since libstdc++.so
requires libm.so
, so libm.so
will be
implicitly linked even if you haven’t instructed its linkage1.
Some libraries are linked by default.#
It is interesting that shared library like libc.so
2 is linked even if we
haven’t specified that. This behaviour can be disabled by providing the
-nostdlib
option:
clang -nostdlib test.c -o test
You will now see an error message about undefined printf()
:
test.c:(.text+0x29): undefined reference to `printf'
Ref:
Different between GCC and Clang on linkage#
You might think that GCC will also fail if we compile the test.c
without
linking libm
, but it is not true. The following command runs without
error for gcc 4.8.0 and 7.5.0 on my servers:
gcc test.c -o test
This is because GCC uses its built-in implementation of some standard C library
functions to produce faster and smaller executables. According to post here,
we can use -fno-builtin
to disable this behavior. We can also use
-fno-builtin-somefunc
to disable a single function named somefunc
. Take the
above test.c
for an example, the following command will result in compilation
error:
gcc -fno-builtin-sqrt test.c -o test
# adding -lm will fix the compilation errors.
# gcc -fno-builtin-sqrt test.c -lm -o test
Ref: