1
2 // 畢業(yè)論文做Pascal編譯器,把編譯生成的中間代碼翻譯為 nasm 匯編調(diào)用 C 語言庫函數(shù)時,在輸出 float 部分出現(xiàn)問題。
3
4
5 // 先說明一下,我安排棧中數(shù)據(jù) 8字節(jié)對齊,不管數(shù)據(jù)實際大小,都分配 8字節(jié),按最低字節(jié)尋址。
6 // 當然,調(diào)用 C 語言函數(shù)時的參數(shù)棧,還是按 i386 的來。
7
8
9 // C printf 格式化字符串
10 data.add( head + "c_format_float32 : db \'%f\', 0" );
11 data.add( head + "c_format_float64 : db \'%lf\', 0" );
12 data.add( head + "c_format_float64G: db \'%G\', 0" );
13
14
15 // 棧頂已經(jīng)是 8字節(jié)的 ieee754 double 數(shù)據(jù),然后
16 text.add( line + "push dword c_format_float64G" );
17 // 或 text.add( line + "push dword c_format_float64" ); 也正確
18 text.add( head + "call printf" );
19 text.add( head + "add esp, 12" );
20 // 生成可執(zhí)行文件后,運行輸出正確
21
22
23 // 棧頂已經(jīng)是 4字節(jié)的 ieee754 float 數(shù)據(jù),且不等于0(次棧頂 4字節(jié)全零),然后
24 text.add( line + "push dword c_format_float32" );
25 text.add( head + "call printf" );
26 text.add( head + "add esp, 12" );
27 // 生成可執(zhí)行文件后,運行輸出 0.000000
28
29
30 // 正確的是
31 // 棧頂已經(jīng)是 4字節(jié)的 ieee754 float 數(shù)據(jù),然后
32 // 先把4字節(jié)的float 轉(zhuǎn)為 8字節(jié)的double
33 text.add( line + "fld dword [esp]" );
34 text.add( head + "fstp qword [esp]" ); // 8字節(jié)對齊,未覆蓋棧中數(shù)據(jù)
35 text.add( head + "push dword c_format_float32" );
36 text.add( head + "call printf" );
37 text.add( head + "add esp, 12" );
38 // 生成可執(zhí)行文件后,運行輸出正確
39
40
結(jié)論:
C 語言的 printf 使用 %f 來輸出 float 時,實際上先把 4字節(jié)的float轉(zhuǎn)化為 8字節(jié)的double,然后訪問了棧上的 8字節(jié)數(shù)據(jù)。
(環(huán)境:Ubuntu12.04 32位 intel i3 nasm gcc)