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   :       }

需要注意的一件事是,您并没有交换您真正想要交换的内容 - 您交换的是传递给函数的指针,而不是指针所指的项目。因此,当函数返回时,交换的数据将被丢弃。该功能只是一个大问题。

您可能想尝试类似的东西:

   _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

如果你忽略前两个字节,你会得到:

  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

它最后缺少 ret ,而且,至关重要的是,一些指令具有eax[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位的?然后是单读、单交换、单写。你可以搜索一下。

再会!

于 2012-09-01T23:17:52.233 回答