我正在学习堆栈(x86)。我知道这是根据LIFO原则运作的一堆数据。我知道有关堆栈的基本操作是push(在堆栈顶部添加一个值)和pop(删除一个值)。 ESP是我们现在在堆栈中的位置的参考。现在,我不明白:
示例:
Push 4
Push ebx
Push eax
上述说明将生成如下堆栈:
8 eax <-- ESP
4 ebx
0 4
ESP指向最后一个附加值eax。
现在,当我们使用pop操作扩展这些指令时,我们会得到以下内容:
Push 4
Push ebx
Pop ebx
Push eax
上面的说明应该在下面的堆栈中产生(如果我是正确的)(前三条指令):
4 (ebx)
0 4 <-- ESP
Ebx从堆栈中移除,ESP已向下移动4位。现在执行所有指令后的堆栈:
4 eax <-- ESP
0 4
我希望这里的一切都是正确的,如果不是评论更受欢迎;-) 现在为指令mov edx,[ebx,+ 04],从这篇文章的第一个堆栈开始。结果如下:
16 eax
8 edx <-- ESP
4 ebx
0 4
它将从ebx + 4位开始编写edx,将前一个值(eax)移到顶部,还是用edx替换eax?
第二个问题(更一般地说)是如何在堆栈上启动,寻址和删除数组的。
我为这个长期问题道歉,但我想了解堆栈的基础知识。感谢。
答案 0 :(得分:1)
您的例子和假设几乎是准确的。问题是堆栈增长了。所以你有地址0和4和8,而不是0xF8,0xF4,0xF0等。如果你在参考手册的说明中你会看到这样的东西:
PUSH:按操作数的大小递减SP(两个或四个字节值 是符号扩展)并将一个字从源传输到堆栈 顶部(SS:SP)。
所以如果sp(esp)在你启动时指向0xFC,那么
push 4 push ebx push eax
然后堆栈看起来像:
0xFC 4 0xF8 (ebx) 0xF4 (eax) <-- esp
所以访问[esp + 4]现在可能更有意义,因为它检索(ebx)值,[esp + 8]是被推送的直接4。
因此,如果您使用局部变量或数组进行反汇编或编译以汇编某些C程序,您将看到在函数输入时它们将向堆栈指针减去一些数字,足以覆盖所有局部变量,然后[esp]他们是如何访问内存的,所以初始化或归零,或者是基于esp的堆栈寻址的简单问题。
答案 1 :(得分:0)
我希望这里的一切都是 正确的,如果没有评论超过 欢迎;-)现在的指示 mov edx,[ebx,+ 04],从...开始 在这篇文章中第一次叠加。是个 以下结果:
16 eax 8 edx <-- ESP 4 ebx 0 4
它将从ebx + 4位开始写入 edx那里移动了以前的值 (eax)到顶部,或者它会被取代 ex与edx?
mov edx, [ebx + 4]
将移动[ebx + 4]
处的值(这是指针参考,除非ebx
指向堆栈,否则与当前堆栈无关(高级:它可能指向堆栈,但引用它不会以任何方式将堆栈)更改为edx
。这似乎与您的理解不同,不止一种方式。
首先,请记住mov
指令的参数用作mov DEST, SRC
,而不是相反。
其次,此mov
操作仅将[ebx + 4]
的值移动到edx
,因此不会以任何方式改变堆栈指针(ESP
)。堆栈将保持与您在此处引用的第一个堆栈保持不变。为清楚起见,堆栈将保持为:
8 eax <-- ESP
4 ebx
0 4
并且堆栈中的任何值都不会以任何方式更改。
另外,我假设您使用的是32位架构。在这种情况下,诸如eax
之类的寄存器将是32位(4字节)。请记住这些是4个BYTES而不是BITS。
你的“第二个问题”在这里有自己独立的问题,有更多信息。祝你好运!
答案 2 :(得分:0)
mov edx, [ebx+04]
获取地址es:ebx + 04的数据并将其放入edx。也许你的意思是mov [ebx+04], edx
?在这种情况下,它将覆盖地址es:ebx+4
处的所有内容。假设es指向堆栈段,并且ebx等于esp,那么堆栈将类似于:
12 edx <-- [ebx+4]
8 edx <-- esp = ebx
4 ebx
0 4
答案 3 :(得分:0)
问题非常错误。
push ebx
将ebx
寄存器的值放在堆栈中,而不是寄存器本身。通过将ebx
寄存器的值放在堆栈上,您不能将其用作寻址的基础。此外,没有指令(或方式)在内存中间“插入”某些内容。这是一个数组,而不是动态列表。
正如我在评论中所说,我认为你不了解集会的基本知识。阅读有关内存模型,寄存器,基本指令,编写一些程序的信息。