-2

私は現在、アセンブラーに慣れようとしており、c++ で for ループを作成し、それを逆アセンブルで調べました。各ステップが何をするのか、および/またはループを手動で改善する方法を誰かが私に説明できるかどうか疑問に思っていました。

for (int i = 0; i < length; i++){
     013A17AE  mov         dword ptr [i],0  
     013A17B5  jmp         encrypt_chars+30h (13A17C0h)  
     013A17B7  mov         eax,dword ptr [i]  
     013A17BA  add         eax,1  
     013A17BD  mov         dword ptr [i],eax  
     013A17C0  mov         eax,dword ptr [i]  
     013A17C3  cmp         eax,dword ptr [length]  
     013A17C6  jge         encrypt_chars+6Bh (13A17FBh)  
temp_char = OChars [i];         // get next char from original string
     013A17C8  mov         eax,dword ptr [i]  
     013A17CB  mov         cl,byte ptr OChars (13AB138h)[eax]  
     013A17D1  mov         byte ptr [temp_char],cl  

前もって感謝します。

4

4 に答える 4

4

まず、投稿した内容にはループ本体の一部しか含まれていないようです。第二に、すべての最適化をオフにしてコンパイルしたように見えます。最適化をオンにした場合、結果がかなり異なって見えても驚かないでください。

それでは、コードを 1 行ずつ見てみましょう。

 013A17AE mov dword ptr [i],0

これは基本的にただのi=0.

 013A17B5 jmp encrypt_chars+30h (13A17C0h)

これはループの先頭に行きます。ほとんどの高水準言語ではループの先頭にテストを配置するのが一般的ですが、アセンブリ言語では常にそうとは限りません。

 013A17B7 mov eax,dword ptr [i]
 013A17BA add eax,1
 013A17BD mov dword ptr [i],eax

これはi++(非常に最適ではない)アセンブリ言語です。の現在の値を取得しi、それに 1 を追加してから、結果を に格納しiます。

 013A17C0 mov eax,dword ptr [i]
 013A17C3 cmp eax,dword ptr [length]
 013A17C6 jge encrypt_chars+6Bh (13A17FBh) 

これは基本的if (i==length) /* skip forward to some code you haven't shown */に の値を取得して の値iと比較し、が より大きいか等しいlength場合はどこかにジャンプします。ilength

これをアセンブリ言語で手で書いていた場合、通常はxor eax, eax(またはsub eax, eax) のようなものを使用してレジスタをゼロにします。ほとんどの場合、最大値から開始し、可能であればゼロまでカウントダウンします (ループでの比較を回避します)。確かに、値を変数に格納した後、すぐにそれを取得することはありません (公平に言えば、最適化をオンにすると、コンパイラもおそらくそれを行わないでしょう)。

それを適用し、「変数」をレジスタに移動すると、次の一般的な順序になります。

    mov ecx, length
loop_top:
    ; stuff that wasn't pasted goes here
    dec ecx
    jnz loop_top
于 2012-04-16T22:11:48.183 に答える
0

これを平易な英語で解釈してみます。

 013A17AE  mov         dword ptr [i],0               ; Move into i, 0
 013A17B5  jmp         encrypt_chars+30h (13A17C0h)  ; Jump to check
 013A17B7  mov         eax,dword ptr [i]             ; Load i into the accumulator (register eax)
 013A17BA  add         eax,1                         ; Increment the accumulator
 013A17BD  mov         dword ptr [i],eax             ; and put that in it, effectively adding
; 1 to i.
check:
 013A17C0  mov         eax,dword ptr [i]             ; Move i into the accumulator
 013A17C3  cmp         eax,dword ptr [length]        ; Compare it to the value in 'length',
; setting flags
 013A17C6  jge         encrypt_chars+6Bh (13A17FBh)  ; Jump if it's greater or equal. This
; address is not in your code snippet

コンパイラは演算に EAX を優先します。各レジスタ (過去に、これがまだ最新かどうかはわかりません) には、より高速に実行できる何らかのタイプの操作があります。

于 2012-04-16T22:16:11.627 に答える
0

より最適化する必要がある部分は次の
とおりです

mov eax,dword ptr [i]    ; Go get "i" from memory, put it in register EAX
add eax,1                ; Add one to register EAX
mov dword ptr [i],eax    ; Put register EAX back in memory "i". (now one bigger)
mov eax,dword ptr [i]    ; Go get "i" from memory, put it in EAX again.

メモリから EAX に値を前後に移動している頻度がわかりますか?

ループの開始時に "i" を EAX にロードし、EAX から直接完全なループを実行し、すべてが完了したら、完成した値を "i" に戻すことができるはずです。(コード内の他の何かがこれを妨げない限り)

于 2012-04-16T22:16:14.467 に答える
0

とにかく、このコードは DEBUG ビルドからのものです。最適化すること可能ですが、MS コンパイラはこのような単純なケースに対して非常に優れたコードを生成します。

手動で行う必要はありません。リリース モードで再ビルドし、リストを読んで方法を学習してください。

于 2012-04-16T22:23:19.560 に答える