Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 在过程中操作运行时堆栈_Assembly_X86_Masm_Irvine32_Irvine16 - Fatal编程技术网

Assembly 在过程中操作运行时堆栈

Assembly 在过程中操作运行时堆栈,assembly,x86,masm,irvine32,irvine16,Assembly,X86,Masm,Irvine32,Irvine16,我正在编写一个包含两个过程的程序。一种是将N个无符号双字数组推送到堆栈中,另一种是从堆栈中弹出N个无符号双字并将其存储在数组中。我能够成功地将所有元素推送到堆栈,但由于堆栈指针(espregister)已更改,因此该过程无法返回到主程序 我已经能够通过操纵esp寄存器返回main,以便保存返回地址,并在返回之前将该地址重新加载到esp。但是,在调用下一个过程时,我推送到堆栈中的条目已被覆盖 在过程中工作时,是否有正确的方法将数据保存在堆栈中 以下是我的一些代码: 主要程序: main PROC

我正在编写一个包含两个过程的程序。一种是将N个无符号双字数组推送到堆栈中,另一种是从堆栈中弹出N个无符号双字并将其存储在数组中。我能够成功地将所有元素推送到堆栈,但由于堆栈指针(
esp
register)已更改,因此该过程无法返回到主程序

我已经能够通过操纵
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
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
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
在ArrayToStack过程中将阵列推送到堆栈:

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
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
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
在StackToArray过程中将堆栈写入控制台:

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
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
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

当过程p需要存储的数据的生存期超过了p的生存期时,数据不能存储在p的堆栈帧内的堆栈上,因为正如您所发现的,当p返回时,数据会“消失”

这里有几个其他的选择会起作用

  • 让调用过程(main)在其堆栈帧中为数据分配空间,并将指向该空间的指针传递给p。如果调用方知道或可以确定p将生成多少数据的最大大小,则此操作有效。调用者应该总是在传递指针的同时传递一个大小,这样P就不会超过分配的空间

  • 在p中使用malloc(或一些等价物),并将指向数据的指针返回给调用者


  • 检查你的房子。在第一段中,您讨论了将N个无符号双字数组推入堆栈的过程,但您的代码处理的是N个无符号字节数组

    此外,我注意到控制台上的输出顺序与arrray相反,并且代码在读取输入数组时将其归零。我把所有这些都保存在下面的解决方案中

    前两个代码段将保留
    ECX
    EDX
    。它们确实会重击EAX

    对编码问题的真正解释当然是看看堆栈是如何随着每个步骤而修改的。仔细看


    选项3:通过将返回地址复制到数组下方,使ESP保持修改状态的自定义调用约定。(例如,
    pop ecx
    输入以获取返回地址。将数据像std::vector一样推送到堆栈上,或者在堆栈上创建一个数组。使用
    push ecx
    /
    ret
    返回)调用函数的堆栈框架将增长,以包括这个新数组。@Peter,是的,我考虑过建议这样做(仅供专家使用)但是决定反对,因为这个答案不是针对专家的。