The linker produces this kind of output
/var/tmp/ccITB4j2.o: In function `main':
/var/tmp/ccITB4j2.o(.text+0x4): undefined reference to `myFunction(void)'
How can I find out the line of source code corresponding to the instruction at .text+0x4 where the function is actually invoked?
First, the other answer to your question is wrong: on Linux you do get file and line number from the linker:
$ cat foo.cc
extern int myFunction(void);
int main()
{
return myFunction();
}
$ g++ -g foo.cc
/tmp/cc3twlhL.o: In function `main':
/tmp/foo.cc:5: undefined reference to `myFunction()'
collect2: ld returned 1 exit status
Above output is from gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
and linker GNU ld (GNU Binutils for Ubuntu) 2.22
, but this has been true for much older versions of GCC and ld as well.
The reason you are not getting the file/line must be that
- you didn't use
-g
flag, or
- you have a really old
ld
, or
- you have configured your
ld
without support for debugging (I am not sure this is even possible).
However, even if your ld
is refusing to tell you the file and line, not all is lost. You can compile your source into object, then use objdump -rdS foo.o
to obtain the same info:
g++ -g -c foo.cc
objdump -rdS foo.o
Disassembly of section .text:
0000000000000000 <main>:
extern int myFunction(void);
int main()
{
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
return myFunction();
4: e8 00 00 00 00 callq 9 <main+0x9>
5: R_X86_64_PC32 _Z10myFunctionv-0x4
}
9: 5d pop %rbp
a: c3 retq
In above output, you can clearly see which source line caused reference to _Z10myFunctionv
(which is the C++
mangled name for myFunction(void)
) to be emitted in the object file.
Key to understanding linker errors is to know the difference between a declaration and a definition.
This is a declaration:
int myFunction();
This is a definition:
int myFunction() {
// do something
return val;
}
When you declare something, the compiler takes it as a promise from you, that you will eventually define it also (perhaps later in the same translation unit, or maybe in a different one). These promises are actually checked by the linker at link time.
So a linker error (such as this one) is actually complaining that you broke your promise to define something. Since this happens after compilation, and since this deals with something that is "not there", it is meaningless to ask for "the line number where it is not there".
Hope that helps explain why you wont get a line number tacked onto an "unresolved symbol" error message from the linker.
I have 3 answers (so far), and an analysis about a particular case where I needed to know how to do this
addr2line
can do it, provided the compiler generated debugging information compatible with the tool.
~ cat asdf.txt
/var/tmp/ccITB4j2.o: In function `main':
/var/tmp/ccITB4j2.o(.text+0x4): undefined reference to `myFunction(void)'
~ cat asdf.txt | addr2line -e /var/tmp/ccITB4j2.o
... it should print src:line info here
Then there's objdump
:
objdump --dwarf=decodedline test.o
test.o: file format elf64-x86-64
Decoded dump of debug contents of section .debug_line:
CU: test.cc:
File name Line number Starting address
test.cc 2 0x23
test.cc 3 0x84
In answer to the question "how does the debugger do it", here's a nice article on the topic: How debuggers work: Part 3 - Debugging information, which is where the objdump
option came from.
I'll apologize in advance for future generations if the link breaks.
I ran into a problem along these lines with Solaris Studio 12.3 in Linux. It looks as though the information it generates (whether in .debug_line
or some other section) debug information incompatible with addr2line
, but only when built with optimizations. The following code will induce a similar link error:
~ cat test.cc
struct Test {int x; Test(); };
inline void test() { Test *t = new Test(); }
void blah() { test(); }
~ CC -g -Kpic test.cc -shared -o libtest.so -Wl,--unresolved-symbols=ignore-in-shared-libs
(...)
test.cc:2: undefined reference to `void operator delete(void*)'
(...)
~ CC -g -Kpic test.cc -shared -o libtest.so -Wl,--unresolved-symbols=ignore-in-shared-libs -O0
(...)
test.cc:(.text+0x45): undefined reference to `void operator delete(void*)'
(...)
~ CC -g -Kpic test.cc -c
~ addr2line -e test.o +0x45
test.cc:2
~ CC -g -Kpic test.cc -O0 -c
~ addr2line -e test.o +0x45
??:?
Resolving the link error for that case requires linking against a compiler library libCrun
. As a counter-example to the naysayer comments about it being useless to know the line numbers: it certainly had me scratching my head as to where the delete
was being referenced. As it turns out, the compiler is inserting extra code that allocates stuff & deletes it. Had it correctly printed the line number (the close brace of the function) it would've been far more obvious that the compiler was doing something out of the ordinary.