Click to See Complete Forum and Search --> : Assembler


kakalake
May 6th, 2003, 04:39 PM
Hello!
Can someone help me with the following assemblercode

extern "C" long double _cdecl exp (double x)
_exp PROC NEAR
PUBLIC _exp
FLDL2E
FLD QWORD PTR [ESP+4] //; x
FMUL //; z = x*log2(e)
FIST DWORD PTR [ESP+4] // round(z)
SUB ESP, 12
MOV DWORD PTR [ESP], 0
MOV DWORD PTR [ESP+4], 80000000H
FISUB DWORD PTR [ESP+16] //; z - round(z)
MOV EAX, [ESP+16]
ADD EAX,3FFFH
MOV [ESP+8],EAX
JLE SHORT UNDERFLOW
CMP EAX,8000H
JGE SHORT OVERFLOW
F2XM1
FLD1
FADD //; 2^(z-round(z))
FLD TBYTE PTR [ESP] //; 2^(round(z))
ADD ESP,12
FMUL //; 2^z = e^x
RET

UNDERFLOW:
FSTP ST
FLDZ //; return 0
ADD ESP,12
RET

OVERFLOW:
PUSH 07F800000H //; +infinity
FSTP ST
FLD DWORD PTR [ESP] //; return infinity
ADD ESP,16
RET

_exp ENDP
return 0
}


I want to use this function in my c++ programm. I am using Vc++ 6.0.

Thanks in advance

Paul McKenzie
May 6th, 2003, 05:09 PM
It's not C++, so how do you propose to use it in a C++ program?

Do you mean

a) translate it into C++ code or

b) place it in-line into the C++ code or

c) use a seperate assembler and compile the code. Then include the obj in your project

Which one a), b), or c), or do you have something else in mind?

Regards,

Paul McKenzie

kakalake
May 6th, 2003, 05:16 PM
I want to use it inline in my code:

If you are interested you can show me shortly how to solve my problem with each of your suggested solutions.

Thanks

Paul McKenzie
May 6th, 2003, 05:27 PM
Originally posted by kakalake
I want to use it inline in my code:

If you are interested you can show me shortly how to solve my problem with each of your suggested solutions.

Thanks You have to use the _asm keyword. It should be documented in the VC++ help.

To translate it to C++, you have to know what the code is supposed to do and just rewrite it in C++.

To compile it using a separate assembler, you have to get MASM or some other assembler to create an obj. Then you include the obj file in your project.

Regards,

Paul McKenzie

kakalake
May 6th, 2003, 05:41 PM
I already used the keyword _asm but it still doesnīt work.

double exp (double x)
{
_asm
{
FLDL2E
FLD QWORD PTR [ESP+4] //; x
FMUL //; z = x*log2(e)
FIST DWORD PTR [ESP+4] // round(z)
SUB ESP, 12
MOV DWORD PTR [ESP], 0
MOV DWORD PTR [ESP+4], 80000000H
FISUB DWORD PTR [ESP+16] //; z - round(z)
MOV EAX, [ESP+16]
ADD EAX,3FFFH
MOV [ESP+8],EAX
JLE SHORT UNDERFLOW
CMP EAX,8000H
JGE SHORT OVERFLOW
F2XM1
FLD1
FADD //; 2^(z-round(z))
FLD TBYTE PTR [ESP] //; 2^(round(z))
ADD ESP,12
FMUL //; 2^z = e^x
RET

UNDERFLOW:
FSTP ST
FLDZ //; return 0
ADD ESP,12
RET

OVERFLOW:
PUSH 07F800000H //; +infinity
FSTP ST
FLD DWORD PTR [ESP] //; return infinity
ADD ESP,16
RET

}

return 0;
}


Everything works fine but when the function jumps to the label Underflow, or Overflow it breaks with an access violation error. This error occurs when the label tries to RETurn with RET to the position where it was called.

rxbagain
May 6th, 2003, 06:24 PM
You must not call RET in your directly in your code. This will invalidate the stack frame becuase when you entered the procedure, the compiler added this code to your own

push ebp
mov ebp, esp
sub esp, 40h
push ...
push...
...

By calling RET in your code, you did not cleaned the ESP, so the return address is invalid.

What you have to do is declare a double variable to store the result instead of directly accessing offsets of the esp and in your code, add a JUMPLABEL before the return statement and jump to that label instead of issuing RET.

double exp (double x)
{
double retval;
__asm {

...
...
JMP RETURN_RESULT

UNDERFLOW:
...
...
JMP RETURN_RESULT

OVERFLOW:
...
...
JMP RETURN_RESULT
}
RETURN_RESULT:
return retval;
}


Hope this will help you.

kakalake
May 6th, 2003, 06:54 PM
i have not written the code. I havenīt any experiences with assembler. Could you show me what you mean?

Thanks

rxbagain
May 6th, 2003, 08:52 PM
This is the modified code. I removed the ESP and replaced them with variable to avoid offset error.


double exp (double myval)
{
double retval = 0;
DWORD tempval[3];
__asm {
FLDL2E
FLD QWORD PTR [myval] //; x
FMUL //; z = x*log2(e)
FIST DWORD PTR [myval] // round(z)
MOV DWORD PTR [tempval], 0
MOV DWORD PTR [tempval + 4], 80000000H
FISUB DWORD PTR [myval] //; z - round(z)
MOV EAX, DWORD PTR [myval]
ADD EAX,3FFFH
MOV [tempval+8],EAX
JLE SHORT UNDERFLOW
CMP EAX,8000H
JGE SHORT OVERFLOW
F2XM1
FLD1
FADD //; 2^(z-round(z))
FLD TBYTE PTR [tempval] //; 2^(round(z))
FMUL //; 2^z = e^x
JMP RETURN_RESULT

UNDERFLOW:
FSTP ST
FLDZ //; return 0
JMP RETURN_RESULT

OVERFLOW:
PUSH 07F800000H //; +infinity
FSTP ST
ADD ESP, 4
FLD DWORD PTR [tempval] //; return infinity

RETURN_RESULT:
FST QWORD PTR [retval];
}
return retval;
}


Hope this will help you.

kakalake
May 7th, 2003, 04:08 AM
Thanks a lot to all especially to rxbagain.

Thanks, thanks, thanks ....