如何检查从哪里引用函数

How to check where a function is referenced from

在裸机 C/C++ 项目中,我使用 gcc-arm-embedded (currently the most recent 4.9-2015-q2).

出于某些原因,我必须避免使用某些功能,例如某些 stdio 等(不想使用重定向或半主机)。

此外,我将 FreeRtos 与 heap_4.c 一起使用,例如malloc() 像这样直接重定向到 pvPortMalloc()

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

因此,我不想在我的二进制文件中包含工具链堆管理代码的任何部分。

现在,在某些情况下,我团队的开发人员意味着使用例如printf() 间接引用了 _malloc_r()(以及更多),实际上很难找出引用的位置以及修复的位置。

(使用 printf() 只是这里的一个例子。在我的项目中,我有 printf() 的自定义实现,它不使用 stdio 直接打印到 uart。但还有其他情况,例如类型信息 demangeling , …)

目前,我的项目(由大约 200 个 c 和 c++ 源文件组成)在没有以任何方式引用 _malloc_r() 的情况下编译得很好 - 只要我使用 gcc 4.8 构建.

但是在使用 gcc 4.9 构建时,我看到了对 _malloc_r 和其他一些不需要的引用。

可能有命令行工具来分析我的 elf 文件以找出引用特定函数的位置?

编辑 2015-07-20:

使用自定义 malloc.h 的 Peraphs,您可以在其中取消定义或重新定义 _malloc_r

类似于:

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

也去Hooks-for-Malloc看看

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.

另一个提示是使用 LD_PRELOAD What is the LD_PRELOAD trick?

我不确定我是否理解正确,但您似乎想避免在您的项目中使用某些特定功能。简单地给函数标识符下毒怎么样?

此代码无法(有意)为 printf 编译:

#define printf FORBIDDEN

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

出现以下错误:

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
               ^~~~~~~~~

所以声明和重新定义的顺序无关紧要。你不需要知道所有调用禁用函数的函数:

#define printf FORBIDDEN

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

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

这是一个在静态编译程序中找出对_exit的引用的例子:

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

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

编译它:

$ gcc hello.c -static -g

找出_exit的地址:

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

objdump -d -j .textgrep反汇编为_exit的地址,cut的地址出线并管道到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
??:?

结果是:

函数 oommain__run_exit_handlers、...请参考函数 _exit