2

整数配列の bubble_sort (前の質問を参照) を作成したところ、標準のスワップを無視して、次のようなアセンブリ スワップを実装することにしました。

int swap(int* x, int* y)
{
if(x != y)
  {
       _asm
      {
        mov eax,[x];
        mov ebx, [y];
        mov [y],eax;
        mov [x], ebx;
      }
    }
return 0;
}

結果のコードにそのまま挿入され、機能することを実際に確信していました。さて、このスワップを使用する私のコードは機能しますが、コンパイラがそれをどのように変換したかを調べたところ、私のスワップは次のように変更されました。

if(x != y)
00E01A6F  inc         ebp  
00E01A70  or          byte ptr [ebx],bh  
00E01A72  inc         ebp  
00E01A73  or          al,74h  
if(x != y)
00E01A75  or          al,8Bh  
  {
       _asm
      {
        mov eax,[x];
00E01A77  inc         ebp  
00E01A78  or          byte ptr [ebx+45890C5Dh],cl  
        mov [y],eax;
00E01A7E  or          al,89h  
        mov [x], ebx;
00E01A80  pop         ebp  
00E01A81  or          byte ptr [ebx],dh  
      }
   }
return 0;
00E01A83  rcr         byte ptr [edi+5Eh],5Bh  
}

MS VS 2012 でコンパイルしました。これらの余分な行は何を意味し、なぜそこにあるのでしょうか? _asm フラグメントをそのまま使用できないのはなぜですか?

4

3 に答える 3

4

その関数をどのようにコンパイルし、どのように逆アセンブルしたか教えていただけますか?

を使用してコンパイルすると

cl /FAsc -c test.c

インライン アセンブラー パーツのアセンブリ リストに次のように表示されます。

; 4    :   {
; 5    :        _asm
  0000a 53       push    ebx
; 6    :       {
; 7    :         mov eax,[x];
  0000b 8b 44 24 08  mov     eax, DWORD PTR _x$[esp]
; 8    :         mov ebx, [y];
  0000f 8b 5c 24 0c  mov     ebx, DWORD PTR _y$[esp]
; 9    :         mov [y],eax;
  00013 89 44 24 0c  mov     DWORD PTR _y$[esp], eax
; 10   :         mov [x], ebx;
  00017 89 5c 24 08  mov     DWORD PTR _x$[esp], ebx
; 4    :   {
; 5    :        _asm
  0001b 5b       pop     ebx
$LN4@swap:
; 11   :       }

注意すべきことの 1 つは、実際に交換したいものを交換していないことです。つまり、ポインターが参照する項目ではなく、関数に渡されたポインターを交換しています。したがって、関数が戻ると、スワップされたデータは破棄されます。この関数は、1 つの大きな問題にすぎません。

次のようなことを試してみてください:

   _asm
  {
    mov eax,[x];
    mov ebx,[y];

    mov ecx, [eax]
    mov edx, [ebx]

    mov [eax], edx
    mov [ebx], ecx
  }

しかし、率直に言って、C でスワップを実行すると、同様の (またはより優れた) コードになる可能性があります。

于 2012-09-01T23:31:57.097 に答える
3

最初と最後のバイトがありません。現在のコードを見ると、次のようになります。

inc ebp                    ; 45
or byte ptr [ebx],bh       ; 08 3B
inc ebp                    ; 45
or al,74h                  ; 0C 74
or al,8Bh                  ; 0C 8B
inc ebp                    ; 45
or byte ptr [ebx+45890C5Dh],cl ; 08 8B 5D 0C 89 45
or al,89h                  ; 0C 89
pop ebp                    ; 5B
or byte ptr [ebx],dh       ; 08 33
rcr byte ptr [edi+5Eh],5Bh ; C0 5F 5E 5B

最初の 2 バイトを無視すると、次のようになります。

  cmp eax, [ebp + 12] ; 3B 45 0C
  jz skip             ; 74 0C
  mov eax, [ebx + 8]  ; 8B 45 08
  mov ebx, [ebp + 12] ; 8B 5D 0C 
  mov [ebp + 12], eax ; 89 45 0C 
  mov [ebx + 8], ebx  ; 89 5B 08 
skip:
  xor eax, eax        ; 33 C0
  pop edi             ; 5F
  pop esi             ; 5E
  pop ebp             ; 5B

eax最後に ret がありません。決定的には、引数としてandを持つ命令があり[ebp + 8]ます (amovは意味があります)。最初のバイトが欠落しているため、逆アセンブリと命令ストリームの同期が取れていませんでした。

もちろん、プロローグもありません。

于 2012-09-02T14:58:04.010 に答える
0

main() の最後を見たい場合は、最初にプッシュして最後にポップする必要があります:)

 _asm
  {
    push eax     //back-up of registers
    push ebx
    mov eax,[x];
    mov ebx, [y];
    mov [y],eax;
    mov [x], ebx;
    pop ebx      //resume the registers where they were
    pop eax      // so, compiler can continue working normally
  }

コンパイラはそれらを他の目的にも使用するためです。

使用することもできましたxchg

mov eax,[x]
xchg   eax, [y]
mov   [x],eax

あなたは64ビットですか?次に、1 回の読み取り、1 回のスワップ、1 回の書き込みがあります。検索できます。

良い一日!

于 2012-09-01T23:17:52.233 に答える