Find the call chain that causes a function to be linked in
Asked Answered
T

2

6

I'm working on an embedded system and while analyzing the binary with nm I find a lot of symbols from standard library functions such as:

00001524 std::time_get<char, std::istreambuf_iterator<char, std::char_traits<char> > >::_M_extract_via_format(std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, std::_Ios_Iostate&, tm*, char const*) const [clone .localalias]

This means that there is a std::time_get function that gets linked in, which is 1524 bytes large. I would like to find out what call-chain causes the calls to std::time_get since I'm not actually referencing that in any part of my code.

Trying to use the linker flag --cref and looking in the map file I can find the symbol, but I can't find what's calling it. It only tells me that libstdc++_nano.a(locale-inst.o) references it:

.text._ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE21_M_extract_via_formatES3_S3_RSt8ios_baseRSt12_Ios_IostateP2tmPKc
                0x00000000080a07bc      0x5fc /opt/st/stm32cubeide_1.10.1/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.10.3-2021.10.linux64_1.0.0.202111181127/tools/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+dp/hard/libstdc++_nano.a(locale-inst.o)
                0x00000000080a07bc                std::time_get<char, std::istreambuf_iterator<char, std::char_traits<char> > >::_M_extract_via_format(std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, std::_Ios_Iostate&, tm*, char const*) const

How can I go from there to find the caller?

Terbia answered 29/9, 2023 at 8:50 Comment(2)
Do you think you could reduce your code to the point where either you narrow down the culprit, or the code is simple and does not leak any sensitive info so that the binary could be shared?Two
@Two don't think I can, the binary is about 1MB and contains too much info to share, I've tried reducing the search surface but without luck, I may need to do incremental linking or something to figure out at which point it gets includedTerbia
L
1

You can use the linker -y flag to answer this question (though this is quite tedious).

Example:

// foo.c
int foo() { return 42; }

// bar.c
int bar() { return foo(); }

// main.c
int main() { return bar(); }
gcc -w -c main.c foo.c bar.c
ar r libfoo.a foo.o
ar r libbar.a bar.o

gcc main.o -L. -lbar -lfoo -Wl,-y,foo
 
/usr/bin/ld: ./libbar.a(bar.o): reference to foo
/usr/bin/ld: ./libfoo.a(foo.o): definition of foo

This tells you that foo was selected into the link because bar.o has a reference to it. Repeat for bar:

gcc main.o -L. -lbar -lfoo -Wl,-y,bar
/usr/bin/ld: main.o: reference to bar
/usr/bin/ld: ./libbar.a(bar.o): definition of bar

You can also use the -M flag to gain the same info:

gcc main.o -L. -lbar -lfoo -Wl,-M

will have output similar to this:

 .text          0x0000000000001070       0xb9 /usr/lib/gcc/x86_64-linux-gnu/13/crtbeginS.o
 .text          0x0000000000001129       0x10 main.o
                0x0000000000001129                main           <<<---
 .text          0x0000000000001139       0x10 ./libbar.a(bar.o)
                0x0000000000001139                bar            <<<---
 .text          0x0000000000001149        0xb ./libfoo.a(foo.o)
                0x0000000000001149                foo            <<<---

The <<<--- markers show which symbol caused the corresponding .o to be pulled into the link.

Lignin answered 30/9, 2023 at 2:6 Comment(1)
hmm, this shows me that the functions are being used by libstdc++_nano but it doesn't show me what caused that to be included.Terbia
U
1

Why you don't use the readelf command-line tool or a similar tool to analyze the object files or binary? to do this you can simply run the the command on the object file or binary that contains the symbol you are interested in:

readelf -s <object_file>

let me show you with an example, assume you have an object file named example.o and you want to find the caller of the symbol std::time_get > >::_M_extract_via_format

readelf -s example.o

then, look for the symbol std::time_get > >::_M_extract_via_format in the output and note down the symbol's address, and locate the section associated with the symbol,for example it could be .text or .rodata or anything like that! now run this command to display the relocation entries for that section:

readelf -r example.o

and search for the symbol's address in the relocation entries,this will give you the list of relocations that reference the symbol, and fom the relocation entries, identify the object files or libraries that reference the symbol, for example, let's say you find the following relocation entry(as you see the relocation entry indicates that the symbol is referenced as a global data object) :

Relocation section '.rel.text' at offset 0x1000 contains 1 entries:
Offset          Info           Type           Symbol's Value  Symbol's Name + Addend
00001024  000000000008 R_ARM_GLOB_DAT   0000000000000000   std::time_get<char, std::istreambuf_iterator<char, std::char_traits<char> > >::_M_extract_via_format

and finally, to find the object file or library that references this symbol, you can use the nm command on the object file or library file and then look for the symbol's offset in the output to identify the callers of the symbol, like below

nm -C example.o
Uribe answered 4/10, 2023 at 14:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.