tags:

views:

89

answers:

1

I need to call PrintResult from my assembly to display the result. I know I have to use extrn _PrintResult somewhere, and I should call the function using call _PrintResult but I'm not sure quite sure how to use it. any suggestions

public _Square

.386

.model flat

.code

_Square proc

mov eax, [esp+4]

imul eax

ret

_Square endp

.............Here is my C++ code.........

#include <iostream>

using namespace std;

enum ResultCode {ShowSquare};
enum SuccessCode {Failure, Success};

extern "C" long Square (long);

void main ()
 {
 long Num1; 
         long Num2;

 do
  {
  cout << "Enter Number to Square" << endl;
  cin >> Num1;
  Result = Square (Num1);
  cout << "Square is: " << Result << endl;
  } while (Result > 0);
 }

void PrintResult (ResultCode PrintCode, long Value) //PrintCode, long Value)
 {
 switch (PrintCode)
  {
  case ShowSquare:
    cout << "Display of square is: " << Value << endl;
    break;

  default:
    cout << "Error in assembly routines" << endl;
  }
}
+3  A: 

I usually don't like to post full code for things, but give this a try:

32-bit Assembly

.386
.model flat
.code

_Square proc
mov eax, [esp+4]
imul eax

push eax ; Save the calculated result

; Call PrintResult here
push eax ; value
push 0 ; ShowSquare
call _PrintResult
add esp, 8 ; Clear the stack

pop eax ; Return the calculated result

ret
_Square endp

C++

#include <iostream>

using namespace std;

enum ResultCode {ShowSquare};
enum SuccessCode {Failure, Success};

extern "C" long Square(long);

int main(int argc, char* argv[])
{
    long Num1, Num2;

    do
    {
        cout << "Enter number to square" << endl;
        cin >> Num1;
        Num2 = Square(Num1);
        cout << "Square returned: " << Num2 << endl;
    }
    while (Num2);

    return 0; 
}

extern "C"
void PrintResult(ResultCode result, long value)
{
    switch (result)
    {
        case ShowSquare:
            cout << "Square is: " << value << endl;
            break;

        default:
            cout << "Error calculating square" << endl;
            break;
    }
}


Because you are writing a C program, the default calling mechanism is cdecl which means that all the parameters are passed on the stack, the return value is passed back in eax, and the caller is responsible for cleaning up the stack afterward.

So in order to call PrintResult, you have to push all of your parameters onto the stack before invoking the procedure. And after the procedure returns, we have to clean up our stack (add esp, 8).

Because the cdecl calling convention allows eax to be modified during the call, eax may not be preserved when PrintResult returns, so we save the calculated result before calling PrintResult and then restore it after the call returns.

I have not tried the above code, but I hope it helps get you going down the right track.


Note: Because you are using a C++ compiler, the extern "C" before PrintResult is required.

Miquella
Why would `extern "C"` be required?
Rob Kennedy
Because it is a C++ compiler, it will mangle the method name unless you put the `extern "C"` there, which would mean that the call in the assembly would have to use the mangled name. While technically possible, it's not very fun! :P
Miquella
@ Miquella, woah thank you so very much, it worked. I spent trying to figure it out. Thanks again
justbrianr
@justbrianr Does it make sense? I would be happy to explain it a bit more if anything doesn't make sense. Also, if it worked for you, would you please accept my answer? ;)
Miquella
@Miquella, I am wondering, y do we need to push eax twice
justbrianr
I was wondering if that would be confusing or not... because we're using cdecl calling convention, `eax` may be modified during the call to PrintResult. We don't know if it will be or not, that's up to how the compiler is feeling today. We can't take that chance, so we store a second copy on the stack so we can get it back after the call to PrintResult (`pop eax`).
Miquella