I am trying to process the output of a nm or readelf -s on an executable. However, I am having trouble differentiating static functions from each other in the output.
Here is what I am working with:
test.c
static int foo() {
int x = 6;
}
main() {}
other.c
static int foo() {
int x = 5;
}
I compile these like so:
gcc -o test test.c other.c
And then run a nm command to get all the symbols:
nm test
Among which the following two symbols (for my static functions) appear:
00000000004004ed t foo
0000000000400500 t foo
Is there a method to be able to distinguish which file the specific foo function appeared from? Or will I need to do some magic before compiling to get this to work?
I should add that for my use case, I have access to the final binary and the object files used by it, but I cannot actually build it myself to ensure that it has a symbol table.
Thanks!
The nm commands provides information on the symbols being used in an object file or executable file. The default information that the 'nm' command provides is : Virtual address of the symbol. A character which depicts the symbol type.
nm (name mangling) is a Unix command used to dump the symbol table and their attributes from a binary executable file (including libraries, compiled object modules, shared-object files, and standalone executables). The output from nm distinguishes between various symbol types.
The nm-tool utility provides information about NetworkManager, device, and wireless networks.
Your question assumes that, given an executable, you can always discover
the names of the static
(local) functions that were compiled into it,
using nm
or another tool. Thus you will be able to see when two or
more such names are the same and to raise the question of how to discover
what source files they were compiled from.
However, that assumption is false. In the case of gcc, if files are compiled
with optimization -O0
then local symbols will be emitted in the object
file symbol table. -O0
is the default, so it applies in the case of your:
gcc -o test test.c other.c
But if files are compiled at any higher optimization level - as they certainly
will be for a release build - then local symbols are omitted from the object
files symbol table. So the linker never even sees them. So you cannot recover
them from the executable with nm
or anything else.
Compile your sample files with:
gcc -O1 -o test test.c other.c
then nm test
again, and you will observe that the:
00000000004004ed t foo
0000000000400500 t foo
have vanished, together with all of the other static function names.
In that case, if as you say you cannot control how the executable is built, then you cannot ensure that it is even possible for your question to arise.
If you could control how the executable is built to ensure that files are
compiled with -O0
, then there are several ways in which you can tie the
static function names to source files. Two equally simple ones would be:
readelf -s test
and
objdump -t test
each of which will list a source file name at the head of each chunk of symbols that come from it.
(And if it needs saying, the gdb
approach suggested by by @Amol does not escape the restriction that the executable must have been compiled with optimization -O0
)
I tried out following sequence.
If you have stripped output file with no debugging symbols then using gdb
you can create object file.
Follow the commands as below :
$ gdb a.out
will give following as output
Reading symbols from /home/amol/amol/a.out...(no debugging symbols found)...done.
Then
(gdb)
will come in terminal
Give following commands in sequence ((gdb)
prompt come by default as you go on typing commands)
(gdb) maint print symbols filename
(gdb) maint print psymbols filename
(gdb) maint print msymbols filename
Now in your folder you can see one file with named as filename. Open this file in text editor then you can see information as below :
[ 8] t 0x80483b4 foo section .text test.c
[ 9] T 0x80483c3 main section .text other.c
[10] t 0x80483c8 foo section .text other.c
Here you can clearly see that which foo()
function is come from which .c
file. Hope this helps for you.
You may need to read the ELF symbol table and extract ELF32_ST_BIND value.
According to the ELF specification (see http://flint.cs.yale.edu/cs422/doc/ELF_Format.pdf) the values for ELF32_ST_BIND can be:
Name Value
STB_LOCAL 0
STB_GLOBAL 1
STB_WEAK 2
STB_LOPROC 13
STB_HIPROC 15
Where STB_LOCAL is defined to be "Local symbols are not visible outside the object file containing their definition. Local symbols of the same name may exist in multiple files without interfering with each other." which seem to match up fairly well with static C functions.
For example, taking you sample and modifying it slightly:
test.c:
static int foo() {
int x = 5;
}
int bar()
{
int y = 6;
}
main() {}
other.c:
static int foo()
{
int x = 7;
}
and compiling with gcc -o test test.c other.c
and looking at the symbol table (lots of entries removed):
readelf -s test
Num: Value Size Type Bind Vis Ndx Name
37: 00000000004004f0 13 FUNC LOCAL DEFAULT 13 foo
39: 0000000000400510 13 FUNC LOCAL DEFAULT 13 foo
52: 00000000004004fd 13 FUNC GLOBAL DEFAULT 13 bar
We can see that the two static functions show up as LOCAL and the one `normal' function shows up a GLOBAL
Note: while this method will work with non-debug files, if the final file is stripped, we can not use this method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With