尝试将ecx寄存器保存在堆栈上,然后将ecx寄存器用于过程调用内的循环时遇到一些麻烦。我从数字中获得的输出受主要而不是过程中的ecx约束。问题的本质是在Masm中使用字符串,然后使用ascii图表表将其更改为数字,然后将这些新数字放入数组中。但是,当我从用户输入数字时,它受主循环的限制,例如,如果我的ecx为3,则它将只输入我输入的前三个数字。首先是代码,然后是程序,然后是两个宏。任何帮助将不胜感激。
我尝试将ecx寄存器推入过程内部,然后在过程结束后将其弹出,但这只会弄乱我的主循环。我还尝试过使用pushad在过程调用开始时保存所有寄存器,然后使用popad在代码末尾将它们全部弹出。那也没有用。
.data
prompt1 byte "Welcome to Low level I/O programming , Assignment6.asm, I am your Programmer Jackson Miller :)",0
prompt2 byte "Ths will prompt you for 10 unsigned integears, make sure they can fit into a 32 bit register. After you enter 10 raw ints, I will display the list, sum, and average value",0
prompt3 byte " Please enter a unsigned integear: ",0
prompt4 byte " Invalid Entry",0
input byte 200 dup(0)
list dword 20 dup(0)
num dword ?
temp dword ?
test1 byte "How many times it get here",0
main PROC
push offset prompt1
push offset prompt2
call introduction
mov ecx,10
mov edi, offset list
mov ebx,0
mov edx,0
fillnumbers:
push ecx
push edx
displaystring prompt3
push offset input
call readval
pop edx
mov [edi+edx],eax
add edx,4
pop ecx
loop fillnumbers
mov esi, offset list
mov ecx,10
mov ebx,0
displayints:
mov eax, [esi+ebx]
call writedec
add ebx,4
loop displayints
exit ; exit to operating system
main ENDP
readval PROC
push ebp
mov ebp,esp
retry:
mov edx, [ebp+8]
getstring edx
mov esi,edx
mov ecx,0
check:
lodsb
cmp ax,0
je done
cmp ax,57
jle good
jmp notgood
good:
cmp ax,48
jge doublegood
jmp notgood
doublegood:
sub ax,48
mov ebx,10
xchg eax,ecx
mul ebx
add ecx,eax
mov eax,0
jmp check
notgood:
mov edx,offset prompt4
call writestring
call crlf
mov edx, offset prompt3
call writestring
jmp retry
done:
mov eax,ecx
call writedec
pop ebp
ret 4
readval ENDP
displaystring MACRO input
push edx
mov edx, offset input
call writestring
pop edx
ENDM
getstring MACRO buffer
push edx
mov edx,buffer
call readstring
pop edx
ENDM
答案 0 :(得分:1)
Irvine32 ReadString
根据the documentation具有 2 个参数:
在使用getstring
宏进行调用时,ECX拥有main
的循环计数器,因此最大长度字符限制随每次外循环迭代而减小。
为循环计数器选择其他寄存器,例如EDI或EBX,因此您可以将ECX设置为缓冲区长度,也可以让readval
销毁ECX。
loop
指令在除AMD Bulldozer / Ryzen之外的所有现代CPU上运行缓慢,因此,除非您正在优化代码大小,否则您不应该一开始就使用它。但是,如果您是和,那么在ECX中使用倒数计数器实际上很方便,那么可以肯定。否则以其他方式循环,例如
dec edi
/ jnz top_of_loop
。
其他错误:
lodsb
/ cmp ax,0
:您没有将EAX设为零,并且lodsb
有点像mov al, [esi]
/ inc esi
。因此,AX的高字节在这里可能不为零。如果您正在寻找零终止符,则没有必要进行检查。
ReadString返回EAX
=输入字符串的大小,因此在实践中(非常长的输入除外),只有EAX的低字节为非零,而lodsb
则将其替换。因此,您的代码恰好适用于普通输入。
不过,通过检查第一个非数字来停下来要容易得多,而不是分别检查0和非数字。您可以将该ReadString返回值用作递减计数器,但是如果要检查其他非数字输入以结束循环,则
... get string input
xor eax, eax
jmp first_iteration_starts_here
top_of_loop:
imul eax, 10
add eax, edx
first_iteration_starts_here:
movzx edx, [esi]
inc esi
sub edx, '0'
;; EDX = an integer from 0 .. 9 else out of bounds
cmp edx, 9
jbe top_of_loop ; *unsigned* compare catches low characters that wrapped, too
; EDX = some non-digit character minus '0'
; total in EAX.
ret
您正在编写32位代码,因此应该使用2 or 3-operand imul
for integer multiply,除非您实际上想要上半部结果。使用不必要的,效率低下的1-operand mul
不必痛苦。