2

I have recently written my assembly program in visual studio 2017 on a windows 10 laptop. I now wish to alter this code to place values obtained from the user into the registries eax, ebx, ecx and edx

\I have gotten the program to work with defualt hardcorded values but am struggling to find anything on the web to help me get user input. The task specifies that i must use assembly to ask the user

.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 

and this is the code i use to call it from visual studio

#include <iostream> extern "C" int multi(); void main() { printf("%d%",multi()); std:getchar(); } 

I just now please need assistance to alter my code to allow input from the user, I have a feeling to i may have to do a system cll but am not sure which one. This is litterally my first day doing assembly so any help would be appreciated

1
  • Is .stack 100h the size of the stack? That's pretty small if you're going to call library functions. You should be able to leave it at the default. Commented Feb 13, 2019 at 4:40

1 Answer 1

2

Yes, you will need to use a system call. In C++, you'd call std::getchar() to read a character from the standard input. If you're allowed to use the C++ standard library as long as you call it from assembly, then the code would look something like this:

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 

Calling the getchar function is very straightforward. Since it takes no parameters, you don't need to worry about passing anything. It returns its result in the EAX register, like all functions on x86.

The return value of getchar is an ASCII code for the character that the user entered. If you want a numeric value, then you need to subtract '0' from the ASCII code, exploiting the fact that the numbers 0 through 9 are sequential in the ASCII table.

However, you need to store the result somewhere across multiple calls to getchar, since the x86 calling convention specifies that the EAX, EDX, and ECX registers are subject to being clobbered (overwritten) by the function call. Since ESI, EBX, and EDI are call-preserved, I've used those as temporary registers. Another alternative would be to use the stack to temporarily store the input values. Or, optimizing the code to do the arithmetic operations as you go.

Oh, and notice that while the function's name is getchar in the C code, it's _getchar when we call it from assembly. That's because Microsoft's compiler prepends an underscore to exported symbol names.

The expert programmer would add some conditional tests to this code that check for errors. Recall that getchar returns EOF (-1) on failure. You might also want to handle the case when the user presses the Enter key without entering a number. You could use the equivalent of a while loop (cmp eax, -1 + je) to keep spinning until the getchar returns a value that you consider to be within range (from '0' to '9', say).

Consider (warning: completely untested!):

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 

If you can't use the C++ standard library and are forced to use operating system calls, then this becomes much more difficult. Far more difficult, I suspect, than your instructor would ever expect you to be able to do at this stage. You need to call a Win32 function like ReadConsoleInput. There is a trick here, though: write the function C (or C++), compile it with the /Fa option, and look at the assembly listing that the compiler generated.

Sign up to request clarification or add additional context in comments.

1 Comment

There's usually no reason for beginners to use mul unless they need 8086-compatible 16-bit code. x86's "normal" / efficient / simple multiply instruction is two-operand imul r32, r/m32, just like add and sub, so imul esi, ebx is what I would have suggested. Only use widening multiply if you need the high-half result, or if you're code-golfing and want to save a byte of code size. Instructions that have existed since 8086 aren't necessarily simpler.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.