PDA

View Full Version : [SOLVED] C ... strange undefined reference problem



donsy
February 27th, 2011, 07:54 PM
This program compiles and executes fine:

#include <stdio.h>
#include <math.h>

int main(int argc, char **argv)
{
const double base = 16.0;
double value = 0.0;

value = pow(base, 2);
printf("%g\n", value);
return 0;
}
But when I compile this one I get an udefined reference error, note that the only difference is pow(base, 4) instead of pow(base, 2):

#include <stdio.h>
#include <math.h>

int main(int argc, char **argv)
{
const double base = 16.0;
double value = 0.0;

value = pow(base, 4);
printf("%g\n", value);
return 0;
}Here's compile command and resulting error:

$ gcc try.c
/tmp/ccNLOaCV.o: In function `main':
try.c:(.text+0x2b): undefined reference to `pow'
collect2: ld returned 1 exit status

johnl
February 27th, 2011, 08:10 PM
In either case, you need to link to the math library, by passing -lm to gcc.

I would suspect that gcc is optimizing pow(base, 2) to base * base, resulting in the first working because there is no need to pull in pow() from the math library.


Edit confirmed; if you examine the assembly generated with gcc -S you will see the in the first case there is an fmul done, while in the second case, there is a call pow.

MadCow108
February 27th, 2011, 08:16 PM
In either case, you need to link to the math library, by passing -lm to gcc.

I would suspect that gcc is optimizing pow(base, 2) to base * base, resulting in the first working because there is no need to pull in pow() from the math library.

your suspicion is correct:

value = pow(base, 2);
40051a: f2 0f 10 45 f8 movsd -0x8(%rbp),%xmm0
40051f: f2 0f 59 c0 mulsd %xmm0,%xmm0
400523: f2 0f 11 45 f0 movsd %xmm0,-0x10(%rbp)


value = pow(base, 4);
4005ba: f2 0f 10 0d 36 01 00 movsd 0x136(%rip),%xmm1 # 4006f8 <_IO_stdin_used+0x10>
4005c1: 00
4005c2: f2 0f 10 45 f8 movsd -0x8(%rbp),%xmm0
4005c7: e8 d4 fe ff ff callq 4004a0 <pow@plt>
4005cc: f2 0f 11 45 d8 movsd %xmm0,-0x28(%rbp)
4005d1: 48 8b 45 d8 mov -0x28(%rbp),%rax
4005d5: 48 89 45 f0 mov %rax,-0x10(%rbp)

donsy
February 27th, 2011, 08:23 PM
In either case, you need to link to the math library, by passing -lm to gcc.

I would suspect that gcc is optimizing pow(base, 2) to base * base, resulting in the first working because there is no need to pull in pow() from the math library.


Edit confirmed; if you examine the assembly generated with gcc -S you will see the in the first case there is an fmul done, while in the second case, there is a call pow.


your suspicion is correct:

value = pow(base, 2);
40051a: f2 0f 10 45 f8 movsd -0x8(%rbp),%xmm0
40051f: f2 0f 59 c0 mulsd %xmm0,%xmm0
400523: f2 0f 11 45 f0 movsd %xmm0,-0x10(%rbp)
value = pow(base, 4);
4005ba: f2 0f 10 0d 36 01 00 movsd 0x136(%rip),%xmm1 # 4006f8 <_IO_stdin_used+0x10>
4005c1: 00
4005c2: f2 0f 10 45 f8 movsd -0x8(%rbp),%xmm0
4005c7: e8 d4 fe ff ff callq 4004a0 <pow@plt>
4005cc: f2 0f 11 45 d8 movsd %xmm0,-0x28(%rbp)
4005d1: 48 8b 45 d8 mov -0x28(%rbp),%rax
4005d5: 48 89 45 f0 mov %rax,-0x10(%rbp)


Then why does this work?

#include <stdio.h>
#include <math.h>

#define BASE 16.0

int main(int argc, char **argv)
{
double value = 0.0;

value = pow(BASE, 50);
printf("%g\n", value);
return 0;
}

johnl
February 27th, 2011, 08:31 PM
Then why does this work?

#include <stdio.h>
#include <math.h>

#define BASE 16.0

int main(int argc, char **argv)
{
double value = 0.0;

value = pow(BASE, 50);
printf("%g\n", value);
return 0;
}


Because you are passing literals to pow(). You're doing:



x = pow(16.0, 50)


the result of this is never going to change, so it's an obvious optimization; gcc will calculate the result at compile time and omit the call to pow().

Here's my advice: stop worrying about it, let gcc do it's optimization thing, and link against the math library (-lm) when you use a math function in your code, regardless of whether it's optimized out or not.