汇编:索引问题
Assembly: Issues with Indexing
我无法弄清楚如何在我的循环中进行索引。我知道 esi
用于索引,所以我正在尝试使用它...
scores DWORD MAXIMUMSCORES DUP(0)
optionPromptMsg byte "Type 1 to continue or -1 to exit: ", 0
scorePromptMsg byte "Enter your numeric score (0-100): ", 0
scoreErrorMsg byte "Score out of range (0-100)!", 0
optionErrorMsg byte "Only 0 or 1 allowed in option specification!", 0
resultMsg byte " scores have been entered.", 0
.code
main proc
mov esi, 0
L1:
mov edx, offset optionPromptMsg
call WriteString
call ReadInt
mov ebx, 1
cmp eax, ebx
je L2
mov ebx, -1 //99% sure my main is okay
cmp eax, ebx
je L3
mov ebx, -2
mov ecx, 2
cmp ebx, eax
ja L4
cmp eax, ecx
ja L4
L2: call NextScore
jmp L5
L4: mov edx, offset optionErrorMsg
call WriteString
call Crlf
jmp L5
L5:
loop L1
L3 : call WriteScore
exit
main ENDP
WriteScore PROC USES esi //Thought was somehow make esi global?
mov eax, lengthof scores //total number of items added to array
call writeInt
mov edx, offset resultMsg
call WriteString
mov esi,0
L1:
mov eax, scores[esi *4]
call writeInt //writes the numbers in the array
inc esi
loop L1
mov eax, 5000
call Delay
ret
WriteScore ENDP
NextScore PROC USES esi
mov edx, offset scorePromptMsg
call WriteString
call ReadInt
mov ebx, 0
mov ecx, 100
cmp ebx, eax
ja L1
cmp eax,ecx
ja L1
jmp L2
L1:
mov edx, offset scoreErrorMsg
call WriteString
call Crlf
L2:
mov scores[esi*4], eax //gets the next number and puts it in the array
inc esi
ret
NextScore ENDP
当我 运行 它,并向数组添加 3 个项目时,它出于某种原因说 scores
的长度是 20,然后当它打印出数组时,数字是'甚至接近我的预期,通常为数百万或仅 0
.
非常感谢任何建议!
你有几个问题。一是您似乎不了解 procedure/function 上的 USES
指令的用途。如果您使用 USES
并列出一个寄存器,那么这将告诉汇编程序将这些寄存器的值保存在堆栈中,并在函数退出之前恢复它们。这意味着您在该函数中对该寄存器所做的任何更改都不会被调用它的函数看到。
MASM 手册是这样说的 USES:
Syntax: USES reglist
Description:
An optional keyword used with PROC. Generates code to push the
value of registers that should be preserved (and that will be
altered by your procedure) on the stack and pop them off when the
procedure returns.
The <reglist> parameter is a list of one or more registers. Separate
multiple registers with spaces.
由于您似乎希望在函数 NextScore 中对 ESI 所做的更改被调用函数看到,因此您需要删除该过程中的 USES 语句。变化:
NextScore PROC USES esi
至:
NextScore PROC
现在,当您在下一个乐谱中增加 ESI 时,函数退出时不会撤消。
另一个问题是 lengthof 伪操作码:
lengthof: Returns the number of items in array variable.
可能不太清楚,但是这个伪操作码是代码组装时数组中元素的数量。您可以这样定义分数数组:
scores DWORD MAXIMUMSCORES DUP(0)
scores 数组的长度值始终为 MAXIMUMSCORES。而不是使用 lengthof 你应该做的只是使用 ESI 寄存器。您已经使用 ESI 来记录已添加到数组中的元素数。所以这段代码:
WriteScore PROC USES esi ; Thought was somehow make esi global?
mov eax, lengthof scores ; total number of items added to array
call WriteInt
可改为:
WriteScore PROC USES esi ; Thought was somehow make esi global?
mov eax, esi ; esi = number of items added to array
call WriteInt
另一个问题是您似乎不知道 loop
指令的工作原理。从 [x86 指令集] 中,loop
指令执行:
Performs a loop operation using the ECX or CX register as a counter.
Each time the LOOP instruction is executed, the count register is
decremented, then checked for 0. If the count is 0, the loop is
terminated and program execution continues with the instruction
following the LOOP instruction. If the count is not zero, a near jump
is performed to the destination (target) operand, which is presumably
the instruction at the beginning of the loop.
在您的代码中,您从未将 ECX 设置为您希望循环的次数,因此它将使用恰好在 ECX[= 中的任何值75=]。这就是为什么你会打印出很多额外的数字。 ECX需要初始化。由于您想遍历所有输入的分数,只需将 ESI 移动到 ECX。您的 WriteScore 函数做了:
mov esi,0
L1:
mov eax, scores[esi *4]
call WriteInt ; writes the numbers in the array
inc esi
loop L1
我们可以修改为:
mov ecx,esi ; Initialize ECX loop counter to number of scores added
; to the array.
mov esi,0
L1:
mov eax, scores[esi *4]
call WriteInt ; writes the numbers in the array
inc esi
loop L1
现在我们只循环遍历用户实际输入的分数 (ESI)。
考虑到这些变化,您的程序可能看起来像这样:
INCLUDE Irvine32.inc
INCLUDELIB Irvine32.lib
INCLUDELIB user32.lib
INCLUDELIB kernel32.lib
MAXIMUMSCORES equ 20
.data
scores DWORD MAXIMUMSCORES DUP(0)
optionPromptMsg byte "Type 1 to continue or -1 to exit: ", 0
scorePromptMsg byte "Enter your numeric score (0-100): ", 0
scoreErrorMsg byte "Score out of range (0-100)!", 0
optionErrorMsg byte "Only 0 or 1 allowed in option specification!", 0
resultMsg byte " scores have been entered.", 0
.code
main proc
mov esi, 0
L1:
mov edx, offset optionPromptMsg
call WriteString
call ReadInt
mov ebx, 1
cmp eax, ebx
je L2
mov ebx, -1 ; 99% sure my main is okay
cmp eax, ebx
je L3
mov ebx, -2
mov ecx, 2
cmp ebx, eax
ja L4
cmp eax, ecx
ja L4
L2: call NextScore
jmp L5
L4: mov edx, offset optionErrorMsg
call WriteString
call Crlf
jmp L5
L5:
loop L1
L3: call WriteScore
exit
main ENDP
WriteScore PROC USES esi ; We make changes to ESI not visible to caller
; since we don't intend to change the number of scores
; with this function. Any change to ESI in this function
; will not appear to the caller of this function
mov eax, esi ; total number of items added to array in ESI
call WriteInt
mov edx, offset resultMsg
call WriteString
mov ecx,esi
mov esi,0
L1:
mov eax, scores[esi *4]
call WriteInt ; writes the numbers in the array
inc esi
loop L1
mov eax, 5000
call Delay
ret
WriteScore ENDP
NextScore PROC ; We want changes to ESI to exist after we exit this function. ESI
; will effectively act as a global register.
mov edx, offset scorePromptMsg
call WriteString
call ReadInt
mov ebx, 0
mov ecx, 100
cmp ebx, eax
ja L1
cmp eax,ecx
ja L1
jmp L2
L1:
mov edx, offset scoreErrorMsg
call WriteString
call Crlf
L2:
mov scores[esi*4], eax ; gets the next number and puts it in the array
inc esi
ret
NextScore ENDP
END
示例输出:
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 10
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 20
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 40
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 650
Score out of range (0-100)!
Type 1 to continue or -1 to exit: 99
Only 0 or 1 allowed in option specification!
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 100
Type 1 to continue or -1 to exit: -1
+5 scores have been entered.+10+20+40+650+100
我无法弄清楚如何在我的循环中进行索引。我知道 esi
用于索引,所以我正在尝试使用它...
scores DWORD MAXIMUMSCORES DUP(0)
optionPromptMsg byte "Type 1 to continue or -1 to exit: ", 0
scorePromptMsg byte "Enter your numeric score (0-100): ", 0
scoreErrorMsg byte "Score out of range (0-100)!", 0
optionErrorMsg byte "Only 0 or 1 allowed in option specification!", 0
resultMsg byte " scores have been entered.", 0
.code
main proc
mov esi, 0
L1:
mov edx, offset optionPromptMsg
call WriteString
call ReadInt
mov ebx, 1
cmp eax, ebx
je L2
mov ebx, -1 //99% sure my main is okay
cmp eax, ebx
je L3
mov ebx, -2
mov ecx, 2
cmp ebx, eax
ja L4
cmp eax, ecx
ja L4
L2: call NextScore
jmp L5
L4: mov edx, offset optionErrorMsg
call WriteString
call Crlf
jmp L5
L5:
loop L1
L3 : call WriteScore
exit
main ENDP
WriteScore PROC USES esi //Thought was somehow make esi global?
mov eax, lengthof scores //total number of items added to array
call writeInt
mov edx, offset resultMsg
call WriteString
mov esi,0
L1:
mov eax, scores[esi *4]
call writeInt //writes the numbers in the array
inc esi
loop L1
mov eax, 5000
call Delay
ret
WriteScore ENDP
NextScore PROC USES esi
mov edx, offset scorePromptMsg
call WriteString
call ReadInt
mov ebx, 0
mov ecx, 100
cmp ebx, eax
ja L1
cmp eax,ecx
ja L1
jmp L2
L1:
mov edx, offset scoreErrorMsg
call WriteString
call Crlf
L2:
mov scores[esi*4], eax //gets the next number and puts it in the array
inc esi
ret
NextScore ENDP
当我 运行 它,并向数组添加 3 个项目时,它出于某种原因说 scores
的长度是 20,然后当它打印出数组时,数字是'甚至接近我的预期,通常为数百万或仅 0
.
非常感谢任何建议!
你有几个问题。一是您似乎不了解 procedure/function 上的 USES
指令的用途。如果您使用 USES
并列出一个寄存器,那么这将告诉汇编程序将这些寄存器的值保存在堆栈中,并在函数退出之前恢复它们。这意味着您在该函数中对该寄存器所做的任何更改都不会被调用它的函数看到。
MASM 手册是这样说的 USES:
Syntax: USES reglist
Description:
An optional keyword used with PROC. Generates code to push the value of registers that should be preserved (and that will be altered by your procedure) on the stack and pop them off when the procedure returns. The <reglist> parameter is a list of one or more registers. Separate multiple registers with spaces.
由于您似乎希望在函数 NextScore 中对 ESI 所做的更改被调用函数看到,因此您需要删除该过程中的 USES 语句。变化:
NextScore PROC USES esi
至:
NextScore PROC
现在,当您在下一个乐谱中增加 ESI 时,函数退出时不会撤消。
另一个问题是 lengthof 伪操作码:
lengthof: Returns the number of items in array variable.
可能不太清楚,但是这个伪操作码是代码组装时数组中元素的数量。您可以这样定义分数数组:
scores DWORD MAXIMUMSCORES DUP(0)
scores 数组的长度值始终为 MAXIMUMSCORES。而不是使用 lengthof 你应该做的只是使用 ESI 寄存器。您已经使用 ESI 来记录已添加到数组中的元素数。所以这段代码:
WriteScore PROC USES esi ; Thought was somehow make esi global?
mov eax, lengthof scores ; total number of items added to array
call WriteInt
可改为:
WriteScore PROC USES esi ; Thought was somehow make esi global?
mov eax, esi ; esi = number of items added to array
call WriteInt
另一个问题是您似乎不知道 loop
指令的工作原理。从 [x86 指令集] 中,loop
指令执行:
Performs a loop operation using the ECX or CX register as a counter. Each time the LOOP instruction is executed, the count register is decremented, then checked for 0. If the count is 0, the loop is terminated and program execution continues with the instruction following the LOOP instruction. If the count is not zero, a near jump is performed to the destination (target) operand, which is presumably the instruction at the beginning of the loop.
在您的代码中,您从未将 ECX 设置为您希望循环的次数,因此它将使用恰好在 ECX[= 中的任何值75=]。这就是为什么你会打印出很多额外的数字。 ECX需要初始化。由于您想遍历所有输入的分数,只需将 ESI 移动到 ECX。您的 WriteScore 函数做了:
mov esi,0
L1:
mov eax, scores[esi *4]
call WriteInt ; writes the numbers in the array
inc esi
loop L1
我们可以修改为:
mov ecx,esi ; Initialize ECX loop counter to number of scores added
; to the array.
mov esi,0
L1:
mov eax, scores[esi *4]
call WriteInt ; writes the numbers in the array
inc esi
loop L1
现在我们只循环遍历用户实际输入的分数 (ESI)。
考虑到这些变化,您的程序可能看起来像这样:
INCLUDE Irvine32.inc
INCLUDELIB Irvine32.lib
INCLUDELIB user32.lib
INCLUDELIB kernel32.lib
MAXIMUMSCORES equ 20
.data
scores DWORD MAXIMUMSCORES DUP(0)
optionPromptMsg byte "Type 1 to continue or -1 to exit: ", 0
scorePromptMsg byte "Enter your numeric score (0-100): ", 0
scoreErrorMsg byte "Score out of range (0-100)!", 0
optionErrorMsg byte "Only 0 or 1 allowed in option specification!", 0
resultMsg byte " scores have been entered.", 0
.code
main proc
mov esi, 0
L1:
mov edx, offset optionPromptMsg
call WriteString
call ReadInt
mov ebx, 1
cmp eax, ebx
je L2
mov ebx, -1 ; 99% sure my main is okay
cmp eax, ebx
je L3
mov ebx, -2
mov ecx, 2
cmp ebx, eax
ja L4
cmp eax, ecx
ja L4
L2: call NextScore
jmp L5
L4: mov edx, offset optionErrorMsg
call WriteString
call Crlf
jmp L5
L5:
loop L1
L3: call WriteScore
exit
main ENDP
WriteScore PROC USES esi ; We make changes to ESI not visible to caller
; since we don't intend to change the number of scores
; with this function. Any change to ESI in this function
; will not appear to the caller of this function
mov eax, esi ; total number of items added to array in ESI
call WriteInt
mov edx, offset resultMsg
call WriteString
mov ecx,esi
mov esi,0
L1:
mov eax, scores[esi *4]
call WriteInt ; writes the numbers in the array
inc esi
loop L1
mov eax, 5000
call Delay
ret
WriteScore ENDP
NextScore PROC ; We want changes to ESI to exist after we exit this function. ESI
; will effectively act as a global register.
mov edx, offset scorePromptMsg
call WriteString
call ReadInt
mov ebx, 0
mov ecx, 100
cmp ebx, eax
ja L1
cmp eax,ecx
ja L1
jmp L2
L1:
mov edx, offset scoreErrorMsg
call WriteString
call Crlf
L2:
mov scores[esi*4], eax ; gets the next number and puts it in the array
inc esi
ret
NextScore ENDP
END
示例输出:
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 10
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 20
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 40
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 650
Score out of range (0-100)!
Type 1 to continue or -1 to exit: 99
Only 0 or 1 allowed in option specification!
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 100
Type 1 to continue or -1 to exit: -1
+5 scores have been entered.+10+20+40+650+100