32 位 cdecl 處理浮點
作為引數(float, double)
浮點數大小為 32 位,它們在堆疊中自然傳遞。
雙打是 64 位大小,它們在堆疊上傳遞,遵循 Little Endian 約定 1 ,首先推送高 32 位而不是低位。
//C prototype of callee
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 寬,而在堆疊上 TBYTE 可以儲存兩個 32 位推送和一個 16 位推送(4 + 4 + 2 = 10),以保持堆疊對齊 4 個位元組,它結束佔用 12 個位元組,因此使用三個 32 位推送。
尊重 Little Endian 約定,第 79-64 位先按 3 ,然後按 63-32 位,然後按 31-0 位。
//C prototype of the callee
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,來自 Ten Bytes。
3 使用任何延伸的全寬度推動,不使用更高的 WORD。
4 TBYE 寬,注意與整數相反,FP 總是以更高的精度返回。