7

假设我有如下功能:

# 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 程序中以某种方式获取函数的大小吗?

4

2 回答 2

13

有关函数大小的信息存储在相应符号(名称)的ELF 属性中。如何以编程方式解析的 C 示例代码位于 Solaris 手册页的底部gelf_getsym(3ELF)(Linux、*BSD 和 MacOS 中确实存在 libelf,您需要查找结构的st_size字段GElf_Sym),但您也可以使用 objdump / elfdump (Solaris) / readelf (Linux) 用于任务:

$ objdump -h -d --section=.text foo3.o

foo3.o:文件格式elf64-x86-64

部分:
Idx 名称大小 VMA LMA 文件关闭 Algn
  0 .文本 00000012 0000000000000000 0000000000000000 00000040 2**2
                  内容、分配、加载、只读、代码
[ ... ]
部分.text的反汇编:

0000000000000000 <foo>:
   0: 55 推送 %rbp
   1: 48 89 e5 移动 %rsp,%rbp
   4: 89 7d fc mov %edi,0xfffffffffffffffc(%rbp)
   7: 89 75 f8 移动 %esi,0xffffffffffffff8(%rbp)
   a: 8b 45 f8 mov 0xfffffffffffffff8(%rbp),%eax
   d: 03 45 fc 添加 0xfffffffffffffffc(%rbp),%eax
  10:c9请假
  11:c3 回复

这是针对您的代码的未优化编译,而优化版本是:

$ objdump -h -d --section=.text foo3.o

foo3.o:文件格式elf64-x86-64

部分:
Idx 名称大小 VMA LMA 文件关闭 Algn
  0 .文本 00000004 0000000000000000 0000000000000000 00000040 2**4
                  内容、分配、加载、只读、代码
[ ... ]
部分.text的反汇编:

0000000000000000 <foo>:
   0: 8d 04 37 lea (%rdi,%rsi,1),%eax
   3:c3 retq

注意“大小”从0x12变为4? 这就是来自.size汇编程序指令的内容。

尝试使用内联汇编为您提供函数大小/代码位置的“技巧”不考虑编译器生成的胶水代码(函数入口序言/退出尾声,内联代码生成......),也不考虑编译器重新- 订购内联汇编(gcc 这样做是臭名昭著的),因此相信这一点通常不是一个好主意。最后,这取决于你到底想做什么......

编辑:更多的参考,外部以及stackoverflow:

  1. 从 gcc 邮件列表中,线程上sizeof(function)
  2. sizeof(函数名)返回什么?
  3. 在 C 中查找函数的大小
  4. LibELF 示例sourceforge 项目(这是文档/教程)
于 2012-07-10T09:57:08.850 回答
1

为什么不取函数指针和函数末尾当前地址的差呢?看看这个问题来恢复当前的 IP 地址:Get address of current instruction for x86,可能是这个代码,被盗形式的回复之一

unsigned long get_PC()
{
    unsigned long current_instruction;

    __asm__ __volatile__
    (
        "movq 8(%rbp), %rax\n\t"
        : "=a" (current_instruction)
    );

    return current_instruction;
}

会做的伎俩,

于 2012-07-10T09:19:59.613 回答