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 總是以更高的精度返回。