在裸机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:
_malloc_r
。我进一步发现,有一个__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
)来检查。
答案 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
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 .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
??:?
结果是:
函数oom
,main
,__run_exit_handlers
,...确实引用函数_exit
。