非専門的シンギュラリティー研究所

無限に動き続けるシステムを表す方法を AI なども使って考えていきます。

アセンブラ(14)

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 で割った商を返します。