Intel x86 Assembly& Microarchitecture 32位cdecl —处理浮点
示例
作为参数(浮动,双精度)
浮点数为32位,它们自然地在堆栈上传递。
双精度数为64位,它们遵循LittleEndian约定1在栈中传递,首先推入高32位,然后推低32位。
//被调用者的C原型 double foo(double a, float b); foo(3.1457, 0.241); ;Assembly call ;3.1457 is 0x40092A64C2F837B5ULL ;0.241 is 0x3e76c8b4 push DWORD 3e76c8b4h ;b, is 32 bits, nothing special here push DWORD 0c2f837b5h ;a, is 64 bits, Higher part of 3.1457 push DWORD 40092a64h ;a, is 64 bits, Lower part of 3.1457 call foo add esp, 0ch ;Call, using the FPU ;ST(0) = a, ST(1) = b sub esp, 0ch fstp QWORD PTR [esp] ;Storing a as a QWORD on the stack fstp DWORD PTR [esp+08h] ;Storing b as a DWORD on the stack call foo add esp, 0ch
作为参数(长双精度)
长双打是80位2宽,而在堆栈上可以用两个32位压入和一个16位压入存储TBYTE(对于4+4+2=10),以使堆栈对准4个字节,它结束占用12个字节,因此使用了三个32位压入。
遵循LittleEndian约定,首先将位79-64推入3,然后将位63-32推入,然后是位31-0。
//被调用者的C原型 void __attribute__((cdecl)) foo(long double a); foo(3.1457); ;Call to foo in assembly ;3.1457 is 0x4000c9532617c1bda800 push DWORD 4000h ;Bits 79-64, as 32 bits push push DWORD 0c9532617h ;Bits 63-32 push DWORD 0c1bda800h ;Bits 31-0 call foo add esp, 0ch ;Call to foo, using the FPU ;ST(0) = a sub esp, 0ch fstp TBYTE PTR [esp] ;Store a as ten byte on the stack call foo add esp, 0ch
作为返回值
无论大小如何,浮点值都将在ST(0)4中返回。
//C float one() { return 1; } ;Assembly fld1 ;ST(0) = 1 ret //C double zero() { return 0; } ;Assembly fldz ;ST(0) = 0 ret //C long double pi() { return PI; } ;Assembly fldpi ;ST(0) = PI ret
1在较低地址的较低DWORD。
2从十字节开始称为TBYTE。
3使用带有任何扩展名的全角推送,不使用较高的WORD。
4TBYE宽,请注意,与整数相反,FP总是以要求的精度返回。