打印堆栈框架

所以我目前正在学习堆栈帧,我想实验打印一个函数的堆栈帧(手动)。

我有以下图片记住堆栈框架(我可能是错的):

| | 0xffff0fdc +--------------------------------+ | ... | 0xffff0fd8 +--------------------------------+ | parameter 2 | 0xffff0fd4 +--------------------------------+ | parameter 1 | 0xffff0fd0 +--------------------------------+ | return address | 0xffff0fcc +--------------------------------+ | local variable 2 | 0xffff0fc8 +--------------------------------+ | local variable 1 | 0xffff0fc4 +--------------------------------+ 

因此我首先写了这个函数来实现上面的结果并打印出来:

 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++ 

没有太大成功。 我的方法有什么问题?


我还有另一个问题:给定一个递归函数,简单地使用factorial(int n),我们如何找到基址指针在堆栈中的位置?


如果您需要汇编代码:请注意,这只包含函数“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:我不允许使用任何外部function

x86-64没有传递堆栈上的前几个参数(类型允许),因此您没有机会打印它们。 此外,本地的实际堆栈布局取决于编译器和设置。

由于您提供了汇编代码,我们可以检查如下所示的布局:

  return address rbp saved rbp rbp-8 local variable "sp" rbp-16 local variable "loc" rbp-20 local copy of argument "a" rbp-24 local copy of argument "b" 

还要注意ab是4个字节,其余的是8个。此外,C指针算术按项目大小缩放,因此*(sp+4)变为4 * 8 = 32个字节而不是4 ,这可能是你想要的。

如果堆栈布局未更改,则可以使用此代码作为说明:

 #include  #include  int main(); void func(int a,int b) { uint64_t loc = 0; char *sp = (char*)&loc; printf("main = %p\n", main); printf("return address = %p\n", *(void**)(sp + 24)); printf("saved 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); return 0; } 

样本输出:

 main = 0x4005e6 return address = 0x4005f9 saved rbp = 0x7ffe057bf240 sp = 0x7ffe057bf220 loc = 0 a = 2 b = 3