Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从C程序内部或使用内联汇编获得C函数的大小?_C_Gcc_Assembly_Elf_Gnu Assembler - Fatal编程技术网

如何从C程序内部或使用内联汇编获得C函数的大小?

如何从C程序内部或使用内联汇编获得C函数的大小?,c,gcc,assembly,elf,gnu-assembler,C,Gcc,Assembly,Elf,Gnu Assembler,假设我有一个如下函数: # 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(

假设我有一个如下函数:

# 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?*/
并按如下方式编译:

# 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?*/
获取以下程序集结果:

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

为什么不在函数末尾计算函数指针和当前地址的差值?请查看此问题以恢复当前IP地址:,可能是此代码,:


要做到这一点,

有关函数大小的信息存储在对应符号(名称)的ELF属性中。C示例代码如何以编程方式解析此代码位于Solaris手册页的底部(Linux、*BSD和MacOS中也存在libelf,您需要查找
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:文件格式elf64-x86-64 部分: Idx名称大小VMA LMA文件关闭Algn 0.文本00000012 00000000000000000000000000000000000000000040 2**2 内容、分配、加载、只读、代码 [ ... ] 第节的分解。正文: 0000000000000000 : 0:55推送%rbp 1:48 89 e5 mov%rsp,%rbp 4:89 7d fc mov%edi,0xFFFFFFFFFFFFFC(%rbp) 7:89 75 f8移动%esi,0xFFFFFFFFFFFFF8(%rbp) a:8b 45 f8 mov 0xFFFFFFFFFFFFF8(%rbp),%eax d:03 45 fc添加0xFFFFFFFFFFFFFC(%rbp),%eax 10:c9/Q 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 $objdump-h-d--section=.text foo3.o foo3.o:文件格式elf64-x86-64 部分: Idx名称大小VMA LMA文件关闭Algn 0.文本0000000 4 000000000000000000000000000000000000000000000000 40 2**4 内容、分配、加载、只读、代码 [ ... ] 第节的分解。正文: 0000000000000000 : 0:8d 04 37 lea(%rdi,%rsi,1),%eax 3:c3 retq 注意“大小”从
0x12
更改为
4
?这就是来自
.size
汇编指令的内容

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

编辑:更多的外部和堆栈溢出参考:

  • 从gcc邮件列表中
  • sourceforge项目(这是文档/教程)

  • 这将是非常脆弱的,更不用说可移植性了。我不同意这个想法中的脆弱性,可能是你用来恢复地址的方式,AFAIK gcc应该有一些嵌入式方法来实现这一点,但我不记得名称。如果你改变优化选项或一些代码,您可以得到与实际情况大不相同的结果。
    return\u内置\u return\u地址(0)
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu不幸的是
    \u内置\u对象\u大小
    不起作用(至少对于gcc 4.7),符号/对象的大小可能是ELF符号表的一部分。但要使程序在运行时能够访问它,需要链接器,当然还需要汇编程序的支持。我还没有看到GNU汇编程序支持访问符号大小的任何证据。我相信GNU汇编程序和GNU链接器中根本没有支持。大小可能是符号表的一部分,仅用于调试目的。我不明白:您引用的objdump输出显示的是文本部分的大小,而不是单个函数的大小
    readelf-s
    但是确实显示了您提到的符号的
    st_size
    属性。