C 打印堆叠框架
因此,我目前正在学习堆栈帧,我想尝试(手动)打印函数的堆栈帧 我脑海中有一个堆栈帧的以下图片(我可能错了): 因此,我首先编写此函数以实现上述结果并将其打印出来:C 打印堆叠框架,c,assembly,stack,x86-64,C,Assembly,Stack,X86 64,因此,我目前正在学习堆栈帧,我想尝试(手动)打印函数的堆栈帧 我脑海中有一个堆栈帧的以下图片(我可能错了): 因此,我首先编写此函数以实现上述结果并将其打印出来: void func(int a,int b) { uint64_t loc = 0; uint64_t *sp = &loc; printf("%" PRIu64 "\n",*(sp)); printf("%" PRIu64 "\n",*(sp+4)); printf("%" PRIu
void func(int a,int b)
{
uint64_t loc = 0;
uint64_t *sp = &loc;
printf("%" PRIu64 "\n",*(sp));
printf("%" PRIu64 "\n",*(sp+4));
printf("%" PRIu64 "\n",*(sp+8));
printf("%" PRIu64 "\n",*(sp+12));
}
int main()
{
func(2,3);
return 0;
}
我得到:
0
12884901890
51266344552759297
18034967110614932
绝对不是预期的那样
我还尝试“扫描”堆栈以找到其中一个参数:
while (*sp != a) sp++
没有多少成功。我的方法有什么问题
我还有一个问题: 给定一个递归函数,以简单阶乘(intn)为例,我们如何确定基指针在堆栈中的位置
如果您需要汇编代码: 请注意,这只包含函数“func”生成的汇编代码。 我在汇编代码与源代码相关的地方添加了注释
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl %edi, -20(%rbp)
movl %esi, -24(%rbp)
***// uint64_t loc = 0;***
movq $0, -16(%rbp)
***// uint64_t *sp = &loc;***
leaq -16(%rbp), %rax
movq %rax, -8(%rbp)
***// printf("%" PRIu64 "\n",*sp);***
movq -8(%rbp), %rax
movq (%rax), %rax
movq %rax, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf
***printf("%" PRIu64 "\n",*(sp+8));***
movq -8(%rbp), %rax
addq $64, %rax
movq (%rax), %rax
movq %rax, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf
***// printf("%" PRIu64 "\n",*(sp+16));***
movq -8(%rbp), %rax
subq $-128, %rax
movq (%rax), %rax
movq %rax, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf
***// printf("%" PRIu64 "\n",*(sp+32));***
movq -8(%rbp), %rax
addq $256, %rax
movq (%rax), %rax
movq %rax, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf
leave
.cfi_def_cfa 7, 8
ret
任何能帮助我更好地理解堆栈的建议都将不胜感激
PS:我不允许使用任何外部函数x86-64不传递堆栈上的前几个参数(类型允许),因此您没有机会打印这些参数。此外,局部变量的实际堆栈布局取决于编译器和设置 由于您提供了汇编代码,我们可以检查布局,如下所示:
返回地址
rbp已保存rbp
rbp-8局部变量“sp”
rbp-16局部变量“loc”
rbp-20参数“a”的本地副本
rbp-24参数“b”的本地副本
还要注意,a
和b
是4个字节,其余是8个字节。此外,C指针算术按项目大小进行缩放,因此*(sp+4)
将4*8=32
字节数设置为4
如果堆栈布局不变,则可以使用以下代码作为说明:
#包括
#包括
int main();
无效函数(整数a,整数b)
{
uint64_t loc=0;
char*sp=(char*)&loc;
printf(“main=%p\n”,main);
printf(“返回地址=%p\n”,*(void**)(sp+24));
printf(“保存的rbp=%p\n”,*(void**)(sp+16));
printf(“sp=%p\n”,*(void**)(sp+8));
printf(“loc=%lld\n”,*(uint64_t*)(sp));
printf(“a=%d\n”,*(int*)(sp-4));
printf(“b=%d\n”,*(int*)(sp-8));
}
int main()
{
func(2,3);
返回0;
}
样本输出:
main=0x4005e6
返回地址=0x4005f9
保存的rbp=0x7ffe057bf240
sp=0x7ffe057bf220
loc=0
a=2
b=3
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl %edi, -20(%rbp)
movl %esi, -24(%rbp)
***// uint64_t loc = 0;***
movq $0, -16(%rbp)
***// uint64_t *sp = &loc;***
leaq -16(%rbp), %rax
movq %rax, -8(%rbp)
***// printf("%" PRIu64 "\n",*sp);***
movq -8(%rbp), %rax
movq (%rax), %rax
movq %rax, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf
***printf("%" PRIu64 "\n",*(sp+8));***
movq -8(%rbp), %rax
addq $64, %rax
movq (%rax), %rax
movq %rax, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf
***// printf("%" PRIu64 "\n",*(sp+16));***
movq -8(%rbp), %rax
subq $-128, %rax
movq (%rax), %rax
movq %rax, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf
***// printf("%" PRIu64 "\n",*(sp+32));***
movq -8(%rbp), %rax
addq $256, %rax
movq (%rax), %rax
movq %rax, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf
leave
.cfi_def_cfa 7, 8
ret