.commのディレクティブ作ったBSSデータセクションには浮動小点数を保存することはできないのですか?
できます。と、申しますか、メモリ(ここではBSSセクション)上ではその領域が浮動小数点数なのか整数なのか、はたまた固定小数点数なのかの区別はありません。あくまで、取り出した値をレジスタなり演算なりで扱うときに浮動小数点数として扱うか、整数として扱うかの差だけです。言い方を変えるとプログラマ次第です。デバッガーであるgdbの見せ方とも言えます。
質問者様の例では、恐らく、gdbでメモリをダンプしている場所が間違っているか、あるいは浮動小数点数の扱いについて少し誤解があるのかもしれません。小数(つまり実数)はお試しのプログラムでは64ビットの倍精度浮動小数点数で扱っています。これは、メモリ上にストアすると浮動小数点数のビットパターンになります。
ご提示のasmプログラムをcygwin(32ビット)上で確認しました。gccのバージョンは6.4.0です。
gdbでの実行例を示してみます。gdb で、fidl -4(%ebp)
の実行直後を見てみましょう。
まず手始めに、-4(%ebp)を4バイト分ダンプして、正しく2の整数がロードされるはずか確認してみます。
16 fildl -4(%ebp)
(gdb) n
17 fsqrt
(gdb) x/4bx $ebp-4
0x28cc44: 0x02 0x00 0x00 0x00
4バイト(32ビット)分、リトルエンディアンでメモリに整数の2が格納されているので、正しくロードしたはずです。
ここで、浮動小数点数用のFPUのデータレジスタにロードされているかinfo float
コマンドで確認します。
(gdb) info float
=>R7: Valid 0x40008000000000000000 +2
R6: Empty 0x00000000000000000000
R5: Empty 0x00000000000000000000
R4: Empty 0x00000000000000000000
R3: Empty 0x00000000000000000000
R2: Empty 0x00000000000000000000
R1: Empty 0x00000000000000000000
R0: Empty 0x00000000000000000000
Status Word: 0x3800
TOP: 7
Control Word: 0x037f IM DM ZM OM UM PM
PC: Extended Precision (64-bits)
RC: Round to nearest
Tag Word: 0x3fff
Instruction Pointer: 0x23:0x004011e3
Operand Pointer: 0x2b:0x0028cc44
R7 に整数の2がロードされていることが分かります。0x40008000000000000000 となっているのは
2を80ビットの16進数表記、浮動小数点数で表されているからです。
ちなみになぜ80ビットなのと言うと、試しているマシンのCPUがインテルCore i7 870 で、FPUが8087ベースで80ビットだからです。
続けてfsqrt
命令を実行します。2の平行根が得られるはずです。
(gdb) n
18 fstl 4(%esp)
(gdb) info float
=>R7: Valid 0x3fffb504f333f9de6484 +1.414213562373095049
R6: Empty 0x00000000000000000000
R5: Empty 0x00000000000000000000
R4: Empty 0x00000000000000000000
R3: Empty 0x00000000000000000000
R2: Empty 0x00000000000000000000
R1: Empty 0x00000000000000000000
R0: Empty 0x00000000000000000000
Status Word: 0x3820 PE
TOP: 7
Control Word: 0x037f IM DM ZM OM UM PM
PC: Extended Precision (64-bits)
RC: Round to nearest
Tag Word: 0x3fff
Instruction Pointer: 0x23:0x004011e6
Operand Pointer: 0x2b:0x0028cc44
Opcode: 0xd9fa
R7の値が変わっています。+1.414213562373095049となっていて、gdbにより整数2の平方根が実数で表示されていることが分かります。
更に続けて fstl 4(%esp)
を実行します。64ビット(8バイト)の浮動小数点数が4(%esp)に収まります。
それを8バイト分ダンプします。
18 fstl 4(%esp)
(gdb) n
19 movl $code, (%esp)
(gdb) x/8xb $esp+4
0x28cc0c: 0xcd 0x3b 0x7f 0x66 0x9e 0xa0 0xf6 0x3f
これを実数で表示してみると
(gdb) x/f $esp+4
0x28cc0c: 1.4142135623730951
(gdb)
となり、1.414213... で正しく2の平方根が表示されます。
FPUのデータレジスタは80ビット(10バイト)なのだけど、fst命令でメモリへストアされるとき、64ビットの倍精度浮動小数点数に変換されます。その為、info float
でR7を見たときの値とは異なることになります。
上記で、bssセクションのbuffer に正しく値が格納されていることが分かったと思います。printf
で実行して正しく表示されるのは間違いないです。
参考:AP-943 FPU、SSE、および SSE2 を使用した浮動小数点算術演算
おまけとして、8バイトの0xcd, 0x3b, ...の8バイトのシーケンスが本当に浮動小数点数として扱われているか、C言語のプログラムで確認した例を示します。メモリ上のバイト列を無理やりdouble型変数に格納して、printfで表示します。
C
1$ cat t4_test1.c
2#include <stdio.h>
3
4int main(void) {
5 unsigned char bd[] = { 0xcd, 0x3b, 0x7f, 0x66, 0x9e, 0xa0, 0xf6, 0x3f };
6
7 double d1 = *((double*)bd);
8 printf("d1 = [%f]\n", d1);
9 return 0;
10}
11
12$ gcc -Wall t4_test1.c
13
14$ ./a.exe
15d1 = [1.414214]
16
17$
正しく2の平方根である1.41421...が表示されました。
2018/03/13 追記しました。
コメントをいただいたのでこちらでも検証しました。不正な(期待しない)値が表示されたのはコメントでの推測のとおり、gdbのxコマンドの挙動によるもので、メモリ上の対象範囲の解釈の違いが原因です。
結論としては「gdbの使い方の問題」と言えます。
以下のとおり、トレースしてみます。
当該プログラムをrunし、fstl 4(%esp)
の実行直後でブレイクします。
(gdb)
18 fstl 4(%esp)
(gdb)
19 movl $code, (%esp)
ここでx/f
コマンド実行。期待した値(正しいのは1.1414...)が表示されていません。
(gdb) x/f $esp+4
0x28cc0c: 3.01326646e+23
x/8xb
で8バイト分ダンプします。メモリ上の8バイトは正しいことが分かります。
(gdb) x/8xb $esp+4
0x28cc0c: 0xcd 0x3b 0x7f 0x66 0x9e 0xa0 0xf6 0x3f
続けてx/f
を実行。直前でサイズ指定した為にそのサイズがデフォルト値として利用されるので、正しく表示されます。
(gdb) x/f $esp+4
0x28cc0c: 1.4142135623730951
おまけとして、「サイズ指定すればいいのか」と言うことで、x/f
にサイズ指定(g=8バイト/ w=(4バイト)して実行してみます。
(gdb) x/fg $esp+4
0x28cc0c: 1.4142135623730951
(gdb) x/fw $esp+4
0x28cc0c: 3.01326646e+23
(gdb)
x/fw
ではダメなことが分かります。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/03/13 04:51
2018/03/13 05:30
2018/03/13 06:19
2018/03/14 04:51