@Sorush,这是一个示例,可以帮助您更好地了解幕后发生的事情:
#include <stdio.h>
int main(void)
{
printf("begin\n");
printf("loop\n");
// declare a function pointer
int (*loopPtr)();
// set the function pointer to the current function
loopPtr = main;
// skip over the first printf();
loopPtr += 22;
// call the new location
loopPtr();
}
对我来说,它在编译时可以在 x86_64 上运行clang -O0
(嗯,它可以一直工作到堆栈耗尽,因为这是无限递归,并且每个函数调用都会遍历堆栈空间)。
我通过编译确定了偏移量 22,然后反汇编并main()
从 second 的地址中减去 start 的地址printf()
。
首先,我编译它:
clang -O0 test.c
然后拆开看:
otool -tv a.out
...产生了这个输出:
[...]
_main:
0000000100000ee0 pushq %rbp
0000000100000ee1 movq %rsp,%rbp
0000000100000ee4 subq $0x20,%rsp
0000000100000ee8 leaq 0x00000073(%rip),%rdi
0000000100000eef movb $0x00,%al
0000000100000ef1 callq 0x100000f40
0000000100000ef6 leaq 0x0000006c(%rip),%rdi
0000000100000efd movl %eax,0xf4(%rbp)
0000000100000f00 movb $0x00,%al
0000000100000f02 callq 0x100000f40
[...]
_main:
表示main()
函数的入口点,其首地址为0x100000ee0。第一callq
条指令对应于第一个printf()
调用,我想跳过它,所以我选择了紧随其后的地址:0x100000ef6。0x100000ef6 减去 0x100000ee0 是十进制的 22。