组装:嵌套循环问题

时间:2018-11-24 04:05:38

标签: assembly x86 masm irvine32

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

1 个答案:

答案 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位,在这种情况下,使用字符时就足够了。