Assembly 在程序集Masm x86中推送到我自己的堆栈时出错
我不熟悉组装。我已经做了几个月了。当我尝试将值推送到自己的堆栈数组时,我遇到了一个错误,导致程序崩溃。错误显示为“访问冲突写入位置”。我用调试器检查了一下,什么也没找到。因此,我将生成错误的代码放在程序的开头,只是想看看是否有其他代码(目前为止只是从文件中读取)导致了错误。我仍然得到错误。请帮帮我,我不知道发生了什么事。这是我的密码:Assembly 在程序集Masm x86中推送到我自己的堆栈时出错,assembly,x86,stack,masm,Assembly,X86,Stack,Masm,我不熟悉组装。我已经做了几个月了。当我尝试将值推送到自己的堆栈数组时,我遇到了一个错误,导致程序崩溃。错误显示为“访问冲突写入位置”。我用调试器检查了一下,什么也没找到。因此,我将生成错误的代码放在程序的开头,只是想看看是否有其他代码(目前为止只是从文件中读取)导致了错误。我仍然得到错误。请帮帮我,我不知道发生了什么事。这是我的密码: .data myStack DWORD 30 DUP(?) top DWORD $ val DWORD 5 .code mov esi, OFFSE
.data
myStack DWORD 30 DUP(?)
top DWORD $
val DWORD 5
.code
mov esi, OFFSET myStack
mov eax, val
add esi, top
sub esi, 4
mov [esi], eax ;this is where it crashes
假设它逐渐变小,这是典型的基于微处理器的堆栈,然后将一些东西放到堆栈上:
mov eax, [esi]
add esi, 4
mov eax, [esi]
add esi, 4
top
和myStack
相加时,您将得到一个地址,该地址可能位于程序空间之外的其他地方。top
本身已经是堆栈顶部的地址,无需向其添加任何内容
因此,在您的例子中,top
已经是堆栈的顶部。因此,您的初始堆栈指针应该是top
:
.data
myStack DWORD 30 DUP(?)
top DWORD $
val DWORD 5
.code
mov esi, OFFSET top ; Initialize the stack pointer
mov eax, val ; Load a value into eax
sub esi, 4 ; push eax onto the stack
mov [esi], eax
在上面,从“堆栈指针”(最初是top
)中减去4将产生top-4
,这是myStack
区域中最后的4字节空间
要从堆栈中弹出值,请执行以下操作:
mov eax, [esi]
add esi, 4
或者,您可以以不同的方式设置top
,然后代码就可以工作了。但它稍微复杂一点:
.data
myStack DWORD 30 DUP(?)
top DWORD $-myStack ; the value here is current location minus myStack
val DWORD 5
.code
mov esi, OFFSET myStack ; Setup the stack pointer
add esi, top
mov eax, val ; get value in eax
sub esi, 4 ; push eax
mov [esi], eax
除非有压倒一切的理由说明堆栈必须像处理器的堆栈一样工作(即“顶部”向下生长),否则在分配的缓冲区末尾使用“顶部”更容易做到这一点。原因是你不必反省去做。堆栈变得与任何其他缓冲区一样。将第一个项目添加到第一个位置,并增长到分配的缓冲区的末尾 “推送”是指将一个项目添加到下一个可用位置。“Pop”是从最高使用位置移除的问题 请注意,效率与我的论点无关。无论哪种方式,你做的工作量都是一样的。这更容易考虑,因为堆栈的实现方式与任何其他数组类型的结构类似:您添加的第一项进入第一个(编号最低的)地址,等等。它只是一个按后进先出顺序访问的缓冲区 如果您按照我的建议实施:
.data
myStack DWORD 30 DUP(?)
top DWORD myStack
val DWORD 5
.code
MyPush:
// call with EAX containing the value you want to store
mov esi,[top]
mov [esi],eax
add esi,4
mov [top],esi
ret
MyPop:
// returns the value on the top of the stack in EAX
mov esi,[top]
sub esi,4
mov eax,[esi]
mov [top],esi
ret
啊!好的,非常感谢你,潜伏者!这是我第一次使用$,所以我很困惑。所以我永远不必加载myStack?@lisabits,
$
只是指当前的程序计数器。所以top
指向它自己地址的副本。在这种情况下,top
指向的值实际上并不重要,因为您使用标签来表示堆栈结束后的位置。@lisabits,如果您使用top-DWORD$-myStack
而不是top-DWORD$
,代码就会工作。是的,我知道$是当前地址。只是不知怎的,当我知道这件事时,我感到困惑。我猜我认为$本身就是在做$-myStack。很明显,我把这两个人搞混了。快到决赛了,哈哈。我的脑子快没了。谢谢@如果你觉得我的回答可以接受,如果你能把它标记为“接受”,我将不胜感激我想如果我那样做,我的教授会数到的。那么它就不是传统的堆栈了。不过,我现在一切都好了。只是一些需要对付的bug。谢谢,吉姆·米谢尔!我想让我大吃一惊的是,我从来没有在不加载的情况下访问过数组。我的意思是,我知道它会在记忆中的其他地方发生,但一开始我不知道为什么。现在一切都有意义了。@lisabits:不要把堆栈的实现与接口混淆起来。堆栈是一种抽象数据类型,可以向其中添加项。删除项目时,始终会获得最近添加的项目。如何实现其实并不重要。无论项目集合在缓冲区中是“向上”还是“向下”,或者您以某种方式随机存储它们,都是无关紧要的。重要的是,它以正确的顺序返回项目。看,我没有把它和任何东西混淆。我已经完成了程序并交了上来。我想说的是,我的教授告诉我们这样做,如果我不这样做,他可能会数数。我已经让他为比这更无关紧要的事情数数了。@Jim Mischel。。。为什么当我把标签放在评论的前面时,堆栈溢出会一直删除它们?我知道它没有那样对你。奇怪的