0

I have asked a similar question a few days ago, was very imprecise back then though, so here is a much more detailed post. So I am currently writing x86 32 Bit assembly using NASM and I want to use my custom function in a c++ program. I have issues working with the returned value though.

Here is my sample code in assembly:

section .data
value: dq 1.0
section .text
global _arsinh
_arsinh:
    fld dword[esi-8]      ;loads the given value into st0
    ret

Here is my sample/test code in c++:

#include <iostream>
extern "C" float arsinh(float);

int main()
{
    float test = arsinh(5.0);
    printf("%f\n", test);                    //Displays -96715160...
    printf("%f\n", arsinh(5.0));             //Displays -96715160...
    std::cout << test << std::endl;          //Displays -9.671512e+24
    std::cout << arsinh(5.0) << std::endl;   //Displays 5
}

All the assembly code does is load given value from the stack(5.0 in this case) and store it in st0. The problem I am now encountering is, that all but the last of the print statements display a wrong value (not 5.0). I assume the issue is that I am loading a dword and not a qword, as the following code works(displays the correct values) completly fine:

section .data
value: dq 1.0
section .text
global _arsinh
_arsinh:
    fld qword[value]      ;loads value into st0
    ret

I would like to save the returned value into a float and then do some additional calculations in c++/c with it, but I can't seem to figure out how to do that, as I have no choice but to load the given value as a dword.

Weather Vane
  • 33,872
  • 7
  • 36
  • 56
Hajaku
  • 39
  • 5
  • 4
    I don't understand `fld dword[esi-8]`. Where is _ESI_ set? It isn't part of the 32-bit C calling convention for passing paremeters. _C_ floats (single precision) are 32-bits wide (DWORD). The float has been passed on the stack. I think you should be using `fld dword[esp+4]` . dword [esp+0] contains the 32-bit return address pushed by the _CALL_ , dword [esp+4] contains the 32-bit float. – Michael Petch Jun 18 '16 at 19:04
  • 1
    Thank you! That works. I have no idea where I found the [esi-8] thing, even weirder that it worked... – Hajaku Jun 18 '16 at 19:15
  • _ESI_ only appeared to work sometimes. The fact it would yield a correct (in one case) result when referenced in your function is more or less luck, and is dependent on how the calling function may have been using _ESI_ for its own purposes. – Michael Petch Jun 18 '16 at 19:21
  • 2
    I wrote some code (and linked in a comment the other day) that was an example of creating an _arsinh function (I used the x87 FPU instructions just as a test case). That code also loads the float passed on the stack. The code is probably of no use to you, but I'll link to it again. http://www.capp-sysware.com/misc/stackoverflow/37865951/arcsinh.asm – Michael Petch Jun 18 '16 at 19:29
  • 1
    You should have edited the original question and asked to re-open. – too honest for this site Jun 18 '16 at 19:49
  • I have taken the info you provided in this question and reworded the original question here: http://stackoverflow.com/questions/37865951/using-fpu-return-values-in-c-code . I am marking this as a duplicate of the revised original. – Michael Petch Jun 18 '16 at 20:12

0 Answers0