首页 > 解决方案 > 组装:嵌套循环的问题

问题描述

我正在使用程序集中的嵌套循环。所需的输出应该是“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

标签: assemblyx86masmirvine32

解决方案


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

您应该能够在调试器中验证这一点。我想知道是什么让您认为“整个循环将执行”“控制台中不会出现任何内容”,因为显然只有一小部分循环正在执行,并且控制台中应该出现两条新行。

如何修复您的代码...首先在 main 的末尾添加某种退出,如果您正在构建 win32 可执行文件,那么我认为退出 Irvin32 程序的标准方法是使用ExitProcess(检查 Irvine32 包的工作示例)。我认为类似的东西invoke ExitProcess, 0可能会起作用,invoke是某种预定义的宏,它将扩展为mov + call指令,但我没有 windows 和/或 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确实忽略了高 24 位并且将eax仅使用低 8 位(“ al”),并且您仅递增esi1,因此最终这是无害的错误,但您应该了解它是如何工作的。mov al,[esi]在处理字符时,只会从内存中获取 8 位,在这种情况下就足够了。


推荐阅读