_asm 交换和编译器添加

问题描述 投票:0回答:3

我刚刚编写了一个整数数组的 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 片段不能使用?

c++ assembly x86
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 中执行交换可能会产生类似(或更好)的代码。


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]
作为参数的指令(
mov
在那里是有意义的)。丢失的第一个字节使反汇编与指令流不同步。

当然,它也缺少序言。


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位的吗?然后是单次读取、单次交换、单次写入。你可以搜索一下。

美好的一天!

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.