2009-06-11 22 views
9

最近、アセンブリレベルでプログラムをデバッグする必要がありました。私は多くのアセンブラ経験を持っていないので、他の人々のコードをデバッグする前に、単純なC言語のプログラムを書いて、それをシングルステップで実行して言語の感覚を得ることにしました。しかし、私は本当に(-ggdb -O0でコンパイルされた)の2行で作られたものをGCC得ることはありません:このアセンブリはどのように機能しますか?

MAX_SIZEは5であることを#defineで定義されており、私は0x8の中に保存されているローカル変数((ある
items[tail] = i; 
tail = (tail+1) % MAX_SIZE; 

%ebp)、私は推測する)。 GDBによると、これは次のようになります。

0x08048394 <queue+17>: mov 0x8049634,%edx 
0x0804839a <queue+23>: mov 0x8(%ebp),%eax 
0x0804839d <queue+26>: mov %eax,0x804963c(,%edx,4) 
0x080483a4 <queue+33>: mov 0x8049634,%eax 
0x080483a9 <queue+38>: lea 0x1(%eax),%ecx 
0x080483ac <queue+41>: movl $0x66666667,-0xc(%ebp) 
0x080483b3 <queue+48>: mov -0xc(%ebp),%eax 
0x080483b6 <queue+51>: imul %ecx 
0x080483b8 <queue+53>: sar %edx 
0x080483ba <queue+55>: mov %ecx,%eax 
0x080483bc <queue+57>: sar $0x1f,%eax 
0x080483bf <queue+60>: mov %edx,%ebx 
0x080483c1 <queue+62>: sub %eax,%ebx 
0x080483c3 <queue+64>: mov %ebx,-0x8(%ebp) 
0x080483c6 <queue+67>: mov -0x8(%ebp),%eax 
0x080483c9 <queue+70>: shl $0x2,%eax 
0x080483cc <queue+73>: add -0x8(%ebp),%eax 
0x080483cf <queue+76>: mov %ecx,%edx 
0x080483d1 <queue+78>: sub %eax,%edx 
0x080483d3 <queue+80>: mov %edx,-0x8(%ebp) 
0x080483d6 <queue+83>: mov -0x8(%ebp),%ebx 
0x080483d9 <queue+86>: mov %ebx,0x804963 

0x804963cはアイテムのアドレスですので、私はCコードの最初の行がどのように機能するかを見ることができます。また、0x8049634はテールのアドレスなので、キュー+ 33とキュー+ 38は%ecx = tail + 1と同じですが、後で何が起こっているのか分かりません。誰が簡単なモジュロがこのように複雑になると思ったでしょうか?

答えて

14

これは、より高価な除算命令を実行する必要を回避する方法です。私はこれに遭遇したときにもかなり困惑しました。楽しいことは、このトリックに使用されるマジックナンバー(この場合は0x66666667)を検索すると、このトリックを説明する結果が得られることが多いことです。 (私がソースを持っていなかったので、それが唯一の具体的なことだと私は信じています)

クイック検索で私にこのブログ記事を投稿しました:http://blog.dkbza.org/2007/09/reverse-engineering-compiler-produced.htmlこのトリックの紙への間接的なリンクを含む)。

関連する問題