СБОРКА: проблема с вложенным циклом - PullRequest
0 голосов
/ 24 ноября 2018

Я работаю с вложенными циклами в сборке.Желаемый вывод должен быть "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 голосов
/ 24 ноября 2018

Ваш код ничего не делает с тем, что вы описываете ... позвольте мне перешагнуть через одну инструкцию с вами, как происходит выполнение (это не исходный код, а последовательная запись инструкций, поскольку они будут выполняться ЦП, с некоторыми минимальнымикомментарии важных частей):

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);, который естественным образом соответствует ассемблерному способу кодирования (но это не так).t проверять достоверность счетчика на первой итерации, так что это хороший стиль только для случая, когда счетчик всегда является допустимым значением).

Как, например:

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 битов, чего достаточно при работе с символами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...