假设我有如下函数:
# cat 003.c
int foo(int a, int b)
{
return a+b;
}
然后像这样编译它:
gcc -S 003.c
得到如下组装结果:
.file "003.c"
.text
.globl foo
.type foo, @function
foo:
.LFB2:
pushq %rbp
.LCFI0:
movq %rsp, %rbp
.LCFI1:
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
movl -8(%rbp), %edx
movl -4(%rbp), %eax
addl %edx, %eax
leave
ret
.LFE2:
.size foo, .-foo /* size of the function foo, how to get it?*/
上面的最后一行确实获取了函数的大小。编译器在哪里存储大小?我可以使用 C 或内联 asm 在我的原始 C 程序中以某种方式获取函数的大小吗?
最佳答案
有关函数大小的信息存储在相应符号(名称)的 ELF 属性 中。如何以编程方式解析此 C 示例代码位于 gelf_getsym(3ELF)
的 Solaris 联机帮助页底部(libelf在Linux、*BSD和MacOS中也存在,你需要寻找GElf_Sym
结构的st_size
字段),但你也可以使用objdump/elfdump (Solaris)/readelf (Linux) 任务:
$ objdump -h -d --section=.text foo3.o foo3.o: file format elf64-x86-64 Sections: Idx Name Size VMA LMA File off Algn 0 .text 00000012 0000000000000000 0000000000000000 00000040 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE [ ... ] Disassembly of section .text: 0000000000000000 <foo>: 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: 89 7d fc mov %edi,0xfffffffffffffffc(%rbp) 7: 89 75 f8 mov %esi,0xfffffffffffffff8(%rbp) a: 8b 45 f8 mov 0xfffffffffffffff8(%rbp),%eax d: 03 45 fc add 0xfffffffffffffffc(%rbp),%eax 10: c9 leaveq 11: c3 retq
这是针对未优化的代码编译,而优化版本是:
$ objdump -h -d --section=.text foo3.o foo3.o: file format elf64-x86-64 Sections: Idx Name Size VMA LMA File off Algn 0 .text 00000004 0000000000000000 0000000000000000 00000040 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE [ ... ] Disassembly of section .text: 0000000000000000 <foo>: 0: 8d 04 37 lea (%rdi,%rsi,1),%eax 3: c3 retq
注意“大小”从 0x12
更改为 4
了吗?这就是 .size
汇编指令的结果。
尝试使用内联汇编来为您提供函数大小/代码位置的“技巧”并不考虑编译器生成的胶水代码(函数入口序言/导出尾声、内联代码生成……),也不考虑编译器重新排序内联汇编(gcc 这样做是臭名昭著的),因此相信这一点通常不是一个好主意。最后,这取决于你到底想做什么......
编辑:一些外部引用和 stackoverflow 上的引用:
- 来自 gcc 邮件列表,thread on
sizeof(function)
- what does sizeof (function name) return?
- Find size of a function in C
- LibELF by example sourceforge 项目(这是文档/教程)
关于c - 如何从 C 程序内部或使用内联汇编获取 C 函数的大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11410037/