打印堆栈帧 [英] Printing Stack Frames

查看:184
本文介绍了打印堆栈帧的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我目前了解栈帧,我想尝试打印功能的堆栈帧(手动)。

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆