x86 汇编初学者:程序没有正确循环?
x86 Assembly Beginner: Program doesn't loop correctly?
下面程序的目标是接受最多 10 个带符号的 8 字节浮点数
-100 ≤ X ≤ 100 范围内的数字作为用户输入并将它们存储到数组中。使用 ReadFloat Irvine 方法接收用户输入。如果输入超出该范围的数字,则子例程应该停止执行,并且 return 到 eax 当前在数组中的值的数量。这只是一些旨在描述程序应该做什么的上下文。这段代码的问题是它在接受第一个值后没有正确循环。我将其设置为检查输入数字是否在 L1 中高于或等于 -100,然后在 L2 中低于或等于 100。如果数字超出该范围,则子例程应停止执行,但如果在该范围内,则应前进到 L3 和 R1。在 L3 和 R1 中,数字被放入 SFPArray 的索引中,如果数组中的值少于 10 个,程序应无条件跳回 L1 以进行进一步迭代。 R1 中的 JMP 命令就是问题所在。输入一个数字后,当前状态下的子程序将停止执行,我不明白为什么。谁能提供帮助?
INCLUDE c:\irvine\irvine32.inc
INCLUDELIB c:\irvine\irvine32.lib
INCLUDELIB c:\masm32\lib\user32.lib
INCLUDELIB c:\masm32\lib\kernel32.lib
.data
theSFPArray REAL8 10 dup(?) ;an array that can store up to 10 signed floating point numbers
tempStoreFP REAL8 ? ;this variable will temporarily store the FP number acquired from user input, and then push it onto the stack
lengthOfSFPArray DWORD ? ;this variable will store the length of theSFPArray. This value will be used to determine if requestSignedFloats should stop looping.
inputLoopCounter DWORD -1 ;used to determine when the requestSignedFloats subroutine should stop accepting input.
prompt BYTE "Please enter a value: ",0
.CODE
main PROC
call requestSignedFloats
exit
main ENDP
requestSignedFloats PROC
finit ;initializes floating point unit
push edx ;pushes the original value of edx onto the stack. This will be popped when the subroutine ends.
mov edx, OFFSET theSFPArray ;moves the offset of theSFPArray into edx so that values can be placed into it.
push edx ;pushes edx onto the stack while it contains the offset of the SFPArray for later usage.
mov eax,100
push eax
fild dword ptr [esp] ;get the 100 from memory and throw it onto the FPU, into ST(0)
fchs ;changes the 100 in ST(0) into -100
pop eax
L1:
mov edx,OFFSET prompt
call WriteString ;displays the String within the prompt variable on the screen.
call ReadFloat ;requests a float as input from the user and stores it at the top of the floating point stack, aka ST(0).
fcom ;compares the value in ST(1) to the value in ST(0).
jae L2
pop edx ;this line and the two lines below it will execute if the comparison dictates that ST(1) is below the value in ST(0). This should cause the subroutine to end.
pop edx ;a second pop of edx is necessary to restore edx to its original value since two alterations of edx were placed onto the stack at the beginning of the subroutine.
mov lengthOfSFPArray,LENGTHOF theSFPArray ;Moves the current number of values stored in theSFPArray into the lengthOfSFPArray variable.
mov eax,lengthOfSFPArray ;Returns in eax,the number of values in the array, as specified by the requirements
ret
L2:
fstp tempStoreFP ;pops the user input value off of the stack temporarily so that fchs can be used to change the sign of the value in ST(0)
fchs ;changes the -100 in ST(0) into a positive 100.
fld tempStoreFP ;pushes tempStoreFP back onto the stack so that its value is now in ST(1)
fcom
jbe L3
pop edx ;this line and the two lines below it will execute if the comparison dictates that ST(1) is below the value in ST(0). This should cause the subroutine to end.
pop edx ;a second pop of edx is necessary to restore edx to its original value since two alterations of edx were placed onto the stack at the beginning of the subroutine.
mov lengthOfSFPArray,LENGTHOF theSFPArray ;Moves the current number of values stored in theSFPArray into the lengthOfSFPArray variable.
mov eax,lengthOfSFPArray ;Returns in eax,the number of values in the array, as specified by the requirements
ret
L3:
pop edx ;this is done to pop the offset of theSFPArray off of the stack and back into edx since at this point edx still stores the "prompt".
inc inputLoopCounter ;increments inputLoopCounter so that its value is equal to the index that the number input by the user will be stored in.
mov ecx,inputLoopCounter ;uses inputLoopCounter to determine how many times the loop will execute.
R1:
inc edx ;increments edx an amount of times equivalent to the value stored in inputLoopCounter.
loop R1
fstp qword ptr [edx] ;takes the value at the top of the stack and stores it as a REAL8 at the address specified by edx (aka its array index)
mov lengthOfSFPArray,LENGTHOF theSFPArray ;Moves the current number of values stored in theSFPArray into the lengthOfSFPArray variable.
fchs ;changes the 100 in ST(0) to a -100 in preparation for the next iteration of the subroutine.
cmp inputLoopCounter,10
je L4
jmp L1 ;An unconditional jump to L1 that causes this subroutine to execute repeatedly. The line above this one prevents it from being an infinite loop.
L4:
mov eax,lengthOfSFPArray ;Returns in eax,the number of values in the array, as specified by the requirements
pop edx ;if the program makes it to this point, the offset of the array would have been popped off of the stack, meaning the original value of edx is the only thing
;remaining on the stack, so only one pop is necessary
ret
requestSignedFloats ENDP
在你的 .data
部分你定义 lengthOfSFPArray
像这样
lengthOfSFPArray DWORD ? ;this variable will store the length of theSFPArray. This value will be used to determine if requestSignedFloats should stop looping.
?
表示初始值未定义,因此介于 0 和 2^32-1 之间。
在 L1 中,您使用
检索 undefined
值
mov eax,lengthOfSFPArray ;Returns in eax,the number of values in the array, as specified by the requirements
所以 EAX
将是 undefined
或 lengthOfSFPArray
在初始化时的任何值。你在 L2.
中重复
在 R1 中,您将 lengthOfSFPArray
设置为
mov lengthOfSFPArray,LENGTHOF theSFPArray
到 theSFPArray
的 LENGTHOF,在 data
部分定义为
theSFPArray REAL8 10 dup(?)
根据定义,theSFPArray
中的元素数:LENGTHOF(theSFPArray) = 10
.
之后,你将10的值与10的值进行比较,总是TRUE
:
cmp lengthOfSFPArray,10
je L4 ; ALWAYS jump to L4
jmp L1 ; NEVER reached
L4:是你的退出标签,所以整个过程只执行一次。
下面程序的目标是接受最多 10 个带符号的 8 字节浮点数 -100 ≤ X ≤ 100 范围内的数字作为用户输入并将它们存储到数组中。使用 ReadFloat Irvine 方法接收用户输入。如果输入超出该范围的数字,则子例程应该停止执行,并且 return 到 eax 当前在数组中的值的数量。这只是一些旨在描述程序应该做什么的上下文。这段代码的问题是它在接受第一个值后没有正确循环。我将其设置为检查输入数字是否在 L1 中高于或等于 -100,然后在 L2 中低于或等于 100。如果数字超出该范围,则子例程应停止执行,但如果在该范围内,则应前进到 L3 和 R1。在 L3 和 R1 中,数字被放入 SFPArray 的索引中,如果数组中的值少于 10 个,程序应无条件跳回 L1 以进行进一步迭代。 R1 中的 JMP 命令就是问题所在。输入一个数字后,当前状态下的子程序将停止执行,我不明白为什么。谁能提供帮助?
INCLUDE c:\irvine\irvine32.inc
INCLUDELIB c:\irvine\irvine32.lib
INCLUDELIB c:\masm32\lib\user32.lib
INCLUDELIB c:\masm32\lib\kernel32.lib
.data
theSFPArray REAL8 10 dup(?) ;an array that can store up to 10 signed floating point numbers
tempStoreFP REAL8 ? ;this variable will temporarily store the FP number acquired from user input, and then push it onto the stack
lengthOfSFPArray DWORD ? ;this variable will store the length of theSFPArray. This value will be used to determine if requestSignedFloats should stop looping.
inputLoopCounter DWORD -1 ;used to determine when the requestSignedFloats subroutine should stop accepting input.
prompt BYTE "Please enter a value: ",0
.CODE
main PROC
call requestSignedFloats
exit
main ENDP
requestSignedFloats PROC
finit ;initializes floating point unit
push edx ;pushes the original value of edx onto the stack. This will be popped when the subroutine ends.
mov edx, OFFSET theSFPArray ;moves the offset of theSFPArray into edx so that values can be placed into it.
push edx ;pushes edx onto the stack while it contains the offset of the SFPArray for later usage.
mov eax,100
push eax
fild dword ptr [esp] ;get the 100 from memory and throw it onto the FPU, into ST(0)
fchs ;changes the 100 in ST(0) into -100
pop eax
L1:
mov edx,OFFSET prompt
call WriteString ;displays the String within the prompt variable on the screen.
call ReadFloat ;requests a float as input from the user and stores it at the top of the floating point stack, aka ST(0).
fcom ;compares the value in ST(1) to the value in ST(0).
jae L2
pop edx ;this line and the two lines below it will execute if the comparison dictates that ST(1) is below the value in ST(0). This should cause the subroutine to end.
pop edx ;a second pop of edx is necessary to restore edx to its original value since two alterations of edx were placed onto the stack at the beginning of the subroutine.
mov lengthOfSFPArray,LENGTHOF theSFPArray ;Moves the current number of values stored in theSFPArray into the lengthOfSFPArray variable.
mov eax,lengthOfSFPArray ;Returns in eax,the number of values in the array, as specified by the requirements
ret
L2:
fstp tempStoreFP ;pops the user input value off of the stack temporarily so that fchs can be used to change the sign of the value in ST(0)
fchs ;changes the -100 in ST(0) into a positive 100.
fld tempStoreFP ;pushes tempStoreFP back onto the stack so that its value is now in ST(1)
fcom
jbe L3
pop edx ;this line and the two lines below it will execute if the comparison dictates that ST(1) is below the value in ST(0). This should cause the subroutine to end.
pop edx ;a second pop of edx is necessary to restore edx to its original value since two alterations of edx were placed onto the stack at the beginning of the subroutine.
mov lengthOfSFPArray,LENGTHOF theSFPArray ;Moves the current number of values stored in theSFPArray into the lengthOfSFPArray variable.
mov eax,lengthOfSFPArray ;Returns in eax,the number of values in the array, as specified by the requirements
ret
L3:
pop edx ;this is done to pop the offset of theSFPArray off of the stack and back into edx since at this point edx still stores the "prompt".
inc inputLoopCounter ;increments inputLoopCounter so that its value is equal to the index that the number input by the user will be stored in.
mov ecx,inputLoopCounter ;uses inputLoopCounter to determine how many times the loop will execute.
R1:
inc edx ;increments edx an amount of times equivalent to the value stored in inputLoopCounter.
loop R1
fstp qword ptr [edx] ;takes the value at the top of the stack and stores it as a REAL8 at the address specified by edx (aka its array index)
mov lengthOfSFPArray,LENGTHOF theSFPArray ;Moves the current number of values stored in theSFPArray into the lengthOfSFPArray variable.
fchs ;changes the 100 in ST(0) to a -100 in preparation for the next iteration of the subroutine.
cmp inputLoopCounter,10
je L4
jmp L1 ;An unconditional jump to L1 that causes this subroutine to execute repeatedly. The line above this one prevents it from being an infinite loop.
L4:
mov eax,lengthOfSFPArray ;Returns in eax,the number of values in the array, as specified by the requirements
pop edx ;if the program makes it to this point, the offset of the array would have been popped off of the stack, meaning the original value of edx is the only thing
;remaining on the stack, so only one pop is necessary
ret
requestSignedFloats ENDP
在你的 .data
部分你定义 lengthOfSFPArray
像这样
lengthOfSFPArray DWORD ? ;this variable will store the length of theSFPArray. This value will be used to determine if requestSignedFloats should stop looping.
?
表示初始值未定义,因此介于 0 和 2^32-1 之间。
在 L1 中,您使用
检索undefined
值
mov eax,lengthOfSFPArray ;Returns in eax,the number of values in the array, as specified by the requirements
所以 EAX
将是 undefined
或 lengthOfSFPArray
在初始化时的任何值。你在 L2.
在 R1 中,您将 lengthOfSFPArray
设置为
mov lengthOfSFPArray,LENGTHOF theSFPArray
到 theSFPArray
的 LENGTHOF,在 data
部分定义为
theSFPArray REAL8 10 dup(?)
根据定义,theSFPArray
中的元素数:LENGTHOF(theSFPArray) = 10
.
之后,你将10的值与10的值进行比较,总是TRUE
:
cmp lengthOfSFPArray,10
je L4 ; ALWAYS jump to L4
jmp L1 ; NEVER reached
L4:是你的退出标签,所以整个过程只执行一次。