long longな返り値について

投稿者: | 2013年4月16日

今日ふと思いついたこと。x86なLinuxでgccを使ってプログラムを作成すると、普通eaxに関数の返り値が入る。でも、long longは8バイトつまり64bitなので、32bitのeaxには入りきらない。ちょっと調べればわかることなんだけど、これをどうやって返しているのかを調べたのでメモしておく。環境はGentoo Linux 13.0 (amd64)、gccはportageから入れた4.6.3p1.11。

まず、適当にlong longな値を返す関数を書いてみます。

/* return_longlong.c */

long long return_64bit()
{
	return 0x12345678deadbeef;
}

int main()
{
	return_64bit();
}

これを適当にgcc -g -m32 return_longlong.cとかでコンパイルしてobjdump -S a.outしてみます。してみた結果が以下。

080483d4 <return_64bit>:
long long return_64bit()
{
 80483d4:	55                   	push   %ebp
 80483d5:	89 e5                	mov    %esp,%ebp
	return 0x12345678deadbeef;
 80483d7:	b8 ef be ad de       	mov    $0xdeadbeef,%eax
 80483dc:	ba 78 56 34 12       	mov    $0x12345678,%edx
}
 80483e1:	5d                   	pop    %ebp
 80483e2:	c3                   	ret    

つまり、上位32ビットはedx、下位32ビットはeaxに入るようです。cdecl呼び出し規約では関数内でeax, ecx, edxが自由に使用できるから、返り値の上位32ビットを格納する場所にedxが選ばれたんだと思います。ecxが使用されない理由はちょっと思いつかないです。気まぐれかな?

確証はないけれど、下位32ビットがedxではなくeaxに入るのは、もしreturn_64bit()が32bitの値を返すだろうと期待して呼び出されても大丈夫なようにだと思います。例えば、char型変数に32bitの値0x12345678を代入しようとした場合に下位8bitの0x78が代入される、つまり、入りきらない上位の値は切り捨てられるのと同じです。仮にedxに下位、eaxに上位を入れてしまうと、eaxに32bitの返り値が入ってると思って処理を行った場合、上の例で言えば下位の0xdeadbeefが取得したかったのに、上位の0x12345678が取得されて不都合だからだと思います。

ちなみに、64bitでコンパイルするとこんな感じでeaxの64bit版的なレジスタraxに返り値が入ります。また、試しに0x12345678deadbeefを0xdeadbeefに変えてコンパイル→逆アセンブルしなおしたところ、返り値が32bitで表せればraxは使わずeaxで返り値を返すという動作をするようです。

00000000004004e4 <return_64bit>:
long long return_64bit()
{
  4004e4:	55                   	push   %rbp
  4004e5:	48 89 e5             	mov    %rsp,%rbp
	return 0x12345678deadbeef;
  4004e8:	48 b8 ef be ad de 78 	movabs $0x12345678deadbeef,%rax
  4004ef:	56 34 12 
}
  4004f2:	5d                   	pop    %rbp
  4004f3:	c3                   	retq   
00000000004004e4 <return_64bit>:
long long return_64bit()
{
  4004e4:	55                   	push   %rbp
  4004e5:	48 89 e5             	mov    %rsp,%rbp
	return 0xdeadbeef;
  4004e8:	b8 ef be ad de       	mov    $0xdeadbeef,%eax
}
  4004ed:	5d                   	pop    %rbp
  4004ee:	c3                   	retq   

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です