我编写了一个基本的C程序,该程序定义了一个整数变量x,将其设置为零并返回该变量的值:

#include <stdio.h>

int main(int argc, char **argv) {
    int x;
    x = 0;
    return x;
}

当我使用objdump转储目标代码时(在Linux X86-64上使用gcc编译):
0x0000000000400474 <main+0>:    push   %rbp
0x0000000000400475 <main+1>:    mov    %rsp,%rbp
0x0000000000400478 <main+4>:    mov    %edi,-0x14(%rbp)
0x000000000040047b <main+7>:    mov    %rsi,-0x20(%rbp)
0x000000000040047f <main+11>:   movl   $0x0,-0x4(%rbp)
0x0000000000400486 <main+18>:   mov    -0x4(%rbp),%eax
0x0000000000400489 <main+21>:   leaveq
0x000000000040048a <main+22>:   retq

我可以看到函数序言,但是在我们将x设置为0x000000000040047f的x之前,有两条指令将%edi和%rsi移到堆栈上。这些是做什么用的?

另外,与我们将x设置为0的情况不同,GAS语法中所示的mov指令没有后缀。



在这种情况下,-0x14(%rsbp)-0x20(%rbp)都是内存操作数,它们的大小是多少?由于%edi是32位寄存器,因此32位移至-0x14(%rsbp)吗?而由于%rsi是64位寄存器,则64位移至%rsi,-0x20(%rbp)吗?

最佳答案

在这种简单情况下,为什么不直接询问编译器?对于GCC,clang和ICC,有-fverbose-asm选项。

main:
    pushq   %rbp    #
    movq    %rsp, %rbp  #,
    movl    %edi, -20(%rbp) # argc, argc
    movq    %rsi, -32(%rbp) # argv, argv
    movl    $0, -4(%rbp)    #, x
    movl    -4(%rbp), %eax  # x, D.2607
    popq    %rbp    #
    ret

因此,是的,由于新的体系结构允许直接从堆栈指针中减去/添加到堆栈指针,因此它们通过使用“旧”帧指针方法将argvargv保存到堆栈中,从而省略了帧指针(-fomit-frame-pointer)。

关于c - mov%edi和mov%rsi的指令有什么作用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31405187/

10-11 23:10