Search code examples
cstaticnmsymbol-table

How can I differentiate static functions with nm or readelf output in C


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!


Solution

  • 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)