在过程中操作运行时堆栈 [英] Manipulating the Runtime Stack within a procedure

查看:67
本文介绍了在过程中操作运行时堆栈的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究一个包含两个过程的程序.一个将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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆