在过程中操作运行时堆栈 [英] Manipulating the Runtime Stack within a procedure
问题描述
我正在研究一个包含两个过程的程序.一个将N个无符号双字的数组压入堆栈,另一个将N个无符号双字的堆栈弹出并存储在数组中.我能够将所有元素成功推入堆栈,但是由于堆栈指针( esp
寄存器)已更改,因此该过程无法返回到主程序.
通过操作 esp
寄存器,我可以返回到 main ,以便保存返回地址,然后将该地址重新加载到 esp 代码>返回之前.但是,到调用下一个过程时,我压入堆栈的条目已被覆盖.
在过程中工作时,是否有正确的方法将数据保存在堆栈中?
这是我的一些代码:
主要过程:
主PROCmain_loop:;主菜单mov edx,偏移量选择提示调用WriteStringread_input:致电ReadIntjno good_inputjmp main_loopgood_input:cmp eax,0je create_vectorcmp eax,1je array_stackcmp eax,2je stack_arraycmp eax,-1je end_program呼叫crlfjmp main_loopcreate_vector:调用CreateVectorjmp end_optionsarray_stack:调用ArrayToStackjmp end_optionsstack_array:调用StackToArrayjmp end_optionsend_options:呼叫crlfjmp main_loopend_program:mov edx,偏移量退出提示调用WriteString呼叫crlf出口主要ENDP
在 ArrayToStack 过程中将数组推入堆栈:
mov esi,偏移向量mov ebx,N十二月ebxmov eax,0mov ecx,-1push_array_loop:ecxmov al,[esi + ecx]推emov [esi + ecx],字节ptr(0)cmp ecx,ebxjl push_array_loop
通过 StackToArray 过程将堆栈写入控制台:
mov eax,Nmov ebx,4mul ebxmov ebx,eaxmov ecx,0write_stack_loop:mov eax,[esp + ecx]添加ecx,4呼叫WriteDecmov edx,偏移空间调用WriteStringcmp ecx,ebxjl write_stack_loop
检查您的房屋.在第一段中,您将讨论一个将N个无符号双字数组推入堆栈的过程,但是您的代码处理了N个无符号 bytes 数组.>
此外,我观察到您在控制台上的输出将以相反的顺序(到错误),并且您的代码在读取输入数组时将其归零.我将所有这些内容保留在下面的解决方案中.
前2个代码段将保留 ECX
和 EDX
.他们确实破坏了 EAX
.
您的编码问题的真正解释当然是看堆栈如何在每个步骤中被修改.小心点!
ArrayToStack:[ret]^ espmov eax,N;数组元素的数量是运行时值十进制shl eax,2sub esp,eax<-- eax = (N-1)*4 -->[] [...] [] [ret]^ esp推dword ptr [esp + eax][ret] [] [...] [] []^ esp推ECX推edx[edx] [ecx] [ret] [] [...] [] []^ espXor ecx,ecxToStack:异或edx,edxxchg dl,[Vector + ecx];在将源清零的同时读取字节大小的元素mov [esp + 12 + eax],edxecx次级eax,4jnb ToStack[edx] [ecx] [ret] [a_N] [...] [a_2] [a_1]^ esp ^ esp + 12流行版流行音乐[ret] [a_N] [...] [a_2] [a_1]^ esp撤退;EAX以-4结尾[a_N] [...] [a_2] [a_1]^ espStackToConsoleProcedure:[ret] [a_N] [...] [a_2] [a_1]^ esp推ecx推edx[edx] [ecx] [ret] [a_N] [...] [a_2] [a_1]^ esp ^ esp + 12Xor ecx,ecx从堆栈:mov eax,[esp + 12 + ecx * 4]呼叫WriteDecmov edx,偏移空间调用WriteStringecxcmp ecx,Njb FromStackshl ecx,2;ECX = N * 4mov eax,[esp + 8];取回地址mov [esp + 8 + ecx],eax< -------- ecx = N * 4 ------->[ edx ][ ecx ][ ][ a_N ][ ... ][ a_2 ][ ret ]^ esp ^ esp + 8mov eax,ecx流行版流行音乐< -------- eax = N * 4 ------->[] [a_N] [...] [a_2] [ret]^ esp添加esp,eax[返回]^ esp撤退;EAX以N * 4结尾
如果不需要保留 ECX
和 EDX
寄存器,但是仍然允许 EAX
遭到破坏:
ArrayToStack:mov eax,N十进制shl eax,2子 esp, eax推dword ptr [esp + eax]Xor ecx,ecxToStack:异或edx,edxxchg dl,[向量+ ecx]mov [esp + 4 + eax],edxecx次级eax,4jnb ToStack退回StackToConsoleProcedure:Xor ecx,ecx起点:mov eax,[esp + 4 + ecx * 4]呼叫WriteDecmov edx,偏移空间调用WriteStringecxcmp ecx,Njb FromStackshl ecx,2流行曲添加esp,ecx推e退回
I am working on a program that contains two procedures. One that pushes an array of N unsigned double words to the stack, and one that pops N unsigned double words from the stack and stores them in an array. I am able to push all the elements successfully to the stack, but then the procedure cannot return to the main program because the stack pointer (esp
register) has been changed.
I have been able to return to main by manipulating the esp
register so that the return address is saved, and I reload that address into esp
before I return. However, by the time the next procedure is called the entries I pushed to the stack have been overwritten.
Is there a correct way to save data in the stack while working in a procedure?
Here is some of my code:
Main procedure:
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
Pushing the array to the stack in the ArrayToStack procedure:
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
Writing the stack to the console in the StackToArray procedure:
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
Chech your premises. In your first paragraph you talk about a procedure that pushes an array of N unsigned double words to the stack, but your code deals with an array of N unsigned bytes.
Furthermore I observe that your output on the console will be in reverse order (to the arrray) and that your code zeroes the input array as it gets read. I've kept all of these things in below solutions.
The first 2 snippets will preserve ECX
and EDX
. They do clobber EAX
.
The true explanation for your coding problem is of course to see how the stack gets modified with each step. Watch carefully!
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
If there's no need to preserve the ECX
and EDX
registers, but still allowing EAX
to get clobbered:
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
这篇关于在过程中操作运行时堆栈的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!