Сборка: Как изменить этот код, чтобы запросить ввод пользователя - PullRequest
0 голосов
/ 12 февраля 2019

Я недавно написал свою программу сборки в visual studio 2017 на ноутбуке с windows 10.Теперь я хочу изменить этот код, чтобы поместить значения, полученные от пользователя, в реестры eax, ebx, ecx и edx

\. Я получил программу для работы с деформированными жестко заданными значениями, но изо всех сил пытаюсь найти что-нибудь наИнтернет, чтобы помочь мне получить пользовательский ввод.Задача указывает, что я должен использовать ассемблер, чтобы спросить пользователя

.586                            ;Enables assembly on non Priiliged intructions for the prntium processor
.model flat ,c                  ;model=Initialises the program memory mode, flat=Identifies the size of code and data pointers and 
                            ;c=  identifies the naming and calling coventions
.stack 100h
.data                           ; This section will contain all of the static variables for our program
foo dd 0                    ;Variable to be used to store into meory   
.code                           ; Assembly code will be placed here

multi proc                      ; Start of the doit process. Like a method in C#. Method is called 
                            ;in the visual studio form Source

mov eax, 8                  ; Moves the value 8 into the eax Registry
mov ebx, 4                  ; Moves the value 4 into the ebx Registry
mov ecx, 6                  ; Moves the value 6 into the ecx Registry
mov edx, 12                 ; Moves the value 12 into the edx Registry

add eax, ebx                ; Adds the value stored in registry ebx to the vale in eax and stores the answer in eax
add eax, edx                ; Adds the value stored in registry edx to the vale in eax and stores the answer in eax
sub eax, ecx                ; subtracts the value stored in registry ecx from the vale in eax and stores the answer in eax
mul ebx                     ; Multiply the value in registry eax with the value in eax and stores the answer in eax
mov [foo], eax              ; stores the value in registry in eax into the computer memory


ret                         ; returns the valie of the accumulator
multi endp                      ; End of the doit method

end     

, и это код, который я использую, чтобы вызвать его из visual studio

#include <iostream>

extern "C" int multi();

void main()
{
printf("%d%",multi());
    std:getchar();
}

Мне просто сейчас нужна помощь дляизменив свой код, чтобы разрешить ввод от пользователя, у меня есть чувство, что мне, возможно, придется выполнить системный вызов, но я не уверен, какой именно.Это первый день, когда я занимаюсь сборкой, поэтому любая помощь будет признательна

1 Ответ

0 голосов
/ 13 февраля 2019

Да, вам нужно будет использовать системный вызов.В C ++ вы бы вызывали std::getchar(), чтобы прочитать символ из стандартного ввода.Если вам разрешено использовать стандартную библиотеку C ++, если вы вызываете ее из сборки, тогда код будет выглядеть примерно так:

multi proc
    push   esi                   ; \ preserve
    push   ebx                   ; |  callee-preserve
    push   edi                   ; / registers

    call   _getchar              ; read input; return result in EAX
    mov    esi, eax              ; ESI = EAX
    sub    esi, 48               ; ESI -= '0'

    call   _getchar              ; read input; return result in EAX
    mov    ebx, eax              ; EBX = EAX
    sub    ebx, 48               ; EBX -= '0'

    call   _getchar              ; read input; return result in EAX
    mov    edi, eax              ; EDI = EAX
    sub    edi, 48               ; EDI -= '0'

    call   _getchar              ; read input; return result in EAX
    mov    edx, eax              ; EDX = EAX
    sub    edx, 48               ; EDX -= '0'

    mov    ecx, edi              ; ECX = EDI
    mov    eax, esi              ; EAX = ESI

    add    eax, ebx              ; EAX += EBX
    add    eax, edx              ; EAX += EDX
    sub    eax, ecx              ; EAX -= ECX
    mul    ebx                   ; EDX:EAX = EAX * EBX
    mov    [foo], eax            ; *foo = EAX

    pop    edi                   ; \ restore
    pop    ebx                   ; |  callee-preserve
    pop    esi                   ; /  registers

    ret
multi endp

Вызов функции getchar очень прост.Поскольку он не требует параметров, вам не нужно беспокоиться о передаче чего-либо.Он возвращает свой результат в регистр EAX, как и все функции в x86.

Возвращаемое значение getchar - это код ASCII для введенного пользователем символа.Если вам нужно числовое значение, вам нужно вычесть '0' из кода ASCII, используя тот факт, что числа от 0 до 9 являются последовательными в таблице ASCII.

Однако вам нужно сохранить результатгде-то в нескольких вызовах getchar, так как соглашение о вызовах x86 указывает, что регистры EAX, EDX и ECX могут быть перекрыты (перезаписаны) вызовом функции.Поскольку ESI, EBX и EDI сохраняются при вызове, я использовал их в качестве временных регистров.Другой альтернативой будет использование стека для временного хранения входных значений.Или, оптимизируя код для выполнения арифметических операций по ходу дела.

О, и обратите внимание, что хотя имя функции в коде C и равно getchar, когда мы вызываем ее из сборки, это _getchar.Это связано с тем, что компилятор Microsoft добавляет подчеркивание к экспортированным именам символов .

Опытный программист добавил бы в этот код некоторые условные тесты, которые проверяют наличие ошибок.Напомним, что getchar возвращает EOF (-1) при ошибке.Возможно, вы также захотите обработать случай, когда пользователь нажимает клавишу Enter без ввода номера.Вы можете использовать эквивалент цикла while (cmp eax, -1 + je), чтобы вращаться до тех пор, пока getchar не вернет значение, которое, по вашему мнению, находится в пределах диапазона (от '0' до '9', скажем,).

Обратите внимание (предупреждение: полностью не проверено!):

ReadInteger proc
TryAgain:
    call    _getchar          ; read input from stdin; return result in EAX
    cmp     eax, 48           ; \ if (input < '0')
    jl      TryAgain          ; /  jump to TryAgain
    cmp     eax, 57           ; \ if (input > '9')
    jg      TryAgain          ; /  jump to TryAgain
    sub     eax, 48           ; input -= '0'
    ret
ReadInteger endp

multi proc
    push   esi
    push   ebx
    push   edi

    call   ReadInteger
    mov    esi, eax

    call   ReadInteger
    mov    ebx, eax

    call   ReadInteger
    mov    edi, eax

    call   ReadInteger
    add    eax, esi
    add    eax, ebx
    sub    eax, edi
    mul    ebx
    mov    [foo], eax

    pop    edi
    pop    ebx
    pop    esi

    ret
multi endp

Если вы не можете использовать стандартную библиотеку C ++ и вынуждены использовать вызовы операционной системы, тогда это становится намного болеесложно.Я подозреваю, что это гораздо сложнее, чем твой инструктор мог бы ожидать от тебя на этом этапе.Вам нужно вызвать функцию Win32, например ReadConsoleInput.Здесь есть хитрость: напишите функцию C (или C ++), скомпилируйте ее с опцией /Fa и посмотрите список сборок, созданный компилятором.

...