Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.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
“有什么用?”;按%ebp;移动百分比esp,%ebp“;由GCC为x86生成?_Gcc_Assembly_X86 - Fatal编程技术网

“有什么用?”;按%ebp;移动百分比esp,%ebp“;由GCC为x86生成?

“有什么用?”;按%ebp;移动百分比esp,%ebp“;由GCC为x86生成?,gcc,assembly,x86,Gcc,Assembly,X86,这两条指令对gcc为x86机器生成的汇编代码有什么影响: push %ebp movl %esp, %ebp 这是在函数开头看到的典型代码 它将EBP寄存器的内容保存在堆栈上,然后将当前堆栈指针的内容存储在EBP中 堆栈在函数调用期间用于存储本地参数。但在函数中,堆栈指针可能会更改,因为值存储在堆栈上 如果保存堆栈的原始值,则可以通过EBP寄存器引用存储的参数,同时仍然可以使用(向堆栈添加值) 在函数的末尾,您可能会看到命令 pop %ebp ; restore original valu

这两条指令对gcc为x86机器生成的汇编代码有什么影响:

push %ebp
movl %esp, %ebp

这是在函数开头看到的典型代码

它将EBP寄存器的内容保存在堆栈上,然后将当前堆栈指针的内容存储在EBP中

堆栈在函数调用期间用于存储本地参数。但在函数中,堆栈指针可能会更改,因为值存储在堆栈上

如果保存堆栈的原始值,则可以通过EBP寄存器引用存储的参数,同时仍然可以使用(向堆栈添加值)

在函数的末尾,您可能会看到命令

pop %ebp   ; restore original value 
ret        ; return 

这是我们所知的

它保存函数结束时将要检索的当前基指针,并将新ebp设置为新帧的开头

push %ebp
这将推动堆栈上的32位(扩展)基指针寄存器,即堆栈指针(%esp)减去四,然后将%ebp的值复制到堆栈指针指向的位置

movl %esp, %ebp
这会将堆栈指针寄存器复制到基指针寄存器


将堆栈指针复制到基指针的目的是创建堆栈帧,即堆栈上的子例程可以存储本地数据的区域。子例程中的代码将使用基指针引用数据。

unwind的解释是字面真理(尽管有一个小的方向错误),但没有解释原因

%ebp
是堆栈帧的“基本指针”。它是C运行时用来访问堆栈上的局部变量和参数的指针。下面是GCC(G++精确生成)的一些典型函数序言代码,首先是C++源。
// junk.c++
int addtwo(int a)
{
    int x = 2;

    return a + x;
}
这将生成以下汇编程序

.file   "junk.c++"
    .text
.globl _Z6addtwoi
    .type   _Z6addtwoi, @function
_Z6addtwoi:
.LFB2:
    pushl   %ebp
.LCFI0:
    movl    %esp, %ebp
.LCFI1:
    subl    $16, %esp
.LCFI2:
    movl    $2, -4(%ebp)
    movl    -4(%ebp), %edx
    movl    8(%ebp), %eax
    addl    %edx, %eax
    leave
    ret
.LFE2:
    .size   _Z6addtwoi, .-_Z6addtwoi
    .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
    .section    .note.GNU-stack,"",@progbits
现在要解释序言代码(前面的所有内容)
.LCFI2:
,首先:

  • pushl%ebp
    将调用函数的堆栈帧存储在堆栈上
  • movl%esp,%ebp
    获取当前堆栈指针并将其用作被调用函数的帧
  • subl$16,%esp
    为局部变量留出了空间
  • 现在,您的函数已准备就绪。与
    %ebp%
    寄存器具有负偏移量的任何引用都是本地变量(
    x
    )。任何与
    %ebp%
    寄存器有正偏移的引用都是传入的参数


    最后一点是
    leave
    指令,它是一条x86汇编指令,用于恢复调用函数的堆栈帧。这通常在C代码中以更快的
    移动%ebp%esp
    pop%ebp%
    顺序进行优化。然而,出于说明目的,我根本没有在编译时进行任何优化。

    我还认为在编译之后经常注意这一点很重要
    推送%ebp
    movl%esp%ebp
    组件将具有
    push%ebx
    push%edx
    。这些是寄存器
    %ebx
    %edx
    的调用方保存。在例程调用结束时,寄存器将恢复为其原始值


    另外-
    %ebx、%esi、%edi都是被叫方保存寄存器。因此,如果要覆盖它们,您需要先保存它们,然后恢复它们。

    这段代码为您的程序设置堆栈。

    在x86中,堆栈信息由两个寄存器保存

    
        Base pointer (bp): Holds starting address of the stack
        Stack pointer (sp): Holds the address in which next value will be stored
    
    这些寄存器在不同模式下具有不同的名称:

    
                                
    Base pointer           Stack pointer
    16 bit real mode: bp sp 32 bit protected mode: ebp(%ebp) esp(%esp) 64 bit mode: rbp rsp
    设置堆栈时,堆栈指针和基指针在开始时获得相同的地址

    现在解释一下你的代码

    
        push %ebp
    
    此代码将当前堆栈地址推入堆栈,以便函数可以正确地“退出”或“返回”。

    
        movl %esp, %ebp
    
    此代码为函数设置堆栈。

    有关更多信息,请参阅此。


    希望这有帮助

    除此之外,还有各种调用约定,用于控制将输入参数推送到堆栈上的顺序,以及在函数完成后谁将进行清理。
    movl%ebp,%esp/popl%ebp/ret
    -->首先还原
    esp
    ,然后弹出
    ebp
    前面没有描述最后一句话。谢谢你!向上投票。