12

I am having a strange problem.

The math libraries has been added to my makefile.

# include standard C library
LDFLAGS += -lc
# include standard math library
LDFLAGS += -lm

and in the output file (.map) I can see that everything has been linked properly:

LOAD c:/gnu/powerpc-eabi/3pp.ronetix.powerpc-eabi/bin/../lib/gcc/powerpc-eabi/4.3.3/nof\libgcc.a
LOAD c:/gnu/powerpc-eabi/3pp.ronetix.powerpc-eabi/bin/../lib/gcc/powerpc-eabi/4.3.3/../../../../powerpc-eabi/lib/nof\libc.a
LOAD c:/gnu/powerpc-eabi/3pp.ronetix.powerpc-eabi/bin/../lib/gcc/powerpc-eabi/4.3.3/../../../../powerpc-eabi/lib/nof\libm.a

when I do

z = pow((double) 2, (double) 3);

it works fine. But if I test another function like:

double result = asin(x);

I´ll get:

undefined reference to `asin'
collect2: ld returned 1 exit status

How can this be? both pow and asin are available in math.h, see below:

/* Non reentrant ANSI C functions.  */

#ifndef _REENT_ONLY
#ifndef __math_6881
extern double acos _PARAMS((double));
extern double asin _PARAMS((double));
extern double atan2 _PARAMS((double, double));
extern double cosh _PARAMS((double));
extern double sinh _PARAMS((double));
extern double exp _PARAMS((double));
extern double ldexp _PARAMS((double, int));
extern double log _PARAMS((double));
extern double log10 _PARAMS((double));
extern double pow _PARAMS((double, double));
extern double sqrt _PARAMS((double));
extern double fmod _PARAMS((double, double));
#endif /* ! defined (__math_68881) */
#endif /* ! defined (_REENT_ONLY) */

how can one work and the other one generate linker issue? If I run -nm on libm.a I´ll get the following result: (sorry for the huge output, I have only copied the sections with the word sin)

lib_a-e_asin.o:
         U __adddf3
         U __divdf3
         U __gtdf2
00000000 T __ieee754_asin
         U __ieee754_sqrt
         U __muldf3
         U __subdf3
         U fabs

lib_a-e_j0.o:
         U __adddf3
         U __divdf3
         U __gtdf2
00000470 T __ieee754_j0
         U __ieee754_log
         U __ieee754_sqrt
000009b8 T __ieee754_y0
         U __ltdf2
         U __muldf3
         U __subdf3
         U cos
         U fabs
000000b0 r pR2
00000108 r pR3
00000058 r pR5
00000000 r pR8
000000e0 r pS2
00000138 r pS3
00000088 r pS5
00000030 r pS8
00000004 t pzero
00000220 r qR2
00000280 r qR3
000001c0 r qR5
00000160 r qR8
00000250 r qS2
000002b0 r qS3
000001f0 r qS5
00000190 r qS8
00000218 t qzero
         U sin

lib_a-e_j1.o:
         U __adddf3
         U __divdf3
         U __gtdf2
00000470 T __ieee754_j1
         U __ieee754_log
         U __ieee754_sqrt
00000950 T __ieee754_y1
         U __muldf3
         U __subdf3
         U cos
         U fabs
00000004 t pone
000000b0 r pr2
00000108 r pr3
00000058 r pr5
00000000 r pr8
000000e0 r ps2
00000138 r ps3
00000088 r ps5
00000030 r ps8
00000218 t qone
00000220 r qr2
00000280 r qr3
000001c0 r qr5
00000160 r qr8
00000250 r qs2
000002b0 r qs3
000001f0 r qs5
00000190 r qs8
         U sin

lib_a-e_jn.o:
         U __adddf3
         U __divdf3
         U __floatsidf
         U __gedf2
         U __gtdf2
         U __ieee754_j0
         U __ieee754_j1
00000434 T __ieee754_jn
         U __ieee754_log
         U __ieee754_sqrt
         U __ieee754_y0
         U __ieee754_y1
00000000 T __ieee754_yn
         U __ltdf2
         U __muldf3
         U __subdf3
         U cos
         U fabs
         U sin


lib_a-e_sinh.o:
         U __adddf3
         U __divdf3
         U __gtdf2
         U __ieee754_exp
00000000 T __ieee754_sinh
         U __muldf3
         U __subdf3
         U expm1
         U fabs


lib_a-ef_asin.o:
         U __addsf3
         U __divsf3
         U __gtsf2
00000000 T __ieee754_asinf
         U __ieee754_sqrtf
         U __mulsf3
         U __subsf3
         U fabsf


lib_a-ef_j0.o:
         U __addsf3
         U __divsf3
         U __gtsf2
0000035c T __ieee754_j0f
         U __ieee754_logf
         U __ieee754_sqrtf
000006cc T __ieee754_y0f
         U __ltsf2
         U __mulsf3
         U __subsf3
         U cosf
         U fabsf
00000058 r pR2
00000084 r pR3
0000002c r pR5
00000000 r pR8
00000070 r pS2
0000009c r pS3
00000044 r pS5
00000018 r pS8
00000004 t pzerof
00000110 r qR2
00000140 r qR3
000000e0 r qR5
000000b0 r qR8
00000128 r qS2
00000158 r qS3
000000f8 r qS5
000000c8 r qS8
000001a0 t qzerof
         U sinf

lib_a-ef_j1.o:
         U __addsf3
         U __divsf3
         U __gtsf2
0000031c T __ieee754_j1f
         U __ieee754_logf
         U __ieee754_sqrtf
0000062c T __ieee754_y1f
         U __mulsf3
         U __subsf3
         U cosf
         U fabsf
00000004 t ponef
00000058 r pr2
00000084 r pr3
0000002c r pr5
00000000 r pr8
00000070 r ps2
0000009c r ps3
00000044 r ps5
00000018 r ps8
000001a0 t qonef
000000b0 r qr2
000000e0 r qr8
000000c8 r qs2
000000f8 r qs8
         U sinf

lib_a-ef_sinh.o:
         U __addsf3
         U __divsf3
         U __gtsf2
         U __ieee754_expf
00000000 T __ieee754_sinhf
         U __mulsf3
         U __subsf3
         U expm1f
         U fabsf

lib_a-er_lgamma.o:
         U __adddf3
         U __divdf3
         U __eqdf2
         U __fixdfsi
         U __floatsidf
00000004 T __ieee754_lgamma_r
         U __ieee754_log
         U __kernel_cos
         U __kernel_sin
         U __ltdf2
         U __muldf3
         U __nedf2
         U __subdf3
         U fabs
         U floor


lib_a-erf_lgamma.o:
         U __addsf3
         U __divsf3
         U __eqsf2
         U __fixsfsi
         U __floatsisf
00000004 T __ieee754_lgammaf_r
         U __ieee754_logf
         U __kernel_cosf
         U __kernel_sinf
         U __ltsf2
         U __mulsf3
         U __nesf2
         U __subsf3
         U fabsf
         U floorf

lib_a-k_sin.o:
         U __adddf3
         U __fixdfsi
00000000 T __kernel_sin
         U __muldf3
         U __subdf3

lib_a-kf_sin.o:
         U __addsf3
         U __fixsfsi
00000000 T __kernel_sinf
         U __mulsf3
         U __subsf3

lib_a-s_asinh.o:
         U __adddf3
         U __divdf3
         U __gtdf2
         U __ieee754_log
         U __ieee754_sqrt
         U __muldf3
00000000 T asinh
         U fabs
         U log1p

lib_a-s_cos.o:
         U __ieee754_rem_pio2
         U __kernel_cos
         U __kernel_sin
         U __subdf3
00000000 T cos

lib_a-s_isinf.o:
00000000 T isinf

lib_a-s_isinfd.o:
00000000 T __isinfd

lib_a-s_sin.o:
         U __ieee754_rem_pio2
         U __kernel_cos
         U __kernel_sin
         U __subdf3
00000000 T sin

lib_a-sf_asinh.o:
         U __addsf3
         U __divsf3
         U __gtsf2
         U __ieee754_logf
         U __ieee754_sqrtf
         U __mulsf3
00000000 T asinhf
         U fabsf
         U log1pf

lib_a-sf_cos.o:
         U __ieee754_rem_pio2f
         U __kernel_cosf
         U __kernel_sinf
         U __subsf3
00000000 T cosf

lib_a-sf_isinf.o:
00000000 T isinff

lib_a-sf_isinff.o:
00000000 T __isinff

lib_a-sf_sin.o:
         U __ieee754_rem_pio2f
         U __kernel_cosf
         U __kernel_sinf
         U __subsf3
00000000 T sinf

lib_a-w_asin.o:
         U __errno
         U __fdlib_version
         U __gtdf2
         U __ieee754_asin
         U __isnand
00000004 T asin
         U fabs
         U matherr
         U nan

lib_a-w_sincos.o:
         U cos
         U sin
00000000 T sincos

lib_a-w_sinh.o:
         U __errno
         U __fdlib_version
         U __gtdf2
         U __ieee754_sinh
         U finite
         U matherr
00000004 T sinh

lib_a-wf_asin.o:
         U __errno
         U __extendsfdf2
         U __fdlib_version
         U __gtsf2
         U __ieee754_asinf
         U __truncdfsf2
00000004 T asinf
         U fabsf
         U isnanf
         U matherr
         U nan

lib_a-wf_sincos.o:
         U cosf
00000000 T sincosf
         U sinf

lib_a-wf_sinh.o:
         U __errno
         U __extendsfdf2
         U __fdlib_version
         U __gtsf2
         U __ieee754_sinhf
         U __truncdfsf2
         U finitef
         U matherr
00000004 T sinhf

EDIT1: I tested some more and the problem is as follows (not what I originally stated above):

double aa;
double bb = 1.0;
double cc;
aa = sin(1.0);
cc = sin (bb);

What happens when I try to build is that I get a 'undefined reference' at the last line, meaning that when I use constants it is fine, but when I pass variables to the sin functions it will not link. I also tested many of the other math function and I´ll get the exact same linker issue. As soon as I pass a variable to a math function I can not link any more. any ideas?

theAlse
  • 5,577
  • 11
  • 68
  • 110
  • are both the function calls in the same file? – Heisenbug Jun 30 '11 at 11:47
  • 2
    If you use your platform's tool to list the symbol table for an object file (e.g. [`nm `](http://unixhelp.ed.ac.uk/CGI/man-cgi?nm)), are the missing functions listed in libm.a? The error indicates the problem is in the link phase, at which point the header files are no longer involved. In other words, the contents of math.h won't affect the issue. – outis Jun 30 '11 at 11:49
  • yes, pow and asin are right after each other (I skipped the variable declaration above) – theAlse Jun 30 '11 at 11:50
  • @Alborz Perhaps do a `nm libm.a` ? – cnicutar Jun 30 '11 at 11:53
  • @cnicutar @outis, What should I be looking for in the nm output? I can see stuff like: lib_a-ef_asin.o: and lib_a-e_asin.o: and lib_a-e_sinh.o: – theAlse Jun 30 '11 at 12:00
  • @Alborz: as stated before, you're looking for the missing functions listed in the output (likely mangled with a "_" prefix). – outis Jun 30 '11 at 12:09
  • `pow` may be implemented as a builtin by your compiler. – interjay Jun 30 '11 at 12:09
  • 1
    Check your LD_LIBRARY_PATH. You might be looking at a different library to the one the linker is using. Remember that the header file math.h might also refer to a different library to the one being picked up. – cdarke Jun 30 '11 at 13:09
  • 2
    Can you reproduce the problem with just one source file, building the executable without any makefiles, like so: `gcc -o test test.c -lm` or perhaps `gcc -static -o test test.c -lm`? – n. m. could be an AI Jun 30 '11 at 13:59
  • try adding `-std=c99` to the compile line just to see what happens – Vinicius Kamakura Jun 30 '11 at 14:16
  • You are only interested in the symbols with external linkage, you should use nm mode selectively: `nm --extern-only libm.a` – Clifford Jun 30 '11 at 21:53
  • 1
    @hexa: That would change the behaviour of the compiler, not the content of the library. Dialect selection may remove parts of the header file, but that would cause a compiler not a linker error. – Clifford Jun 30 '11 at 21:56
  • 3
    If you are compiling optimized the compiler can optimize away the run-time call to `sin(1.0)`, replacing it by a constant computed at compile time. **Have you #included ** (see Jonathan's answer)? – David Hammen Jul 01 '11 at 16:08
  • Which platform are you on? Which C compiler are you using? Are you cross-compiling? What is the command line that is executed to do the linking? (I see DOS/Windows C: paths and PowerPC architecture.) Is there any chance you are using for type-generic math? – Jonathan Leffler Jul 01 '11 at 17:27

4 Answers4

10

The sequence for -lm -lc -lgcc plays a very important role. Only this sequence works for me.

These commands go to the Linker Options!

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
ottelo
  • 101
  • 1
  • 2
10

The linker isn't complaining about pow((double) 2, (double) 3) because the compiler is replacing it with a constant 8.0. You shouldn't depend on this behavior; instead, you should always use the -lm option properly. (BTW, that's more clearly written as pow(2.0, 3.0).

Consider the following program:

#include <stdio.h>
#include <math.h>
int main(void) {
    double x = 0.1;
    printf("%g\n", pow(2.0, 3.0));
    printf("%g\n", asin(x));
    return 0;
}

When I compile and link it on my system using

gcc c.c -o c

I get:

/tmp/ccXx8ZRL.o: In function `main':
c.c:(.text+0x36): undefined reference to `asin'
collect2: ld returned 1 exit status

Note that it complains about asin but not about pow.

If I change the pow call to pow(x, 3.0), I get:

/tmp/ccOeSaBK.o: In function `main':
c.c:(.text+0x24): undefined reference to `pow'
c.c:(.text+0x52): undefined reference to `asin'
collect2: ld returned 1 exit status

Normally if you want to call a standard math library function, you need to have #include <math.h> at the top of the source file (I presume you already have that) and you need to pass the -lm option to the compiler after the file that needs it. (The linker keeps track of references that haven't been resolved yet, so it needs to see the object file that refers to asin first, so it can resolve it when it sees the math library.)

The linker isn't complaining about the call to pow(2.0, 3.0) because gcc is clever enough to resolve it to a constant 8.0. There's no call to the pow function in the compiled object file, so the linker doesn't need to resolve it. If I change pow(2.0, 3.0) to pow(x, 3.0), the compiler doesn't know what the result is going to be, so it generates the call.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
8

Are you including <math.h> everywhere?

Notice that the names in the library are prefixed with __ieee754_, but the ones the linker can't find are not.

What happens when you compile this code?

#include <math.h>

int main(void)
{
    double d = pow(2, 3);
    double e = asin(1.0 / d);
    return (int)(e+1);
}

If the file is mathtest.c, then compile with:

gcc -o mathtest mathtest.c -lm

(Given that this fails to compile, what symbols are defined in mathtest.o?)


I added a comment to the main question:

Which platform are you on? Which C compiler are you using? Are you cross-compiling? What is the command line that is executed to do the linking? (I see DOS/Windows C: paths and PowerPC architecture.) Is there any chance you are using for type-generic math?

Looking at the LOAD paths you give, I see:

LOAD c:/gnu/powerpc-eabi/3pp.ronetix.powerpc-eabi/bin/../lib/gcc/powerpc-eabi/4.3.3/../../../../powerpc-eabi/lib/nof\libm.a

Which can, I think, be simplified to:

LOAD c:/gnu/powerpc-eabi/3pp.ronetix.powerpc-eabi/powerpc-eabi/lib/nof\libm.a

One part of that path that intrigues me is the nof part; could that be 'no floating point'? The other part that really intrigues me is the presence of powerpc with the c: prefix; it smacks of cross-compilation for PowerPC on a Windows platform. It is important to be forthright and explicit about such things; we need that sort of information to be able to help you sensibly.

Was this the libm.a library that you tested, or did you experiment with another file?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    "Undefined reference" is a linker error, not a compiler error, failing to include a header file would cause a compler error (or a warning in C89). – Clifford Jun 30 '11 at 21:47
  • 5
    @Clifford: unless including the header mapped the source code name from `asin` to `__ieee574_asin`. The output from `nm` shows a symbol `__ieee574_asin`, and if the header mapped the name as suggested, then calling the function without the header would mean that the 'wrong' function was called. If the sample code that I supplied links but the original poster's code does not, I'd be inclined to regard that as 'case proven'. Yes, you can legitimately argue that you are supposed to be able to write `extern double asin(double);` and it should work, but I've seen this sort of name mapping before. – Jonathan Leffler Jun 30 '11 at 23:21
  • ISO/IEC 9899:1999 (E) §7.1.4/2: `Provided that a library function can be declared without reference to any type defined in a header, it is also permissible to declare the function and use it without including its associated header.` So if the include is required, the implementation is non-conforming. – bdonlan Jun 30 '11 at 23:59
  • @bdonlan: I never said otherwise - and I'm aware of that bit of the standard. But I've seen this sort of game played on (Linux) implementations before. And that is one (major) reason why it is better to include the system header than to second guess the system. But I think that if my example does not compile cleanly, then the implementation is simply broken. If it does compile cleanly but the OP's code does not, then the OP's code does something tantamount to not including `` where this implementation requires it...and the fix of including `` will work everywhere. – Jonathan Leffler Jul 01 '11 at 00:06
  • @Jonathan, you have written (almost) the same code as I had originally, and you are linking with -lm as I have. I don´t see any diffrence. I got the undefined reference to ´asin´ again. – theAlse Jul 01 '11 at 06:40
  • @alborz: OK - if the code I showed does not link, you need to get your compiler, your headers or your libraries fixed. The current setup is broken. What I can't say is whether the trouble is in your headers or in your libraries, or whether you have something very weird set in your /etc/ld.so.conf or equivalent (so it is pulling in the wrong maths library). Also, normally I'd expect there to be a `libm.so` rather than `libm.a`; I don't know whether that's a factor. And finally (for now), have you checked whether there are any other missing symbols from the standard set? – Jonathan Leffler Jul 01 '11 at 14:06
  • @Jonathan: I think that I found the real issue here. please see edited post above – theAlse Jul 01 '11 at 14:49
  • @Alborz: it gets weirder and weirder. Since you've not shown us a linkable example that reproduces the problem, I can't help you any further. – Jonathan Leffler Jul 01 '11 at 15:08
1

You can use "filename.c -lm" to solve this problem . And please don't forget to use header file math.h