【问题标题】:How to get the size of a C function from inside a C program or with inline assembly?如何从 C 程序内部或使用内联汇编获取 C 函数的大小?
【发布时间】:2012-07-09 17:39:57
【问题描述】:

假设我有如下函数:

# 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 程序中使用 C 或内联 asm 以某种方式获取函数的大小吗?

【问题讨论】:

  • 不幸的是__builtin_object_size 不起作用(至少对于 gcc 4.7)
  • 符号/对象的大小可能是 ELF 符号表的一部分。但要使其在运行时可供程序访问,则需要链接器,当然还有汇编器支持。我还没有看到任何证据表明 GNU 汇编器支持访问符号的大小。我相信 GNU 汇编器和 GNU 链接器根本不支持。大小可能只是符号表的一部分,仅用于调试目的。

标签: c gcc assembly elf gnu-assembler


【解决方案1】:

为什么不取函数指针和函数末尾当前地址的差呢?看看这个问题恢复当前IP地址:Get address of current instruction for x86,可能是这个代码,stolen form one of the reply

unsigned long get_PC()
{
    unsigned long current_instruction;

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

    return current_instruction;
}

会成功的,

【讨论】:

【解决方案2】:

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

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

$ 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 :
   0: 8d 04 37 lea (%rdi,%rsi,1),%eax
   3:c3 retq

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

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

编辑:更多引用,外部以及 stackoverflow:

  1. 来自 gcc 邮件列表,thread on sizeof(function)
  2. what does sizeof (function name) return?
  3. Find size of a function in C
  4. LibELF by example sourceforge 项目(这是文档/教程)

【讨论】:

  • 我不明白:您引用的 objdump 输出显示的是文本部分的大小,而不是单个函数。 readelf -s 但是确实显示了您提到的符号的 st_size 属性。
猜你喜欢
  • 2012-11-17
  • 1970-01-01
  • 1970-01-01
  • 2014-07-24
  • 2021-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多