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
Assembly 当我将%esp移动到%ebp时会发生什么?_Assembly_Stack - Fatal编程技术网

Assembly 当我将%esp移动到%ebp时会发生什么?

Assembly 当我将%esp移动到%ebp时会发生什么?,assembly,stack,Assembly,Stack,我知道这是一个非常基本的问题,但这里是: 我开始学习汇编程序,我试图理解堆栈是如何工作的 首先,当我向汇编函数传递一个值时,我会这样访问它: movl 4(%esp),%eax # first parameter movl 8(%esp),%ebx # second parameter 但后来有人告诉我最好这样做: push %ebp movl %esp,%ebp # and then I'd access the values on %ebp: movl 8(%ebp),%eax mov

我知道这是一个非常基本的问题,但这里是:

我开始学习汇编程序,我试图理解堆栈是如何工作的

首先,当我向汇编函数传递一个值时,我会这样访问它:

movl 4(%esp),%eax  # first parameter
movl 8(%esp),%ebx  # second parameter
但后来有人告诉我最好这样做:

push %ebp
movl %esp,%ebp
# and then I'd access the values on %ebp:
movl 8(%ebp),%eax
movl 12(%ebp),%eax
pop %ebp
好的,这里有什么区别?当我直接从%esp访问这些值时,它们不是已经在堆栈上了吗?再次使用推送有什么好处

有没有人有一个好的学习工具(适用于dummies类型)来学习堆栈是如何工作的,这样就可以学习这些堆栈指针、返回地址等等?我还没有找到任何关于它如何工作的好的视觉演示。
谢谢

差异和原因都与堆栈帧有关。下面的链接有一个相当好的总结(如果我自己这么说的话)


在大多数情况下,使用%ebp有其历史原因:在16位程序中,x86 CPU不支持指令,如“movw 2(%sp),%ax”,因为x86 CPU仅支持用于内存寻址的%bx、%si、%di和%bp寄存器。因此,在16位程序中,不能使用%sp,因此使用%bp

当使用优化良好的现代编译器时,您将不再看到32位代码中的“push”和“mov%esp,%ebp”指令,但代码将类似于您的第一个示例(“4(%esp)”,而不是“8(%ebp)”)

这类编译器有时出于不同的目的使用%ebp寄存器

有一个用例仍然需要%ebp:alloca()函数:该函数通过执行“sub%eax,%esp”(或类似)指令在堆栈上保留内存。在这个指示之后,你不再知道你的论点在哪里了


但是,在具有“平面”内存布局的32位代码(%ds=%ss)中,您也可以使用任何其他寄存器而不是%ebp。

假设您在函数中的堆栈上推送了一些内容。如果在函数开头将当前堆栈指针复制到
ebp
,则在访问参数时不必跟踪对
esp
所做的更改。谢谢,@Michael。我想我只是对它们(
%ebp
%esp
)的功能以及我应该如何跟踪堆栈和地址感到困惑。顺便说一句,第二个并不是更好,除非有其他东西迫使您设置标准堆栈框架。这显然是更多的说明,而且你通常不会在设置本地设置后更改esp,因此esp与ebp一样稳定。你应该在互联网上找到很多关于堆栈工作原理的好草图。也许谷歌图书也能帮助你。当你想了解EBP的用途时,你需要在谷歌上搜索“堆栈框架”。堆栈框架是在堆栈的“内部”创建的自制结构。这是高级编程语言编译器在调用函数时生成的。每次调用函数时,编译器都会为被调用的函数创建堆栈帧。但是,当您自己编写汇编代码时,如果愿意,您可以手动创建堆栈框架。但是您不必这样做。使用EBP而不是ESI的原因是,默认情况下,EBP访问堆栈段,而ESI访问数据段。这些可以被覆盖,但目的是让寄存器以这种方式使用。谢谢,@Sparky。这是迄今为止关于stack最好的教程。我现在还不完全明白,但我更明白。但是我仍然不知道:1-什么时候事情会隐式地出现在堆栈上?2-基指针的确切用途是什么?3-由于将
%ebp
推送到堆栈有助于更轻松地跟踪变量,我是否应该在每个函数上使用它?@francisaugusto-基本指针用于标记当前堆栈帧。即使您将更多内容推送到堆栈中,EBP也不会更改,直到您进入下一个/上一个堆栈帧(但ESP会更改)。一般来说,如果例程调用另一个例程,则使用EBP和堆栈帧概念。如果不是,它是可选的。你越是习惯它,当你不需要它时,你就会学到越多。最后,通常只有少数情况下您可能需要担心隐式堆栈推送:包括调用、中断和异常。谢谢@Martin。但是,如果我需要局部变量,使用%ebp不是更好吗?这样我就不会混淆以前是
4(%esp)
的内容,然后通过向堆栈中添加一些内容而变成
8(%esp)
?如果手动编程较大的汇编代码,您是对的。对于较小的汇编代码,您可以对所有推送/弹出操作进行概述,这样您就可以使用x(%esp)。对于已编译代码,这不是一个参数,因为编译器不会“混淆”。