打印堆栈帧 [英] Printing Stack Frames
问题描述
所以,我目前了解栈帧,我想尝试打印功能的堆栈帧(手动)。
So I am currently learning about stack frames, and I wanted to experiment printing the stack frame (manually) of a function.
我有一个堆栈帧的心灵下面的图片(我可能是错的):
I have the following picture in mind of a stack frame (I may be wrong):
| | 0xffff0fdc
+--------------------------------+
| ... | 0xffff0fd8
+--------------------------------+
| parameter 2 | 0xffff0fd4
+--------------------------------+
| parameter 1 | 0xffff0fd0
+--------------------------------+
| return address | 0xffff0fcc
+--------------------------------+
| local variable 2 | 0xffff0fc8
+--------------------------------+
| local variable 1 | 0xffff0fc4
+--------------------------------+
所以我第一次写这个函数来实现上述结果,并打印出来:
thus I first wrote this function to achieve the above result and print it :
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
绝对不是什么预期
definitely not what was expected
我也试过扫描通过堆栈找到论据之一:
I also tried "scanning" through the stack to find one of the argument :
while (*sp != a) sp++
但没有成功。什么是错我的方法?
without much success. What is wrong with my method ?
我也有另外一个问题:
给定一个递归函数,只需取阶乘(INT N),我们怎么能现货的里基指针位于堆栈中的地址?
I also had another question : Given a recursive function, take simply factorial(int n), how could we spot the address where the base pointer is located in the stack ?
如果你需要组装code:
请注意,这仅包含函数FUNC生成的汇编code。
我添加了注释到大会code涉及源$ C $ C。
in case you need the assembly code : Note that this only contains the function "func" generated assembly code. I added comments to where the assembly code relates to the source code.
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
任何建议,以帮助我undertand栈更好的将是极大的AP preciated!
Any advices to help me undertand the stack better would be greatly appreciated!
PS:我不允许使用任何外部函数
PS : I am not allowed to use any external functions
推荐答案
X86-64未通过前几个参数堆栈(类型允许),这样你就没有机会来打印这些。此外,对于当地人的实际堆栈布局取决于编译器和设置。
x86-64 does not pass the first few arguments on the stack (type permitting) so you have no chance to print those. Also, the actual stack layout for the locals depends on compiler and settings.
由于您提供的组装code,我们可以检查它看起来像这样的布局:
Since you have provided the assembly code, we can examine the layout which looks like this:
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"
另外请注意, A
和 B
4个字节,其余均为8.此外,C指针运算秤按项目大小,所以 *(SP + 4)
进入 4 * 8 = 32
字节不 4
因为你可能预期。
Also note that a
and b
are 4 bytes, the rest are 8. Furthermore, C pointer arithmetic scales by item size, so *(sp+4)
goes 4 * 8 = 32
bytes not 4
as you probably intended.
如果堆栈布局是不变的,你可以使用这个code作为例证:
If the stack layout is unchanged, you can use this code as illustration:
#include <stdio.h>
#include <stdint.h>
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
这篇关于打印堆栈帧的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!