СБОРКА: проблема с вложенным циклом
Я работаю с вложенными циклами в сборке. Желаемый вывод должен быть "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 ответ
Ваш код ничего не делает с тем, что вы описываете... позвольте мне перешагнуть через одну инструкцию с вами, как происходит выполнение (это не исходный код, а последовательная запись инструкций, поскольку они будут выполняться ЦП, с некоторыми минимальными комментариями важных части):
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
инструкции, но у меня нет окон и / или 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
"), и вы увеличиваете esi
только один, так что, в конце концов, это безобидная ошибка, но вы должны понимать, как она работает. mov al,[esi]
будет извлекать только 8 бит из памяти, что достаточно в этом случае при работе с символами.