GCC の調査(1)
GCC が出力するアセンブリ言語のコードの中で呼ばれる関数について調べていきます。
long のかけ算
long multiply_long_cpp(long x, long y) { return x * y; }
から作られるアセンブリ言語のコードは以下のようになります。
_Z17multiply_long_cppll: link.w %fp,#0 move.l 12(%fp),-(%sp) move.l 8(%fp),-(%sp) jsr __mulsi3 addq.l #8,%sp unlk %fp rts
スタックが
| 0 | 4 | |
| スタックの入り口 | x | y |
の状態でこの関数が呼び出されると
| 0 | 4 | 8 | 12 | 16 | 20 | |
| スタックの入り口 | x | y | fp | pc | x | y |
の状態で __mulsi3 が呼び出されます。__mulsi3 は d0 レジスタに x と y の積を返します。
short のかけ算
short multiply_short_cpp(short x, short y) { return x * y; }
から作られるアセンブリ言語のコードは以下のようになります。
_Z18multiply_short_cppss: link.w %fp,#-4 move.l 8(%fp),%d1 move.l 12(%fp),%d0 move.w %d1,%d1 move.w %d1,-2(%fp) move.w %d0,%d0 move.w %d0,-4(%fp) move.w -2(%fp),%d1 move.w -4(%fp),%d0 muls.w %d1,%d0 unlk %fp rts
スタックが
| 0 | 4 | |
| スタックの入り口 | x | y |
の状態でこの関数が呼び出されると d0 に y、d1 に x を入れて muls を実行しているようです。それ以外のところは何をやっているのか不明です。
double のかけ算
double multiply_double_cpp(double x, double y) { return x * y; }
から作られるアセンブリ言語のコードは以下のようになります。
_Z19multiply_double_cppdd: link.w %fp,#0 move.l 20(%fp),-(%sp) move.l 16(%fp),-(%sp) move.l 12(%fp),-(%sp) move.l 8(%fp),-(%sp) jsr __muldf3 lea (16,%sp),%sp unlk %fp rts
x の上位32ビットを x0、下位32ビットを x1 とします。y の上位32ビットを y0、下位32ビットを y1 とします。スタックが
| 0 | 4 | 8 | 12 | |
| スタックの入り口 | x0 | x1 | y0 | y1 |
の状態でこの関数が呼び出されると link の後
| 0 | 4 | 8 | 12 | 16 | 20 | |
| スタックの入り口 | fp | pc | x0 | x1 | y0 | y1 |
となり
| 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | |
| スタックの入り口 | x0 | x1 | y0 | y1 | fp | pc | x0 | x1 | y0 | y1 |
の状態で __muldf3 が呼び出されます。__muldf3 は d0 と d1 レジスタに x と y の積を返します。
float のかけ算
float multiply_float_cpp(float x, float y) { return x * y; }
から作られるアセンブリ言語のコードは以下のようになります。
_Z18multiply_float_cppff: link.w %fp,#0 move.l 12(%fp),-(%sp) move.l 8(%fp),-(%sp) jsr __mulsf3 addq.l #8,%sp unlk %fp rts
スタックが
| 0 | 4 | |
| スタックの入り口 | x | y |
の状態でこの関数が呼び出されると
| 0 | 4 | 8 | 12 | 16 | 20 | |
| スタックの入り口 | x | y | fp | pc | x | y |
の状態で __mulsf3 が呼び出されます。__mulsf3 は d0 レジスタに x と y の積を返します。
long のわり算
long divide_long_cpp(long x, long y) { return x / y; }
から作られるアセンブリ言語のコードは以下のようになります。
_Z15divide_long_cppll: link.w %fp,#0 move.l 12(%fp),-(%sp) move.l 8(%fp),-(%sp) jsr __divsi3 addq.l #8,%sp unlk %fp rts
スタックが
| 0 | 4 | |
| スタックの入り口 | x | y |
の状態でこの関数が呼び出されると
| 0 | 4 | 8 | 12 | 16 | 20 | |
| スタックの入り口 | x | y | fp | pc | x | y |
の状態で __divsi3 が呼び出されます。__divsi3 は d0 レジスタに x を y で割った商を返します。
short のわり算
short divide_short_cpp(short x, short y) { return x / y; }
から作られるアセンブリ言語のコードは以下のようになります。
_Z16divide_short_cppss: link.w %fp,#-4 move.l 8(%fp),%d1 move.l 12(%fp),%d0 move.w %d1,%d1 move.w %d1,-2(%fp) move.w %d0,%d0 move.w %d0,-4(%fp) move.w -2(%fp),%a0 move.w -4(%fp),%a1 move.l %a1,-(%sp) move.l %a0,-(%sp) jsr __divsi3 addq.l #8,%sp move.l %d0,%d0 unlk %fp rts
long の場合と同様 __divsi3 を呼び出しています。
double のわり算
double divide_double_cpp(double x, double y) { return x / y; }
から作られるアセンブリ言語のコードは以下のようになります。
_Z17divide_double_cppdd: link.w %fp,#0 move.l 20(%fp),-(%sp) move.l 16(%fp),-(%sp) move.l 12(%fp),-(%sp) move.l 8(%fp),-(%sp) jsr __divdf3 lea (16,%sp),%sp unlk %fp rts
x の上位32ビットを x0、下位32ビットを x1 とします。y の上位32ビットを y0、下位32ビットを y1 とします。スタックが
| 0 | 4 | 8 | 12 | |
| スタックの入り口 | x0 | x1 | y0 | y1 |
の状態でこの関数が呼び出されると link の後
| 0 | 4 | 8 | 12 | 16 | 20 | |
| スタックの入り口 | fp | pc | x0 | x1 | y0 | y1 |
となり
| 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | |
| スタックの入り口 | x0 | x1 | y0 | y1 | fp | pc | x0 | x1 | y0 | y1 |
の状態で __divdf3 が呼び出されます。__divdf3 は d0 と d1 レジスタに x を y で割った商を返します。
float のわり算
float divide_float_cpp(float x, float y) { return x / y; }
から作られるアセンブリ言語のコードは以下のようになります。
_Z16divide_float_cppff: link.w %fp,#0 move.l 12(%fp),-(%sp) move.l 8(%fp),-(%sp) jsr __divsf3 addq.l #8,%sp unlk %fp rts
スタックが
| 0 | 4 | |
| スタックの入り口 | x | y |
の状態でこの関数が呼び出されると
| 0 | 4 | 8 | 12 | 16 | 20 | |
| スタックの入り口 | x | y | fp | pc | x | y |
の状態で __divsf3 が呼び出されます。__divsf3 は d0 レジスタに x を y で割った商を返します。


