我正在汇编中使用嵌套循环。所需的输出应该是“ ABCD”(新行)“ EFGH”(新行)“ HIJK”(新行)“ LMNO”,但是目前我没有任何输出。整个循环将执行,但控制台中将不显示任何内容。
INCLUDE Irvine32.inc
.data
ALPHA byte "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"
count byte 4 ; inner loop counter
.code
main proc
mov esi, OFFSET ALPHA
mov ecx, 4 ;outer loop counter
mov ebx, 0 ; inner counter
call part1
main endp
;-----------------------------------------------------------------------------
;part1 proc
;print 4x4 letter matric
;Receives EBX: arr address ECX: outer loop counter
;Returns EAX: full array
;-----------------------------------------------------------------------------
part1 PROC USES ebx ecx edx esi
L1:
cmp ecx, 4 ; test outer loop count
je next ; yes?
call Crlf ; print new line
inc ecx
L2: ;inner loop
cmp ebx, ecx ;
mov eax, [esi] ; mov next letter
call WriteChar ; write it
inc esi ; point to the next element
inc ebx
loop L2 ; loop
next:
call Crlf
ret
part1 ENDP
end main
答案 0 :(得分:1)
您的代码没有执行您所描述的任何操作。.让我与您一起逐步执行一条指令,它是如何执行的(这不是源代码,而是按顺序记录下来的指令,因为这些指令将由CPU执行,并且最少重要部分的评论):
mov esi, OFFSET ALPHA
mov ecx, 4
mov ebx, 0
call part1
cmp ecx, 4
je next ; jump is taken, because ecx == 4
call Crlf
... internal implementation of Crlf by Irvine32 ending with RET
ret ; part1 "ret" returning into main
; there is no more code in main, so the CPU continues
; with next memory interpreting it as machine code
; with a bit of luck (no padding between ENDP/PROC, or NOPs)
; the "part1" code follows after main, so it will get executed
cmp ecx, 4
je next ; jump is taken, because ecx == 4
call Crlf
... internal implementation of Crlf by Irvine32 ending with RET
ret ; part1 "ret" returning out of your code completely
; in some environments that may work as clean exit from app
; in others that ret will go to whatever address is at stack and crash
您应该能够在调试器中进行验证。我想知道是什么让您认为“整个循环将执行” 和“什么都不会出现在控制台中” ,因为显然只执行了很小一部分循环,并且控制台中应该出现两行。
如何修复代码...首先在主体的末尾添加某种退出,如果要构建Win32可执行文件,那么我认为退出Irvin32程序的标准方法是使用ExitProcess
(查看Irvine32软件包的工作示例)。我认为类似invoke ExitProcess, 0
的方法可能会起作用,invoke
是某种预定义的宏,它将扩展为mov + call
指令,但是我没有Windows和/或Irvine32来检查自己。 / p>
然后确定您要如何实际跟踪循环。例如,将外部计数器放入ecx
中,将内部计数器放入ebx
中,由于您知道大小是否固定为4x4,因此请以do { ..; --counter; } while (counter);
样式进行递减计数,这符合汇编的编码方式自然(但它不会在第一次迭代时检查计数器的有效性,因此仅在计数器始终为有效值的情况下,这才是好样式)。
例如:
part1 PROC USES eax ebx ecx esi
mov ecx, 4
outerLoop:
mov ebx, 4 ; reset inner counter (for every outer loop)
innerLoop:
mov al, [esi] ; load next letter
call WriteChar
inc esi ; point to next element
dec ebx ; --innerCounter
jnz innerLoop
call Crlf ; print new line after 4 chars
dec ecx ; --outerCounter
jnz outerLoop
ret
part1 ENDP
现在,这应该在控制台中产生如下内容:
A,B,
C,D,
E,F,
G,H,
那是因为您确实将ALPHA
定义为一个长字符串,包括逗号等。您可能确实想要类似
ALPHA byte 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P'
或等效的
ALPHA byte "ABCDEFGHIJKLMNOP"
它们都产生16个字节,其值分别为65、66、67,...('A' == 65
)。
还在您的原始代码中:
mov eax, [esi] ; mov next letter
将加载四个字节。 WriteChar
确实忽略了eax
的高24位,并且仅使用低8位(“ al
”),并且您仅将esi
加1,因此最终,这是无害的错误,但是您应该了解它的工作方式。 mov al,[esi]
仅从内存中提取8位,在这种情况下,使用字符时就足够了。