2015-11-11 2 views
0

У меня возникли проблемы с выяснением того, как сделать индексацию в моих циклах. Я знаю, что 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 элементов в массиве, это по какой-либо причине говорит lengthof scores 20, а затем, когда он печатает массив, цифры даже не приближаются к ожидаемому, обычно в миллионах или просто 0.

Любые предложения очень ценятся!

+0

Добавить оставшуюся часть источника. При минимальном значении _, код должен включать ваши функции 'ReadInt' и' WriteString'. Кроме того, вы должны запускать это в отладчике. Если это dos-based, используйте Turbo Debugger. Вы сразу увидите свою ошибку, если будете отлаживать код. ;) – enhzflep

+0

@enhnzflep Я использую визуальную студию, чтобы написать ее, и отладчик для нее хорошо .. собака sh * t, на мой взгляд. О чем этот турбо-отладчик вы говорите? И что вы подразумеваете, добавив оставшуюся часть источника? – Bob

+0

@enhzflep: Он использует библиотеку Irvine32. Некоторая полезная информация об этом есть [здесь] (http://math.uaa.alaska.edu/~afkjm/cs221/handouts/procedures.pdf) –

ответ

1

У вас есть пара вопросов. Во-первых, вы, похоже, не понимаете, что такое директива USES для процедуры/функции. Если вы используете USES и перечислите регистр (регистры), который сообщает ассемблеру сохранить значение этих регистров в стеке и восстановить их перед тем, как функция завершит работу. Это означает, что любое изменение, которое вы делаете в этом регистре в этой функции, не будет видно функции, которая его вызвала.

Руководство MASM говорит это о ИСПОЛЬЗУЕТ:

Синтаксис: ИСПОЛЬЗУЕТ reglist

Описание:

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 псевдо-опкод делает:

lengthof: Возвращает количество элементов в переменной массива.

Это может быть неясно, но этот псевдоокодирование - это количество элементов в массиве при сборке кода. Вы определяете массив оценок, как это:

scores DWORD MAXIMUMSCORES DUP(0) 

В оценки массив всегда будет иметь значение lengthof из 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 
+0

OHHH в порядке! Не уверен, почему, но я был под впечатлением, что esi был счетчиком для цикла! Не забывайте, что это 'ecx'. Блестящее объяснение @Michael_Petch действительно показало, почему и как все работает. – Bob

+0

@ user38254 Возможно, вы думали об инструкциях типа [movsb, movsw, movsl] (https://courses.engr.illinois.edu/ece390/archive/spr2002/books/labmanual/inst-ref-movsb.html) , –

Смежные вопросы