了解编译目标文件中 C 函数的大小

jce*_*cea 3 c compiler-construction elf compiler-optimization object-files

在 C 语言中很容易得到函数的起始地址,但不能得到它的大小。因此,我目前正在目标文件上执行“nm”,以便找到我的函数,然后找到下一个函数的起始地址。我需要执行“nm”,因为编译器可以(在我的情况下实际上可以)重新排序函数,因此源顺序可以与对象顺序不同。

我想知道是否还有其他方法可以做到这一点。例如,指示编译器保留目标文件中的源代码顺序等。也许有一些 ELF 魔法?

我的编译器是 GCC、CLANG 和 Sun Studio。平台:Solaris 及其衍生产品、MacOSX、FreeBSD。未来要拓展。

lor*_*nix 5

我发现 的输出objdump -t xxx将为程序和目标文件 (.o) 提供明确的函数大小/长度值。

例如:(来自我的一个项目)

objdump -t emma | grep " F .text"

0000000000401674 l F .text 0000000000000376 parse_program_header
00000000004027ce l F .text 0000000000000157 create_segment
00000000004019ea l F .text 000000000000050c parse_section_header
0000000000402660 l F .text 000000000000016e create_section
0000000000401ef6 l F .text 000000000000000a parse_symbol_section
000000000040252c l F .text 0000000000000134 create_symbol
00000000004032e0 g F .text 0000000000000002 __libc_csu_fini
0000000000402240 g F .text 000000000000002e emma_segment_count
00000000004022f1 g F .text 0000000000000055 emma_get_symbol
00000000004021bd g F .text 000000000000002e emma_section_count
0000000000402346 g F .text 00000000000001e6 emma_close
0000000000401f00 g F .text 000000000000002f emma_init
0000000000403270 g F .text 0000000000000065 __libc_csu_init
0000000000400c20 g F .text 0000000000000060 estr
00000000004022c3 g F .text 000000000000002e emma_symbol_count
0000000000400b10 g F .text 0000000000000000 _start
0000000000402925 g F .text 000000000000074f main
0000000000401f2f g F .text 000000000000028e emma_open
Run Code Online (Sandbox Code Playgroud)

我对这个列表进行了一些删减,它很长。您可以看到第五列(第二个宽列有很多零......)给出了每个函数的长度值。 main是 0x74f 字节长,emma_close是 0x1e6,parse_symbol_section是微不足道的 0x0a 字节... 10 个字节!(等等……那是一个存根吗?)

此外,我只查找了该部分'F'unctions中的.text,从而进一步限制了列表。选项仅-t显示objdump符号表,因此它省略了相当多对函数长度收集不是特别有用的其他信息。

我想你可以这样使用它:

objdump -t MYPROG | grep "MYFUNCTION$" | awk '{print "0x" $(NF-1)}' | xargs -I{} -- python -c 'print {}'
Run Code Online (Sandbox Code Playgroud)

一个例子:

00000000004019ea l F .text 000000000000050c parse_section_header

$ objdump -t emma | grep "parse_section_header$" | awk '{print "0x" $(NF-1)}' | xargs -I{} -- python -c 'print {}'
1292
Run Code Online (Sandbox Code Playgroud)

检查,因为 0x50c == 1292。

我曾经$(NF-1)在 awk 中抓取列,因为第二个字段的内容和空间可能会有所不同,具体取决于与所涉及符号相关的标识符。另外,请注意grep 中的尾随$,导致main找到mainmain.c函数,而不是其名称的条目。

xargs -I{} -- python -c 'print {}'位是将十六进制值转换为十进制值。如果有人能想到更简单的方法,请插话。(您可以看到awk前缀0x在哪里)。

啊,我刚刚记得我有一个别名,objdump它预设了demangleobjdump 的选项。--demangle如果添加到 objdump 调用,将使匹配变得更容易。(我也使用--wide,更容易阅读,但不会影响这个特定的输出)。

这适用于任何ELF 对象、库、程序、对象文件,只要它没有被剥离。(我也测试了带调试符号和不带调试符号的情况)

希望这可以帮助。

(我看了看,parse_symbol_section 一个存根。)