NASM x86 程序集中的 C 浮动
C float in NASM x86 assembly
在我的大学项目中,我必须在 x86 汇编中使用浮点数的二进制表示来进行算术运算。禁止使用 FPU,所以我尝试读取浮点数并将 return 作为 DWORD 但无论我尝试做什么,我都会得到“-nan”。有什么建议吗?
编辑:
我使用 gcc,它是 32 位代码
C 中的声明(我无法更改)
extern "C" float func(float num);
*.asm 文件
section .text
global func
func:
;prolog
push ebp
mov ebp, esp
; zapamiętanie rejestrów zachowywanych
push ebx
push esi
push edi
mov eax, DWORD [ebp+8]
;mov eax, 0xffffffff i checked that but i still get the same result
; odtworzenie rejestrów, które były zapamiętane
pop edi
pop esi
pop ebx
;epilog
pop ebp
ret
示例结果(对于 256)
01000011100000000000000000000000
11111111110000000000000000000000
num1: 256.000000
num2: -nan
编辑:
没有检查位部分的C代码
#include <stdio.h>
extern "C" float func(float num);
int main()
{
float num1;
float num2;
scanf("%f", &num1);
num2=func(num1);
printf("num1: %f\nnum2: %f\n", num1, num2);
return 0;
}
在 32 位 Linux ABI 中,float
值实际上在 8087 FP 堆栈的顶部被 return 编辑为 long double
。不使用 FPU 就不能 return a float
。
你可能被限制做的是加减法的浮点运算……但是你仍然需要将浮点栈中的结果加载到return中。在 64 位模式下,您将 return float
值作为 xmm0
寄存器中的 double
。
尝试将代码更改为:
section .text
global func
func:
push ebp
mov ebp, esp
flds 8(%ebp)
pop ebp
ret
如果您将 return 类型的函数声明为 float
,结果将 return 在 FPU (ST0) 中编辑。对于 returning EAX
中的值,您必须将其声明为整数类型。对于 printf
你必须伪造一个浮点数。示例:
caller.c:
#include <stdio.h>
#include <stdint.h>
extern float asmfunc1(float);
extern uint32_t asmfunc2(float);
int main (void)
{
printf ("asmfunc1: %f\n", asmfunc1(456.78));
uint32_t ifl = asmfunc2(123.45);
float* pfl = (float*) &ifl; // Faking a float
printf ("asmfunc2: %f\n", *pfl);
return 0;
}
callee.asm:
section .text
global asmfunc1, asmfunc2
asmfunc1:
fld dword [esp+4]
ret
asmfunc2:
push ebp
mov ebp, esp
mov eax, [ebp+8]
leave
ret
构建 & 运行:
nasm -felf callee.asm
gcc -m32 callee.o caller.c
./a.out
在我的大学项目中,我必须在 x86 汇编中使用浮点数的二进制表示来进行算术运算。禁止使用 FPU,所以我尝试读取浮点数并将 return 作为 DWORD 但无论我尝试做什么,我都会得到“-nan”。有什么建议吗?
编辑: 我使用 gcc,它是 32 位代码
C 中的声明(我无法更改)
extern "C" float func(float num);
*.asm 文件
section .text
global func
func:
;prolog
push ebp
mov ebp, esp
; zapamiętanie rejestrów zachowywanych
push ebx
push esi
push edi
mov eax, DWORD [ebp+8]
;mov eax, 0xffffffff i checked that but i still get the same result
; odtworzenie rejestrów, które były zapamiętane
pop edi
pop esi
pop ebx
;epilog
pop ebp
ret
示例结果(对于 256)
01000011100000000000000000000000
11111111110000000000000000000000
num1: 256.000000
num2: -nan
编辑:
没有检查位部分的C代码
#include <stdio.h>
extern "C" float func(float num);
int main()
{
float num1;
float num2;
scanf("%f", &num1);
num2=func(num1);
printf("num1: %f\nnum2: %f\n", num1, num2);
return 0;
}
在 32 位 Linux ABI 中,float
值实际上在 8087 FP 堆栈的顶部被 return 编辑为 long double
。不使用 FPU 就不能 return a float
。
你可能被限制做的是加减法的浮点运算……但是你仍然需要将浮点栈中的结果加载到return中。在 64 位模式下,您将 return float
值作为 xmm0
寄存器中的 double
。
尝试将代码更改为:
section .text
global func
func:
push ebp
mov ebp, esp
flds 8(%ebp)
pop ebp
ret
如果您将 return 类型的函数声明为 float
,结果将 return 在 FPU (ST0) 中编辑。对于 returning EAX
中的值,您必须将其声明为整数类型。对于 printf
你必须伪造一个浮点数。示例:
caller.c:
#include <stdio.h>
#include <stdint.h>
extern float asmfunc1(float);
extern uint32_t asmfunc2(float);
int main (void)
{
printf ("asmfunc1: %f\n", asmfunc1(456.78));
uint32_t ifl = asmfunc2(123.45);
float* pfl = (float*) &ifl; // Faking a float
printf ("asmfunc2: %f\n", *pfl);
return 0;
}
callee.asm:
section .text
global asmfunc1, asmfunc2
asmfunc1:
fld dword [esp+4]
ret
asmfunc2:
push ebp
mov ebp, esp
mov eax, [ebp+8]
leave
ret
构建 & 运行:
nasm -felf callee.asm
gcc -m32 callee.o caller.c
./a.out