How to go from linker error to line of code in sources?

The component produces this type of output.

/var/tmp/ccITB4j2.o: In function `main': /var/tmp/ccITB4j2.o(.text+0x4): undefined reference to `myFunction(void)' 

How do I find out the line of source code that matches the instructions in .text + 0x4, where the function is actually called?

+3
source share
3 answers

Firstly, another answer to your question is incorrect: on Linux, you get the 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 

The above is derived from gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 and linker GNU ld (GNU Binutils for Ubuntu) 2.22 , but this is true for much older versions of GCC and ld.

The reason you are not getting the file / line should be

  • you did not use the -g flag or
  • you have really old ld or
  • you configured ld without debugging support (I'm not sure if this is even possible).

However, even if your ld refuses to tell you the file and line, not everything is lost. You can compile the source into an object, and then use objdump -rdS foo.o to get the same information:

 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 the above output, you can clearly see which line of the source caused the link to _Z10myFunctionv (which is the C++ changed name for myFunction(void) ), which should be emitted in the object file.

+6
source

The key to understanding linker errors is to know the difference between a declaration and a definition.

This announcement:

 int myFunction(); 

This 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 (perhaps later in the same translation system or, possibly, in another). These promises are actually checked by the linker during the connection.

So a linker error (like this one) actually complains that you have broken your promise to define something. Since this happens after compilation, and since it deals with something that "does not exist", it makes no sense to ask for "line number where it does not exist."

Hope this helps explain why you won't get the line number attached to the "unresolved character" error message from the linker.

+2
source

I have 3 answers (so far) and analysis of a specific case when I needed to know how to do this


addr2line can do this if the compiler generates 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 is 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 response to the question "how does the debugger do this", here is a good article on the topic: How debuggers work: Part 3 - Debugging information , where the objdump option comes from.

I will apologize in advance for future generations if the connection breaks.


I ran into a problem on these lines with Solaris Studio 12.3 on Linux. It seems that the information it generates (in .debug_line or some other section) debugs information that is incompatible with addr2line , but only when building with optimization. The following code will cause 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 a communication error for this case requires linking to the libCrun compiler libCrun . As a counter-example, for the employer's comments that it is useless to know the line numbers: I, of course, had to scratch my head about where delete referenced. As it turned out, the compiler inserts additional code that selects the material and removes it. If he correctly printed the line number (tight binding of the function), it would be much more obvious that the compiler was doing something unusual.

+1
source

Source: https://habr.com/ru/post/1483578/


All Articles