ASSEMBLY:嵌套循环问题

ASSEMBLY: issue with nested loop

我在汇编中使用嵌套循环。所需的输出应该是 "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

你的代码没有做你描述的任何事情..让我和你一起跨过单条指令,执行是如何发生的(这不是源代码,而是指令的顺序写下,因为它们将由 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

您应该能够在调试器中验证这一点。我想知道是什么让您认为 "The whole loop will execute""nothing will appear in the console",显然只有循环的最小部分正在执行,控制台中应该出现两条新行。

如何修复您的代码...首先在 main 的末尾添加某种出口,如果您正在构建 win32 可执行文件,那么我认为退出 Irvin32 程序的标准方法是使用 ExitProcess(检查 Irvine32 包的工作示例)。我认为 invoke ExitProcess, 0 之类的东西可能会起作用,invoke 是某种预定义的宏,它将扩展为 mov + call 指令,但我没有 windows and/or Irvine32 来检查一下自己。

然后考虑一下您实际想要如何跟踪循环。例如将外部计数器放入 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 位,这在这种情况下就足够了,当处理字符时。