How to check where a function is referenced from

1.2k views Asked by At

In a bare metal C/C++ project, I use gcc-arm-embedded (currently the most recent 4.9-2015-q2).

For some reasons, I have to avoid using some functions, like some of stdio et cetera (don't want to use retargeting or semihosting).

Further, I use FreeRtos with heap_4.c and had e.g. malloc() redirected directly to pvPortMalloc() like this:

void* malloc(size_t s) {
    return pvPortMalloc(s);
}

Therefore, I don't want to have any parts of the toolchain's heap management code within my binary.

Now, there are some situations, as were a developer of my team means to use e.g. printf() which indirectly references _malloc_r() (and some more) and it's actually quite hard to find out where it's referenced from and so where to fix.

(The use printf() is just an example here. In my project, I have custom implementation of printf() which prints directly to uart without using stdio. But there are other cases, e.g. type info demangeling, …)

Currently, I have the situation that my project (which consists of about 200 c and c++ source files) compiles well without referencing _malloc_r() in any way - as long as I build with gcc 4.8.

But when building with gcc 4.9, I see unwanted references to _malloc_r and some more.

Might there be command line tool to analyze my elf file for finding out where specific functions are referenced from?

Edit 2015-07-20:

  • Finally, I'd solved my underlying problem, that I need to build my whole project with gcc 4.9 without having references to _malloc_r inside of my code.
  • Some of the references I'd found by applying this answer.
  • Further I find out, that there is a __gnu_cxx::__snprintf_lite() which references the full blown of iostream which I don't want in my code. This __gnu_cxx::__snprintf_lite() is used by some exceptions of the gcc stl implementation (e.g. referenced by __throw_out_of_range_fmt()). (Yep, my code uses std::map). My way to get rid of iostream was to simply provide my own __gnu_cxx::__snprintf_lite() like this (having my own small footprint vsnprintf):

    namespace __gnu_cxx {
        int __snprintf_lite(char* buf, size_t bufsize, const char* fmt, va_list ap) {
            return vsnprintf(buf, bufsize, fmt, ap);
        }
    }
    

    This can be checked by viewing the gcc-4.9 library sources (e.g. src/gcc/libstdc++-v3/src/c++11/snprintf_lite.cc).

3

There are 3 answers

5
4566976 On BEST ANSWER

This is an example for finding out the references to _exit in a statically compiled program:

/* hello.c */
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    write(1, "Hello\n", 6);
    _exit(0);
}

Compile it:

$ gcc hello.c -static -g

Find out the address of _exit:

$ nm a.out | grep " _exit"
000000000040f760 T _exit

Disassemble with objdump -d -j .text, grep for the address of _exit, cut the address out of the line and pipe it to addr2line:

$ objdump -d -j .text a.out | grep 40f760 | cut -c 1-8 | addr2line -e a.out -f
oom
dl-tls.o:?
main
/home/m/hello.c:8
__run_exit_handlers
??:?
??
??:0
_Exit
??:?
_dl_non_dynamic_init
??:?
abort
??:?
do_lookup_x
dl-lookup.o:?
_dl_relocate_object
??:?
_dl_signal_error
??:?
dl_open_worker
dl-open.o:?
_dl_close_worker.part.0
dl-close.o:?
_dl_start_profile
??:?

The result is:

Functions oom, main, __run_exit_handlers, ... do reference the function _exit.

3
frhack On

Peraphs using a custom malloc.h where you can undef or redefine _malloc_r

Something similar to:

extern _PTR malloc _PARAMS ((size_t));
#ifdef __CYGWIN__
#undef _malloc_r
#define _malloc_r(r, s) malloc (s)
#else
extern _PTR _malloc_r _PARAMS ((struct _reent *, size_t));
#endif

Take a look to Hooks-for-Malloc too

The GNU C Library lets you modify the behavior of malloc, realloc, and free by specifying appropriate hook functions. You can use these hooks to help you debug programs that use dynamic memory allocation, for example.

The hook variables are declared in malloc.h.

Another hint is using LD_PRELOAD What is the LD_PRELOAD trick?

1
Kuba Wyrostek On

I am not sure, whether I understood you correctly, but it seems you want to avoid using some specific functions in your project. How about simply poisoning the function identifiers?

This code fails to compile (intentionally) for printf:

#define printf FORBIDDEN

int main(int argc, char *argv[]) {
  printf("Test");
}

with the following error:

Untitled.cpp:11:3: error: no matching function for call to 'FORBIDDEN'
  printf("Test");
  ^~~~~~
Untitled.cpp:3:16: note: expanded from macro 'printf'
#define printf FORBIDDEN
               ^~~~~~~~~

So the order of declaration and redefinition does not matter. You do not need to know all functions that call forbidden functions:

#define printf FORBIDDEN

// this in included file:
void otherfunc() {
  printf("I fail.");
}
// eof included file

int main(int argc, char *argv[]) {
  otherfunc();
}