如何检查引用函数的位置

时间:2015-06-27 12:18:19

标签: c++ c gcc freertos bare-metal

在裸机C / C ++项目中,我使用gcc-arm-embedded(目前是最新的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。但还有其他情况,例如类型信息demangeling,... )

目前,我的情况是我的项目(由大约200个c和c ++源文件组成)编译得很好而不会以任何方式引用_malloc_r() - 只要我使用gcc 4.8构建。< / p>

但在使用gcc 4.9进行构建时,我会看到对_malloc_r等不需要的引用。

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

编辑2015-07-20:

  • 最后,我解决了我的基本问题,我需要使用gcc 4.9构建整个项目,而不需要在我的代码中引用_malloc_r
  • 我通过应用this answer找到的一些参考文献。
  • 我进一步发现,有一个__gnu_cxx::__snprintf_lite()引用了我在代码中不想要的iostream的全部内容。 __gnu_cxx::__snprintf_lite() gcc实施的某些例外情况(例如stl引用)使用此__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)来检查。

3 个答案:

答案 0 :(得分:2)

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

  

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

     

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

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

答案 1 :(得分:2)

我不确定,我是否理解正确,但似乎您希望避免在项目中使用某些特定功能。如何简单地中毒函数标识符?

此代码无法(有意)编译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();
}

答案 2 :(得分:2)

这是在静态编译的程序中查找对_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反汇编地址为_exitcut地址不在行中并将其传输到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