如何检查从何处引用函数

How to check where a function is referenced from

本文关键字:何处 引用 函数 检查 何检查      更新时间:2023-10-16

在一个裸金属C/C++项目中,我使用嵌入式gcc arm(目前是最新的4.9-2015-q2)。

出于某些原因,我不得不避免使用一些函数,比如stdio等函数(不想使用重定目标或半托管)。

此外,我将FreeRtos与heap_4.c一起使用,并将例如malloc()直接重定向到pvPortMalloc(),如下所示:

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

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

现在,有一些情况,因为我的团队的开发人员打算使用例如printf(),它间接引用_malloc_r()(以及更多),实际上很难找到它是从哪里引用的,也很难找到修复的地方。

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

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

但是,当使用gcc 4.9进行构建时,我看到了对_malloc_r和更多内容的不必要引用。

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

编辑2015-07-20:

  • 最后,我解决了我的根本问题,即我需要使用gcc 4.9构建我的整个项目,而不需要在代码中引用_malloc_r
  • 我通过应用这个答案找到的一些参考资料
  • 此外,我发现有一个__gnu_cxx::__snprintf_lite()引用了iostream的完整版本,我不希望在我的代码中使用它。该__gnu_cxx::__snprintf_lite()gccstl实现的一些例外使用(例如由__throw_out_of_range_fmt()引用)。(是的,我的代码使用std::map)。我摆脱iostream的方法是简单地提供我自己的__gnu_cxx::__snprintf_lite(),如下所示(有我自己的小占地面积vsnprintf):

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

    这可以通过查看gcc-4.9库源(例如src/gcc/libstdc++-v3/src/c++11/snprintf_lite.cc)进行检查。

这是一个在静态编译程序中查找_exit引用的示例:

/* hello.c */
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
    write(1, "Hellon", 6);
    _exit(0);
}

编译:

$ gcc hello.c -static -g

查找_exit:的地址

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

objdump -d -j .text拆下,grep拆下_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。。。请参考函数CCD_ 30。

我不确定我是否正确理解了你,但你似乎想避免在项目中使用一些特定的函数。不如简单地毒害函数标识符?

此代码无法(故意)为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();
}

使用自定义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

看看挂钩马洛克太

GNU C库允许您修改malloc、realloc和通过指定适当的钩子函数来释放。你可以用这些钩子为了帮助您调试使用动态内存分配的程序实例

钩子变量在malloc.h中声明。

另一个提示是使用LD_PRELOAD LD_PRELLOAD技巧是什么?