我最近在visual studio 2017中用windows 10笔记本电脑编写了我的汇编程序。我现在希望修改此代码,将从用户获得的值放入注册表eax、ebx、ecx和edx-
\我已经让这个程序处理了defalt硬编码的值,但我很难在网上找到任何东西来帮助我获得用户输入。任务指定我必须使用汇编来询问用户
.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
这是我用来从visualstudio调用它的代码
#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
函数非常简单。由于它不需要参数,所以您不需要担心传递任何东西。它在EAX
寄存器中返回结果,就像x86上的所有函数一样。
getchar
的返回值是用户输入的字符的ASCII代码。如果您想要一个数值,那么您需要从ASCII代码中减去'0'
,利用数字0到9在ASCII表中是连续的这一事实。
但是,您需要将结果存储在多次调用getchar
的某个位置,因为x86调用约定指定EAX
、EDX
和ECX
寄存器会被函数调用破坏(覆盖)。由于ESI
、EBX
和EDI
是保留调用的,所以我将它们用作临时寄存器。另一种选择是使用堆栈来临时存储输入值。或者,优化代码,以便在进行算术运算时进行运算。
哦,请注意,虽然函数的名称在C代码中是getchar
,但当我们从汇编中调用它时,它是_getchar
。这是因为微软的编译器在导出的符号名前面加了一个下划线。
专家程序员会在代码中添加一些条件测试来检查错误。回想一下,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++标准库,并且被迫使用操作系统调用,那么这将变得更加困难。我怀疑,这比你的教练在这个阶段所期望的要困难得多。您需要调用像ReadConsoleInput
这样的Win32函数。不过,这里有一个技巧:编写函数C(或C++),使用/Fa
选项进行编译,然后查看编译器生成的程序集列表。