I have a small program written in AT&T assembler for the x64 processor in linux and compiled it using Gnu Assembler using the fpatan function. I know I can get the atan value other ways. I am not able to understand how to move floating point values created in the st0-st7 registers into a C++ program.
In this example, I can view the result value using GDB.
My code is as follows:
# trigtest1.s - An example of using the FPACOS instructions
.section .data
y:
.float 1.625
x:
.float .25
.section .bss
.lcomm result, 4
.section .text
.globl _start
_start:
nop
finit
flds y
flds x
fpatan
fsts result
movl $1, %eax
movl $0, %ebx
int $0x80
I can compile and link it with:
as -gstabs trigtest1.s -o trigtest.o ld trigtest.o -o trigtest
With GDB after stepping through the program with a breakpoint set at movl $1, %eax I get: (gdb)x/f &result 0x6000e0 : 1.41814697
This is what I was expecting. The problem comes when I try to use it in a C++ program. First here is the function.
# asm.s - An example of using the FPATAN function
.global ArcTan
.section .data
y:
.float 1.625
x:
.float .25
.section .bss
.lcomm result, 4
.section .text
ArcTan:
nop
finit
flds y
flds x
fpatan
fsts result
nop
ret
And here is the C++ program that calls the assembler function:
#include <iostream>
using namespace std;
extern "C" float ArcTan();
int main()
{
cout<<"Arctan is "<<ArcTan()<<endl;
cout<<endl;
return 0;
}
I compile and link using: as -gstabs asm.s -o asm.o g++ -gstabs -O0 main.cpp asm.o -o runme
When I use GDB to view what is going on, the value in result is never updated and stays at 0. I would like to use the value calculated with fpatan in the C++ program but have not been successful in returning the value. Any help will be greatly appreciated.
x86-64 returns float
in XMM0, not legacy x87 st0
. Build your code with
g++ -m32 asm.s main.cpp -o runme
to build 32-bit code that uses the 32-bit calling convention if you want to use legacy x87 for FP math.
Note that your C++ code isn't reading result
, it's reading the return value of the function which it expects in a register. If you did use extern float result;
in your C++ code, you could read it just fine.
(turns out Michael Petch has already written a full answer on Return a float from a 64-bit assembly function that uses x87 FPU, closing this as a duplicate.)