windows - 汇编:如何更改此代码以请求用户输入

标签 windows visual-studio assembly x86 user-input

我最近在 Windows 10 笔记本电脑上的 Visual Studio 2017 中编写了我的汇编程序。我现在希望更改此代码,将从用户获得的值放入注册表 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();
}

我现在需要帮助来更改我的代码以允许用户输入,我有一种感觉,我可能必须执行一个系统 cll,但不确定是哪一个。这实际上是我组装的第一天,因此我们将不胜感激

最佳答案

是的,您需要使用系统调用。在 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函数非常简单。由于它不带任何参数,因此您无需担心传递任何内容。与 x86 上的所有函数一样,它在 EAX 寄存器中返回结果。

getchar 的返回值是用户输入的字符的 ASCII 代码。如果您想要一个数值,则需要从 ASCII 代码中减去 '0',利用数字 0 到 9 在 ASCII 表中是连续的这一事实。

但是,您需要将多次调用 getchar 的结果存储在某处,因为 x86 调用约定指定 EAXEDXECX 寄存器容易被函数调用破坏(覆盖)。由于 ESIEBXEDI 是调用保留的,因此我将它们用作临时寄存器。另一种选择是使用堆栈临时存储输入值。或者,优化代码以随时执行算术运算。

哦,请注意,虽然该函数的名称在 C 代码中为 getchar,但当我们从汇编中调用它时,它的名称为 _getchar。那是因为微软的编译器prepends an underscore to exported symbol names .

专家程序员会向此代码添加一些条件测试来检查错误。回想一下,失败时 getchar 返回 EOF (-1)。您可能还想处理用户按下 Enter 键而不输入数字的情况。您可以使用相当于 while 循环 (cmp eax, -1 + je) 来继续旋转,直到 getchar code> 返回一个您认为在范围内的值(例如,从 '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 option 编译它。 ,然后查看编译器生成的程序集列表。

关于windows - 汇编:如何更改此代码以请求用户输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54657639/

相关文章:

C 递归搜索文件夹及其子文件夹中的文件

python - 在 Apache 上部署 Django 时出错

c# - Visual Studio 2008/2010 错误/问题列表

visual-studio - 在 Web 安装项目期间/之后修改 Web.config

assembly - "GCC -S"的汇编输出: why does .全局定位在.data之前?

c++ - 指向动态分配数组的静态指针

c++ - 如何从 Windows MFC 客户端使用 SSL?

c# - VS2010 中没有智能感知

windows - Tasm 对名称较长的文件给出错误

linux - 洞察调试器断点不起作用