Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 打印堆叠框架_C_Assembly_Stack_X86 64 - Fatal编程技术网

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