我正在开发一个包含两个程序的程序。一个将N个无符号双字数组推送到堆栈,另一个从堆栈中弹出N个无符号双字并将它们存储在数组中。我能够将所有元素成功地推送到堆栈,但是程序无法返回到主程序,因为堆栈指针(esp
寄存器)已被更改。
我已经能够通过操纵esp
寄存器返回main,以便保存返回地址,并在返回之前将该地址重新加载到esp
中。但是,在调用下一个过程时,我推送到堆栈的条目已被覆盖。
在处理过程中是否有正确的方法将数据保存在堆栈中?
这是我的一些代码:
主要程序:
main PROC
main_loop:
; Main menu
mov edx, offset choicePrompt
call WriteString
read_input:
call ReadInt
jno good_input
jmp main_loop
good_input:
cmp eax, 0
je create_vector
cmp eax, 1
je array_stack
cmp eax, 2
je stack_array
cmp eax, -1
je end_program
call crlf
jmp main_loop
create_vector:
call CreateVector
jmp end_options
array_stack:
call ArrayToStack
jmp end_options
stack_array:
call StackToArray
jmp end_options
end_options:
call crlf
jmp main_loop
end_program:
mov edx, offset exitPrompt
call WriteString
call crlf
exit
main ENDP
在ArrayToStack过程中将数组推送到堆栈:
mov esi, offset Vector
mov ebx, N
dec ebx
mov eax, 0
mov ecx, -1
push_array_loop:
inc ecx
mov al, [esi + ecx]
push eax
mov [esi + ecx], byte ptr(0)
cmp ecx, ebx
jl push_array_loop
在StackToArray过程中将堆栈写入控制台:
mov eax, N
mov ebx, 4
mul ebx
mov ebx, eax
mov ecx, 0
write_stack_loop:
mov eax, [esp + ecx]
add ecx, 4
call WriteDec
mov edx, offset spacePrompt
call WriteString
cmp ecx, ebx
jl write_stack_loop
检查你的房屋。在第一段中,您将讨论将N个无符号双字数组推送到堆栈的过程,但是您的代码处理的是N个无符号字节的数组。
此外,我观察到控制台上的输出将以相反的顺序(到arrray),并且您的代码在读取时将输入数组归零。我把所有这些东西保存在下面的解决方案中。
前2个片段将保留ECX
和EDX
。他们做clobber EAX
。
编码问题的真正解释当然是看每个步骤如何修改堆栈。仔细观察!
ArrayToStack:
[ ret ]
^ esp
mov eax, N ; The number of array elements is a runtime value
dec eax
shl eax, 2
sub esp, eax
<-- eax = (N-1)*4 -->
[ ][ ... ][ ][ ret ]
^ esp
push dword ptr [esp + eax]
[ ret ][ ][ ... ][ ][ ]
^ esp
push ecx
push edx
[ edx ][ ecx ][ ret ][ ][ ... ][ ][ ]
^ esp
xor ecx, ecx
ToStack:
xor edx, edx
xchg dl, [Vector + ecx] ; Reading byte-sized element while zeroing the source
mov [esp + 12 + eax], edx
inc ecx
sub eax, 4
jnb ToStack
[ edx ][ ecx ][ ret ][ a_N ][ ... ][ a_2 ][ a_1 ]
^ esp ^ esp+12
pop edx
pop ecx
[ ret ][ a_N ][ ... ][ a_2 ][ a_1 ]
^ esp
ret ; EAX ends at -4
[ a_N ][ ... ][ a_2 ][ a_1 ]
^ esp
StackToConsoleProcedure:
[ ret ][ a_N ][ ... ][ a_2 ][ a_1 ]
^ esp
push ecx
push edx
[ edx ][ ecx ][ ret ][ a_N ][ ... ][ a_2 ][ a_1 ]
^ esp ^ esp+12
xor ecx, ecx
FromStack:
mov eax, [esp + 12 + ecx*4]
call WriteDec
mov edx, offset spacePrompt
call WriteString
inc ecx
cmp ecx, N
jb FromStack
shl ecx, 2 ; ECX = N*4
mov eax, [esp + 8] ; Fetch return address
mov [esp + 8 + ecx], eax
<-------- ecx = N*4 ------->
[ edx ][ ecx ][ ][ a_N ][ ... ][ a_2 ][ ret ]
^ esp ^ esp+8
mov eax, ecx
pop edx
pop ecx
<-------- eax = N*4 ------->
[ ][ a_N ][ ... ][ a_2 ][ ret ]
^ esp
add esp, eax
[ ret ]
^ esp
ret ; EAX ends at N*4
如果没有必要保留ECX
和EDX
寄存器,但仍然允许EAX
被破坏:
ArrayToStack:
mov eax, N
dec eax
shl eax, 2
sub esp, eax
push dword ptr [esp + eax]
xor ecx, ecx
ToStack:
xor edx, edx
xchg dl, [Vector + ecx]
mov [esp + 4 + eax], edx
inc ecx
sub eax, 4
jnb ToStack
ret
StackToConsoleProcedure:
xor ecx, ecx
Fromtack:
mov eax, [esp + 4 + ecx*4]
call WriteDec
mov edx, offset spacePrompt
call WriteString
inc ecx
cmp ecx, N
jb FromStack
shl ecx, 2
pop eax
add esp, ecx
push eax
ret
当过程P需要存储寿命超过P的生命周期的数据时,数据不能存储在P的堆栈帧内的堆栈中,因为正如您所发现的,当P返回时它会“消失”。
以下是其他一些可行的选项。