c++ 如何在调用过程之前将EAX设置为输入值

db2dz4w8  于 2023-03-20  发布在  其他
关注(0)|答案(2)|浏览(138)
.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD
INCLUDE Irvine32.inc

.data
prompt BYTE "Please enter the lower bound: ", 0
prompt2 BYTE "Please enter the upper bound: ", 0
lowerbound SDWORD ?
count DWORD ?

.code
main PROC

    mov ecx, 3

L1:
    mov count, ecx  
    mov ecx, 30 
    mov edx, OFFSET prompt
    call WriteString
    call ReadInt
    mov lowerbound, eax

    mov edx, OFFSET prompt2
    call WriteString
    call ReadInt
    mov ebx, lowerbound

L2:
    call BetterRandomRange
    call WriteInt
    call crlf
    loop L2
    
    mov ecx, count
    loop L1
    exit
    INVOKE ExitProcess,0
main ENDP

BetterRandomRange PROC ;loop 3 times

sub eax, ebx
call RandomRange
add eax, ebx            this keeps in within range but causes a division by zero error
;sub eax, ebx        no error but slightly out of range for the 30 iterations
ret

BetterRandomRange ENDP

END main

我试图完成基于用户输入生成M和N-1之间的整数的问题,其中M在EBX(下限)中,N在EAX(上限)中,数字在EAX中返回。
我已经在一定程度上找到了错误,因为在调用BetterRandomRange之前,上限没有存储在EAX中。但是,我不确定如何修复这个错误,因为EAX和EBX在第一次迭代中有正确的边界值。我是汇编新手,还在学习中,所以对我来说有点困惑。任何帮助都将不胜感激!

bzzcjhmw

bzzcjhmw1#

当你第一次调用BetterRandomRange时,它会改变eax中的值。另外,WriteIntcrlf也可能改变它,因为eax不跨函数保留。所以在第二次迭代中,eax包含crlf留在那里的任何东西,而不是上限。
你需要做的是存储上界(可能是一个静态变量,就像你在lowerbound中所做的那样),并在循环中每次调用'BetterRandomRange之前重新加载它。

i2loujxw

i2loujxw2#

首先输入你的 upperbound 并将其放入一个变量中:

mov  edx, OFFSET prompt2
call WriteString
call ReadInt            ; -> EAX
mov  upperbound, eax

然后输入您的 lowerbound 并将其放入EBX:

mov  edx, OFFSET prompt
call WriteString
call ReadInt            ; -> EAX
mov  ebx, eax           ; lowerbound
  • L2* 循环中的代码不会清除EBX寄存器,但EAX寄存器会被 BetterRandomRange 修改。因此,从其变量重新加载 upperbound

一个二个一个一个

  • L2* 循环不是运行了30次吗?是 L1 循环运行了3次。

对当前代码最快的修复方法是在堆栈上保留来自EAX的值:

L2:
    push eax                                <<<< new
    call BetterRandomRange  ; -> EAX
    call WriteInt
    call crlf
    pop  eax                                <<<< new
    loop L2
L2:

不是指令。L2 只对应于push eax指令(后面)在内存中的地址。这是循环的顶部。第一次ECX=30

push eax

堆栈指针ESP减4,EAX寄存器写入[esp]。(ESP指向保留的EAX)。

call BetterRandomRange  ; -> EAX

堆栈指针ESP减4,返回地址写入[esp]。接下来,指令指针EIP移动到 BetterRandomRange 过程,代码在此过程中为EAX计算新值,然后返回到此处。为了返回,从[esp]加载指令指针EIP,然后堆栈指针增加4。(ESP再次指向保留的EAX)。

call WriteInt

堆栈指针ESP减去4,返回地址写入[esp]。接下来,指令指针EIP移动到 WriteInt 过程,在此过程中,代码将EAX中的值写入屏幕,然后返回此处。WriteInt 可以在此过程中清除EAX寄存器。要返回,从[esp]加载指令指针EIP,然后堆栈指针上升4。(ESP再次指向保留的EAX)。

call crlf

堆栈指针ESP减4,返回地址写入[esp]。接下来,指令指针EIP移动到 crlf 过程,代码在此过程中向屏幕写入一个换行符,然后返回此处。crlf 在此过程中可以清除EAX寄存器。要返回,从[esp]加载指令指针EIP,然后堆栈指针上升4。(ESP再次指向保留的EAX)。

pop  eax

EAX寄存器从[esp]加载,然后堆栈指针增加4。EAX现在恢复为 upperbound 值。

loop L2

ECX寄存器递减,如果它不为零,则执行分支。然后执行在循环的顶部继续。如果ECX递减到零,则执行将在后面的行中失败,从而结束循环。

不要强迫自己在循环中使用loop指令

您的 L1 回路当前为:

mov ecx, 3
L1:
    mov count, ecx
    mov  ecx, 30

    ...

    mov ecx, count
    loop L1

您可以通过以下几种方法避免不建议使用的loop指令(因为它太慢):

mov  count, 3
L1:
  mov  ecx, 30    
  ...

  dec  count
  jnz  L1

另一种方法是:

mov  ecx, 3
L1:
  push ecx
  mov  ecx, 30

  ...

  pop  ecx
  dec  ecx
  jnz  L1

您可以通过类似的方式避免 L2 循环中的loop

相关问题