Binary2.0勉強会 6

前回確認した関数の呼び出し回りを実際に逆アセして見てみましょう。

niha@hoge:~/src/c$ cat bin02.c
int hoge(int i){
  int ret = i;
  return ret;
}
niha@hoge:~/src/c$ gcc -c -g bin02.c
niha@hoge:~/src/c$ objdump -S bin02.o

bin02.o:     file format elf32-i386

Disassembly of section .text:

00000000 <hoge>:
int hoge(int i){
   0:	55                   	push   %ebp
   1:	89 e5                	mov    %esp,%ebp
   3:	83 ec 10             	sub    $0x10,%esp
  int ret = i;
   6:	8b 45 08             	mov    0x8(%ebp),%eax
   9:	89 45 fc             	mov    %eax,-0x4(%ebp)
  return ret;
   c:	8b 45 fc             	mov    -0x4(%ebp),%eax
}
   f:	c9                   	leave  
  10:	c3                   	ret    

まずは、ベースポインタをスタックに退避させています。
その後、ベースポインタをスタックポインタの値に、スタックポインタは16引いて、16バイト分のスタックが確保されました。16バイトも使わないと思うんですが…なんででしょうね。
ここから関数内の処理。第一引数を EBP 経由でさしているのが「0x8(%ebp)」。ちなみに「0x4(%ebp)」には ret の戻り先が、「(%ebp)」には元のベースポインタが入ってます。
第一引数を EAX に、更に EAX をスタックに積んでいます。そして、返り値としてスタックに積まれた第一引数を EAX レジスタに。
えーと、無駄ですね。無駄です。許せない。
ふざけんな、ということで最適化オプションつけてコンパイルした結果。

   0:	55                   	push   %ebp
   1:	89 e5                	mov    %esp,%ebp
   3:	8b 45 08             	mov    0x8(%ebp),%eax
   6:	5d                   	pop    %ebp
   7:	c3                   	ret

素晴らしー。
あとは leave で EBP と ESP を復元して、 ret でぴょーんと飛んでおしまい。
関数呼ぶときは大体こんな感じで。

niha@hoge:~/src/c$ cat bin03.c
int func(int x, int y, int z);

void hoge(){
  func(1, 2, 3);
}
niha@hoge:~/src/c$ gcc -c -g bin03.c
niha@hoge:~/src/c$ objdump -S bin03.o

bin03.o:     file format elf32-i386

Disassembly of section .text:

00000000 <hoge>:
int func(int x, int y, int z);

void hoge(){
   0:	55                   	push   %ebp
   1:	89 e5                	mov    %esp,%ebp
   3:	83 ec 18             	sub    $0x18,%esp
  func(1, 2, 3);
   6:	c7 44 24 08 03 00 00 	movl   $0x3,0x8(%esp)
   d:	00 
   e:	c7 44 24 04 02 00 00 	movl   $0x2,0x4(%esp)
  15:	00 
  16:	c7 04 24 01 00 00 00 	movl   $0x1,(%esp)
  1d:	e8 fc ff ff ff       	call   1e <hoge+0x1e>
}
  22:	c9                   	leave  
  23:	c3                   	ret    

スタックにぺぺっと積んで call。おしまい!