2017-07-27 4 views
3

I解体Win32のC++プログラムを読んだと私はかなりの数を参照してください。コンパイラはこれらを生成する理由"AND AL、0xFF"の目的は何ですか?

AND AL,0xFF 

は、この完全に無意味ですか?ここで

は長い例です。

movsx eax, byte ptr [ebx] 
shl  eax, 18h 
movsx edx, byte ptr [ebx+1] 
shl  edx, 10h 
add  eax, edx 
movsx ecx, byte ptr [ebx+2] 
shl  ecx, 8 
add  eax, ecx 
movsx edx, byte ptr [ebx+3] 
add  eax, edx 
xor  edx, edx 
call sub_43B55C 
mov  ecx, eax 
mov  edx, eax 
sar  ecx, 10h 
and  al, 0FFh  # <---- 
sar  edx, 8 
and  cl, 0FFh  # <---- 
mov  [esi], cl 
and  dl, 0FFh  # <---- 
mov  [esi+1], dl 
mov  [esi+2], al 
add  ebx, 4 
add  esi, 3 
inc  ebp 
cmp  ebp, 6 
jl  short loc_43B5E4 

ことが目的ではないことができるようにフラグは、これらの操作の後にチェックされていません。 ANDの後には、AL,CLおよびDLの値が[ESI + n]に移動されています。

+2

前に何があったかわからなくても、言うことは難しいです。 EAXがポインタであり、16バイトの境界に整列させる必要があるとしましょう。これは、真の場合はZFを設定するので、命令へのポイントはフラグを設定することだけです。コンパイラの設定が適切であれば、 'test al、0xff'を使用することもできます。 –

+0

コメントありがとうございます。フラグはチェックされていません。 ANDingは、バイトがメモリに移動する前に発生しているようです。コンテキストの周囲のコードを更新しました。 – user35358

+3

本当に変わったようです。おそらく、この命令は、パディングのために、またはフックのマーカーとして存在します。 – fuz

答えて

4

@fuzが示唆しているように、これは単にオプティマイザがfoo & 0xffをノーオペレーションであると認識していないという欠陥です。

私は、プロジェクトのコンパイル設定を「Release」を設定した後、ボーランドC++ Builderの6で、次のコードスニペットをコンパイル:

unsigned char foobar(int foo) { return (foo >> 16) & 0xff; } 

は、この操作は、あなたが非常に密接に提供解体で行わ似ています。私たちは32ビットの値を持っています。これは与えられたビット数をシフトしてバイト値に変換し、基本的に元の値の16-23ビットを1バイトとして返します。 shrの代わりにsar命令を生成するために、入力パラメータはタイプintであり、おそらくintも元のコードで使用されています。あなたが見ることができるように

@foobar$qi PROC NEAR 
; COMDEF @foobar$qi 
     push ebp          ; 0000 _ 55 
     mov  ebp, esp        ; 0001 _ 8B. EC 
     mov  eax, dword ptr [ebp+8H]     ; 0003 _ 8B. 45, 08 
     sar  eax, 16         ; 0006 _ C1. F8, 10 
     and  al, 0FFFFFFFFH       ; 0009 _ 24, FF 
     pop  ebp          ; 000B _ 5D 
     ret            ; 000C _ C3 
@foobar$qi ENDP 

コンパイルと(私はC++ BuilderのIDE内からアセンブリリストを有効にする方法を見つけ出すことができなかったとして)objconvと結果の.objファイルを分解した後、私はこれを得ました、冗長andはまだそこにあります。命令コードでは、実際のコードストリームの即値が8ビットであることが明確に示されているため、逆アセンブルでは32ビットの即値は無視できます。

Microsoft Visual Studio C++ 6は同じことをしているようですが、32ビットレジスタ全体で動作します(したがって、32ビットの即値により3バイト多く生成されます)。 、関数の戻り値が明示的に8ビットであると宣言されたかを見て:

[email protected]@[email protected] PROC NEAR        ; foobar 
; 1 : unsigned char foobar(int foo) { return (foo >> 16) & 0xff; } 
    00000 55    push ebp 
    00001 8b ec   mov  ebp, esp 
    00003 8b 45 08   mov  eax, DWORD PTR _foo$[ebp] 
    00006 c1 f8 10   sar  eax, 16      ; 00000010H 
    00009 25 ff 00 00 00 and  eax, 255    ; 000000ffH 
    0000e 5d    pop  ebp 
    0000f c3    ret  0 
[email protected]@[email protected] ENDP         ; foobar 

はまた、the oldest version of gcc available on godboltは正しく、本質的に呼び出し規則によるリストの間で自然な違いを除いてちょうどシフト、何にこれをコンパイルします。

関連する問題