Сборка: проблемы с индексацией
У меня проблемы с выяснением, как сделать индексацию в моих циклах. я знаю esi
используется для индексации, поэтому я пытаюсь использовать это...
scores DWORD MAXIMUMSCORES DUP(0)
optionPromptMsg byte "Type 1 to continue or -1 to exit: ", 0
scorePromptMsg byte "Enter your numeric score (0-100): ", 0
scoreErrorMsg byte "Score out of range (0-100)!", 0
optionErrorMsg byte "Only 0 or 1 allowed in option specification!", 0
resultMsg byte " scores have been entered.", 0
.code
main proc
mov esi, 0
L1:
mov edx, offset optionPromptMsg
call WriteString
call ReadInt
mov ebx, 1
cmp eax, ebx
je L2
mov ebx, -1 //99% sure my main is okay
cmp eax, ebx
je L3
mov ebx, -2
mov ecx, 2
cmp ebx, eax
ja L4
cmp eax, ecx
ja L4
L2: call NextScore
jmp L5
L4: mov edx, offset optionErrorMsg
call WriteString
call Crlf
jmp L5
L5:
loop L1
L3 : call WriteScore
exit
main ENDP
WriteScore PROC USES esi //Thought was somehow make esi global?
mov eax, lengthof scores //total number of items added to array
call writeInt
mov edx, offset resultMsg
call WriteString
mov esi,0
L1:
mov eax, scores[esi *4]
call writeInt //writes the numbers in the array
inc esi
loop L1
mov eax, 5000
call Delay
ret
WriteScore ENDP
NextScore PROC USES esi
mov edx, offset scorePromptMsg
call WriteString
call ReadInt
mov ebx, 0
mov ecx, 100
cmp ebx, eax
ja L1
cmp eax,ecx
ja L1
jmp L2
L1:
mov edx, offset scoreErrorMsg
call WriteString
call Crlf
L2:
mov scores[esi*4], eax //gets the next number and puts it in the array
inc esi
ret
NextScore ENDP
Когда я запускаю его и добавляю 3 элемента в массив, он по какой-то причине говорит о длине scores
равно 20, а затем, когда он распечатывает массив, числа даже не близки к тому, что я ожидаю, как правило, в миллионах или просто 0
,
Любые предложения очень ценятся!
1 ответ
У вас есть пара вопросов. Во-первых, вы, кажется, не понимаете, что USES
Директива о процедуре / функции предназначена для. Если вы используете USES
и перечислить регистр (ы), который говорит ассемблеру сохранить значение этих регистров в стеке и восстановить их непосредственно перед выходом из функции. Это означает, что любые изменения, внесенные вами в этот регистр в этой функции, не будут видны функцией, вызвавшей ее.
В руководстве MASM говорится об ИСПОЛЬЗОВАНИИ:
Синтаксис: использует регистр
Описание:
An optional keyword used with PROC. Generates code to push the value of registers that should be preserved (and that will be altered by your procedure) on the stack and pop them off when the procedure returns. The <reglist> parameter is a list of one or more registers. Separate multiple registers with spaces.
Поскольку вы, кажется, хотите, чтобы вызывающая функция видела изменения в ESI, сделанные в функции NextScore, вы захотите удалить оператор USES из этой процедуры. Изменить:
NextScore PROC USES esi
чтобы:
NextScore PROC
Теперь, когда вы увеличиваете ESI в следующем счете, оно не будет отменено при выходе из функции.
Другая проблема заключается в том, что длина псевдо-кода операции:
lengthof: возвращает количество элементов в переменной массива.
Это может быть не ясно, но этот псевдо-код операции - это число элементов в массиве, когда код был собран. Вы определяете массив баллов следующим образом:
scores DWORD MAXIMUMSCORES DUP(0)
Массив показателей всегда будет иметь значение длины MAXIMUMSCORES. Вместо того, чтобы использовать lengthof, вы должны просто использовать регистр ESI. Вы уже используете ESI для хранения количества элементов, добавленных в массив. Итак, этот код:
WriteScore PROC USES esi ; Thought was somehow make esi global?
mov eax, lengthof scores ; total number of items added to array
call WriteInt
Может быть изменено на:
WriteScore PROC USES esi ; Thought was somehow make esi global?
mov eax, esi ; esi = number of items added to array
call WriteInt
Другая проблема заключается в том, что вы не знаете, как loop
инструкция работает. Из [x86 Инструкции] loop
инструкция делает:
Выполняет операцию цикла, используя регистр ECX или CX в качестве счетчика. Каждый раз, когда выполняется инструкция LOOP, регистр счетчика уменьшается, а затем проверяется на 0. Если счетчик равен 0, цикл завершается, и выполнение программы продолжается с инструкцией, следующей за инструкцией LOOP. Если счетчик не равен нулю, выполняется близкий переход к операнду назначения (цели), который, вероятно, является инструкцией в начале цикла.
В вашем коде вы никогда не устанавливаете ECX на количество циклов, которое хотите зациклить, поэтому он будет использовать любое значение, которое будет в ECX. Вот почему у вас распечатано много дополнительных номеров. ECX должен быть инициализирован. Поскольку вы хотите просмотреть все введенные результаты, просто переместите ESI в ECX. Ваша функция WriteScore сделала:
mov esi,0
L1:
mov eax, scores[esi *4]
call WriteInt ; writes the numbers in the array
inc esi
loop L1
Мы можем изменить это так:
mov ecx,esi ; Initialize ECX loop counter to number of scores added
; to the array.
mov esi,0
L1:
mov eax, scores[esi *4]
call WriteInt ; writes the numbers in the array
inc esi
loop L1
Теперь мы просто перебираем количество баллов (ESI), которое фактически ввел пользователь.
С учетом этих изменений ваша программа может выглядеть примерно так:
INCLUDE Irvine32.inc
INCLUDELIB Irvine32.lib
INCLUDELIB user32.lib
INCLUDELIB kernel32.lib
MAXIMUMSCORES equ 20
.data
scores DWORD MAXIMUMSCORES DUP(0)
optionPromptMsg byte "Type 1 to continue or -1 to exit: ", 0
scorePromptMsg byte "Enter your numeric score (0-100): ", 0
scoreErrorMsg byte "Score out of range (0-100)!", 0
optionErrorMsg byte "Only 0 or 1 allowed in option specification!", 0
resultMsg byte " scores have been entered.", 0
.code
main proc
mov esi, 0
L1:
mov edx, offset optionPromptMsg
call WriteString
call ReadInt
mov ebx, 1
cmp eax, ebx
je L2
mov ebx, -1 ; 99% sure my main is okay
cmp eax, ebx
je L3
mov ebx, -2
mov ecx, 2
cmp ebx, eax
ja L4
cmp eax, ecx
ja L4
L2: call NextScore
jmp L5
L4: mov edx, offset optionErrorMsg
call WriteString
call Crlf
jmp L5
L5:
loop L1
L3: call WriteScore
exit
main ENDP
WriteScore PROC USES esi ; We make changes to ESI not visible to caller
; since we don't intend to change the number of scores
; with this function. Any change to ESI in this function
; will not appear to the caller of this function
mov eax, esi ; total number of items added to array in ESI
call WriteInt
mov edx, offset resultMsg
call WriteString
mov ecx,esi
mov esi,0
L1:
mov eax, scores[esi *4]
call WriteInt ; writes the numbers in the array
inc esi
loop L1
mov eax, 5000
call Delay
ret
WriteScore ENDP
NextScore PROC ; We want changes to ESI to exist after we exit this function. ESI
; will effectively act as a global register.
mov edx, offset scorePromptMsg
call WriteString
call ReadInt
mov ebx, 0
mov ecx, 100
cmp ebx, eax
ja L1
cmp eax,ecx
ja L1
jmp L2
L1:
mov edx, offset scoreErrorMsg
call WriteString
call Crlf
L2:
mov scores[esi*4], eax ; gets the next number and puts it in the array
inc esi
ret
NextScore ENDP
END
Пример вывода этого:
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 10
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 20
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 40
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 650
Score out of range (0-100)!
Type 1 to continue or -1 to exit: 99
Only 0 or 1 allowed in option specification!
Type 1 to continue or -1 to exit: 1
Enter your numeric score (0-100): 100
Type 1 to continue or -1 to exit: -1
+5 scores have been entered.+10+20+40+650+100