Reputation: 1557
I have a program (main.c
):
#include <stdio.h>
#include <math.h>
int main() {
int result = sqrt(9);
printf("result: %d\n" ,result);
return 0;
}
double sqrt(double blah) {
return 0;
}
When I run this, my result is
result: 3
This would tell me the linker is choosing the libm
library's sqrt
function instead of mine to call in my main
function.
I don't get any errors or warnings when I compile this program with all warnings enabled:
gcc main.c -Wall
My questions:
sqrt
to call?
The only thing I can think of is when I run gcc --precompile
, I see this function declaration:
extern double sqrt(double);
Does this tell the linker that sqrt is defined outside of this file? And since this already satisfies the definition of sqrt
, my own definition is ignored when linking?
gcc info (I know it is really clang, since I am on mac, not sure if that makes a difference in terms of this question)
gcc --version
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.0 (clang-1100.0.33.17)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Edit:
The assembly output:
.section __TEXT,__text,regular,pure_instructions
.build_version macos, 10, 15 sdk_version 10, 15
.section __TEXT,__literal8,8byte_literals
.p2align 3 ## -- Begin function main
LCPI0_0:
.quad 4621256167635550208 ## double 9
.section __TEXT,__text,regular,pure_instructions
.globl _main
.p2align 4, 0x90
_main: ## @main
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $16, %rsp
movsd LCPI0_0(%rip), %xmm0 ## xmm0 = mem[0],zero
movl $0, -4(%rbp)
sqrtsd %xmm0, %xmm0
cvttsd2si %xmm0, %eax
movl %eax, -8(%rbp)
movl -8(%rbp), %esi
leaq L_.str(%rip), %rdi
movb $0, %al
callq _printf
xorl %esi, %esi
movl %eax, -12(%rbp) ## 4-byte Spill
movl %esi, %eax
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
## -- End function
.globl _sqrt ## -- Begin function sqrt
.p2align 4, 0x90
_sqrt: ## @sqrt
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
movsd %xmm0, -8(%rbp)
xorps %xmm0, %xmm0
popq %rbp
retq
.cfi_endproc
## -- End function
.section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "result: %d\n"
.subsections_via_symbols
Upvotes: 3
Views: 557
Reputation: 12708
There's a problem you have not acquainted for:
When you linked your executable, you specified -lm
in order to provide both versions of the sqrt()
function, the one you provided, and the libm.so
shared executable.
The problem is that the shared executable probably will take preference because linking is done at load time, your function is an instrinsic function, and the compiler has not resolved the reference before closing the compiled .o
. This makes the dynamic linker to select one of the functions at shared object loading time.
When there were no shared binaries, the sqrt()
function was indeed in a sqrt.o
file that was stored in libm.a
, and the linker selected only the binaries from the archive that were resolving some unresolved references, in that case, the sqrt.o
from libm.a
should have not been included, and your sqrt()
should have been referenced instead.
By the way, there's also an issue in how the compiler treats the sqrt()
function since the compiler accepts to support what is called an intrinsic function (as sqrt()
is) They normally take preference and so, you are somehow advised not to name your functions like the intrinsic ones. This aspect, which is very extended in FORTRAN, has not been an issue until now. The compiler treats completely different the intrinsic functions from others... and you will see that with other library functions doesn't happen.
You will see this thing to emerge as a warning from the compiler if you try to define sqrt()
as a different function (for example, an unsigned sqrt(unsigned n);
integer version of the square root) The compiler will emit a warning suggesting you to rename your function so you don't use the same name of an instrinsic function. I have not digged this deeply, but somehow, the compiler knows the existence of some functions before any definition is #include
d.
Upvotes: 1
Reputation: 224546
The names of standard C library function are reserved for use as identifiers with external linkage. You are not supposed to use them for your own functions. This means that when you use a reserved name, the compiler may assume it is the standard function, not your own implementation. Then, to optimize your program (even without full optimization turned on), the compiler may replace a call to sqrt
with the processor’s square root instruction. Or the compiler could even calculate the result itself and build that into the assembly code.
Upvotes: 3