ページ 11

アセンブリの読み方について

Posted: 2012年12月18日(火) 16:53
by 安藤
以前アセンブリについて投稿した者です。
前回の問題の類似問題を解いていたのですが、提出先に間違いだと突き返されてしまいましたのでまた質問させていただきます。

前回同様、<fff>と<main>を読めばわかるようで、かつmainは同じくscanfから入力した値を<fff>で処理してprintfで出力するものなのですが
fffの解釈が間違っていました。

コメント(私の考え)とコードを載せますので何がよろしくないのか教えていただきたいです。

コード:

00000000004004d8 <fff>:
  4004d8:       55                      push   %rbp
  4004d9:       48 89 e5                mov    %rsp,%rbp
  4004dc:       48 83 ec 08             sub    $0x8,%rsp
  4004e0:       89 7d fc                mov    %edi,0xfffffffffffffffc(%rbp) 入力値ediをrbpcに。
  4004e3:       83 7d fc 01             cmpl   $0x1,0xfffffffffffffffc(%rbp) 1とrbpcの値を比較。
  4004e7:       75 09                   jne    4004f2 <fff+0x1a> 1≠rbpcならジャンプ
  4004e9:       c7 45 f8 01 00 00 00    movl   $0x1,0xfffffffffffffff8(%rbp) 1をrbp8に。
  4004f0:       eb 14                   jmp    400506 <fff+0x2e> ジャンプ
  4004f2:       8b 7d fc                mov    0xfffffffffffffffc(%rbp),%edi rbpcの値をediに。
  4004f5:       83 ef 01                sub    $0x1,%edi ediから1を引く。
  4004f8:       e8 db ff ff ff          callq  4004d8 <fff> fffの再帰呼び出し。
  4004fd:       89 c2                   mov    %eax,%edx eaxをedxに。
  4004ff:       0f af 55 fc             imul   0xfffffffffffffffc(%rbp),%edx edxをrbpcで割り、その商をedxとする。
  400503:       89 55 f8                mov    %edx,0xfffffffffffffff8(%rbp) edxの値をrbp8に。
  400506:       8b 45 f8                mov    0xfffffffffffffff8(%rbp),%eax rbp8の値をeaxに。このeaxが戻り値になる。
  400509:       c9                      leaveq 
  40050a:       c3                      retq   

000000000040050b <main>:
  40050b:       55                      push   %rbp
  40050c:       48 89 e5                mov    %rsp,%rbp
  40050f:       48 83 ec 10             sub    $0x10,%rsp
  400513:       48 8d 75 fc             lea    0xfffffffffffffffc(%rbp),%rsi
  400517:       bf 48 06 40 00          mov    $0x400648,%edi
  40051c:       b8 00 00 00 00          mov    $0x0,%eax
  400521:       e8 ca fe ff ff          callq  4003f0 <scanf@plt>
  400526:       8b 7d fc                mov    0xfffffffffffffffc(%rbp),%edi
  400529:       e8 aa ff ff ff          callq  4004d8 <fff>
  40052e:       89 c6                   mov    %eax,%esi
  400530:       bf 4b 06 40 00          mov    $0x40064b,%edi
  400535:       b8 00 00 00 00          mov    $0x0,%eax
  40053a:       e8 91 fe ff ff          callq  4003d0 <printf@plt>
  40053f:       c9                      leaveq 
  400540:       c3                      retq   
  400541:       90                      nop    
  400542:       90                      nop    
  400543:       90                      nop    
  400544:       90                      nop    
  400545:       90                      nop    
  400546:       90                      nop    
  400547:       90                      nop    
  400548:       90                      nop    
  400549:       90                      nop    
  40054a:       90                      nop    
  40054b:       90                      nop    
  40054c:       90                      nop    
  40054d:       90                      nop    
  40054e:       90                      nop    
  40054f:       90                      nop    

以上から私の考えは以下のようになりました。
入力値と値1の差を、←(ここが怪しい
入力値で割り、その値を戻り値とする。

fffを再帰呼び出した後、最終的(再帰呼び出し終了時)にeaxに1が入るのはわかったのですがそれまでの過程でどうしたいのかわからなくなってしまいました。

なんとなくなのですが、素数や公約数が絡んでいる気がします。

以上です、回答よろしくお願いします。

Re: アセンブリの読み方について

Posted: 2012年12月18日(火) 21:43
by softya(ソフト屋)
imul が間違っています。英語の意味をよく考えましょう。
アセンブラ命令は大抵英単語を短縮した物なんですよ。

あとjmp 400506 <fff+0x2e> ジャンプは雑かなぁ。

Re: アセンブリの読み方について

Posted: 2012年12月18日(火) 23:34
by ISLe
前のスレから疑問に思ってたんですが、0xfffffffffffffffc(%rbp)をrbpcと表現するのはどういう意図があるのでしょうか。

0xfffffffffffffffc(%rbp)というのは-4(%rbp)のことで、rbpレジスタが示すアドレスの4番地前という意味です。
スタックフレームに関しては理解しなくても良いのでしょうか。

Re: アセンブリの読み方について

Posted: 2012年12月18日(火) 23:50
by 安藤
imulは×(かける)でした、すみません。

となると
14行目がedx×rbpcでその席をedxとする。
となりますので、大雑把に申し上げますと、
fffの一回の動作で入力値と1つ小さい値との掛け算を行っており、1つ小さい値とそれからさらに1小さい値との掛け算・・・を行って最終的に値が1になったらfffは終了するので、
このプログラムは入力値に対する階乗を求めるプログラムになると考えました。

意見をよろしくお願いします。

コード:

00000000004004d8 <fff>:
  4004d8:       55                      push   %rbp
  4004d9:       48 89 e5                mov    %rsp,%rbp
  4004dc:       48 83 ec 08             sub    $0x8,%rsp
  4004e0:       89 7d fc                mov    %edi,0xfffffffffffffffc(%rbp) 入力値ediをrbpcに。
  4004e3:       83 7d fc 01             cmpl   $0x1,0xfffffffffffffffc(%rbp) 1とrbpcの値を比較。
  4004e7:       75 09                   jne    4004f2 <fff+0x1a> 1≠rbpcならジャンプ
  4004e9:       c7 45 f8 01 00 00 00    movl   $0x1,0xfffffffffffffff8(%rbp) 1をrbp8に。
  4004f0:       eb 14                   jmp    400506 <fff+0x2e> 400506へジャンプ
  4004f2:       8b 7d fc                mov    0xfffffffffffffffc(%rbp),%edi rbpcの値をediに。
  4004f5:       83 ef 01                sub    $0x1,%edi ediから1を引く。
  4004f8:       e8 db ff ff ff          callq  4004d8 <fff> fffの再帰呼び出し。
  4004fd:       89 c2                   mov    %eax,%edx eaxをedxに。
  4004ff:       0f af 55 fc             imul   0xfffffffffffffffc(%rbp),%edx edx×rbpcでその積をedxとする。
  400503:       89 55 f8                mov    %edx,0xfffffffffffffff8(%rbp) edxの値をrbp8に。
  400506:       8b 45 f8                mov    0xfffffffffffffff8(%rbp),%eax rbp8の値をeaxに。このeaxが戻り値になる。
  400509:       c9                      leaveq 
  40050a:       c3                      retq   

000000000040050b <main>:
  40050b:       55                      push   %rbp
  40050c:       48 89 e5                mov    %rsp,%rbp
  40050f:       48 83 ec 10             sub    $0x10,%rsp
  400513:       48 8d 75 fc             lea    0xfffffffffffffffc(%rbp),%rsi
  400517:       bf 48 06 40 00          mov    $0x400648,%edi
  40051c:       b8 00 00 00 00          mov    $0x0,%eax
  400521:       e8 ca fe ff ff          callq  4003f0 <scanf@plt>
  400526:       8b 7d fc                mov    0xfffffffffffffffc(%rbp),%edi
  400529:       e8 aa ff ff ff          callq  4004d8 <fff>
  40052e:       89 c6                   mov    %eax,%esi
  400530:       bf 4b 06 40 00          mov    $0x40064b,%edi
  400535:       b8 00 00 00 00          mov    $0x0,%eax
  40053a:       e8 91 fe ff ff          callq  4003d0 <printf@plt>
  40053f:       c9                      leaveq 
  400540:       c3                      retq   
  400541:       90                      nop    
  400542:       90                      nop    
  400543:       90                      nop    
  400544:       90                      nop    
  400545:       90                      nop    
  400546:       90                      nop    
  400547:       90                      nop    
  400548:       90                      nop    
  400549:       90                      nop    
  40054a:       90                      nop    
  40054b:       90                      nop    
  40054c:       90                      nop    
  40054d:       90                      nop    
  40054e:       90                      nop    
  40054f:       90                      nop    


Re: アセンブリの読み方について

Posted: 2012年12月18日(火) 23:55
by softya(ソフト屋)
そういえば、rbpcは理解のための便宜上つけた名前ですので提出する時は、ちゃんと書かないとマズイでしょうね。
ISLeさんも書いている通りスタックフレームの動作として書かなくて大丈夫でしょうか? どこまで書けばOKなのか知っているのは安藤さんだけですよ。

【補足】
>このプログラムは入力値に対する階乗を求めるプログラムになると考えました。
それで合っていますが、
jmp 400506 <fff+0x2e> 400506へジャンプ
も雑ですね。もう少し意味を解説しても良いのでは?
ラベル名を付けるとしたら、 400506ってなんでしょうね?

Re: アセンブリの読み方について

Posted: 2012年12月19日(水) 00:25
by 安藤
rbpcは正しく書くと億劫でしたのでここにおいては省略させていただきました。

解答はプログラムが何をしているか、が記されていればOKでした。
スタックフレームについては言及されませんでした。
前回の問題でしたら
“フィボナッチ数列を表す処理をしている。
標準入力から読み込んだ整数値におけるフィボナッチ数を出力するが、入力値が1または2の場合は1を出力する。”
で大丈夫でした。

【補足】について
jmp 400506 <fff+0x2e> メモリアドレス400506へ移動する。

ここまで説明すればよろしいでしょうか。

Re: アセンブリの読み方について

Posted: 2012年12月19日(水) 00:31
by softya(ソフト屋)
> jmp 400506 <fff+0x2e> メモリアドレス400506へ移動する。
うーん。意味的なものを書けるようになると後々良いと思うんですよね。
400506から始まる処理はなんでしょうか?

実のところ
4004e9: c7 45 f8 01 00 00 00 movl $0x1,0xfffffffffffffff8(%rbp) 1をrbp8に。
4004f0: eb 14 jmp 400506 <fff+0x2e> 400506へジャンプ
はC言語では1つの命令なんですよね。

まぁ、今回の回答に関係無いですけどイメージできると格段にアセンブラを読む速度が上がると思います。

Re: アセンブリの読み方について

Posted: 2012年12月19日(水) 00:50
by 安藤
なるほど、移動した先の処理まで書くとよいのですね。
そしてCで書くと

コード:

int fff{
.
.
.
if(rbpc=1)
return rbp8(eax?);
.
.

}
のようになるということでしょうか。

※rbpc等は書き方を省略させていただきました。

Re: アセンブリの読み方について

Posted: 2012年12月19日(水) 01:00
by softya(ソフト屋)
完全にCで書くと
4004e9: c7 45 f8 01 00 00 00 movl $0x1,0xfffffffffffffff8(%rbp) 1をrbp8に。
4004f0: eb 14 jmp 400506 <fff+0x2e> 400506へジャンプ
は、return 1;です。rbp8は隠し変数ですのでC言語では表面に現れないでんです。

アセンブラのまま書くなら
4004e9: c7 45 f8 01 00 00 00 movl $0x1,0xfffffffffffffff8(%rbp) rbp8 = 1;
4004f0: eb 14 jmp 400506 <fff+0x2e> goto return_fff;
って感じでしょうか。

Re: アセンブリの読み方について

Posted: 2012年12月19日(水) 01:56
by 安藤
Cで書くとその1文で終わってしまうのですね。


ありがとうございます。
隠し変数の概念を含め、いろいろ勉強になりました。
また、わからなくなったら質問させてください。