【问题标题】:Wrong Visual Studio assembly output?错误的 Visual Studio 程序集输出?
【发布时间】:2017-09-19 17:50:24
【问题描述】:

这个经典函数是我写的:(在32位模式下)

void ex(size_t a, size_t b)
{
    size_t c;
    c = a;
    a = b;
    b = c;
}

我在main里面这样称呼它:

size_t a = 4;
size_t b = 5;
ex(a,b);

我对输入函数时生成的汇编代码的期望是这样的:

1-将 b 和 a 的值压入堆栈:(已完成)

mov         eax,dword ptr [b]
push        eax
mov         ecx,dword ptr [a]
push        ecx

2-使用堆栈中a和b的值:

push        ebp
mov         ebp, esp
sub         esp, 4
    c = a;
mov         eax, dword ptr [ebp+8]
mov         dword ptr [ebp-4], eax

其他变量依此类推。

但是,这是我在调试时发现的:

push        ebp  
mov         ebp,esp  
sub         esp,0CCh  // normal since it's in debug with ZI option
push        ebx  
push        esi  
push        edi  
lea         edi,[ebp-0CCh]  
mov         ecx,33h  
mov         eax,0CCCCCCCCh  
rep stos    dword ptr es:[edi]  
    size_t c;
    c = a;
mov         eax,dword ptr [a]  
mov         dword ptr [c],eax  

为什么直接使用变量a而不是调用栈中存储的值呢?没看懂……

【问题讨论】:

  • 无法调用存储在堆栈中的整数。仅调用函数。您需要使用其他动词。
  • 你的函数是荒谬的,所以你真的可以期待任何荒谬的事情发生。您正在操作一些局部变量,然后在没有返回值且没有任何副作用的情况下返回。我敢打赌,在非调试版本中,您的函数将被编译为空。
  • 我很惊讶由于函数没有执行任何操作而生成了任何代码。
  • 编译器只是使用a 作为ebp+8 的别名和c 作为ebp-4 的别名。如果生成的汇编代码确实可以编译,那么这些别名是在某处定义的。如果不是,那么ac 仅供参考。
  • @Mike Nakis 实际上,这是我参加的课程中的一个示例,该示例显示了按值传递参数和按地址传递参数之间的区别。

标签: c visual-studio assembly


【解决方案1】:

调试器不显示使用ebp 访问a 的指令。编写内联汇编时允许使用相同的语法。否则还是会出现dword ptr的原因。

很容易获得您喜欢的方式,右键单击>取消选中“显示符号名称”。

【讨论】:

  • 哦,我现在明白了。谢谢你的回答!
【解决方案2】:

使用程序集输出选项(右键单击文件名、属性...),我可以从调试程序集输出中得到您所期望的。这可能取决于您使用的 VS 版本。对于这个例子,我使用了 VS2005。我在不同的系统上安装了 VS2015,但还没有尝试过。

_c$ = -8                                ; size = 4
_a$ = 8                                 ; size = 4
_b$ = 12                                ; size = 4
_ex     PROC                            ; COMDAT
        push    ebp
        mov     ebp, esp
        sub     esp, 204                ; 000000ccH
        push    ebx
        push    esi
        push    edi
        lea     edi, DWORD PTR [ebp-204]
        mov     ecx, 51                 ; 00000033H
        mov     eax, -858993460         ; ccccccccH
        rep stosd                       ;fill with 0cccccccch
        mov     eax, DWORD PTR _a$[ebp]
        mov     DWORD PTR _c$[ebp], eax
        mov     eax, DWORD PTR _b$[ebp]
        mov     DWORD PTR _a$[ebp], eax
        mov     eax, DWORD PTR _c$[ebp]
        mov     DWORD PTR _b$[ebp], eax
        pop     edi
        pop     esi
        pop     ebx
        mov     esp, ebp
        pop     ebp
        ret     0
_ex     ENDP

请注意,这不起作用,您需要使用指针才能进行交换。

void ex(size_t *pa, size_t *pb)
{
    size_t c;
      c = *pa;
    *pa = *pb;
    *pb = c;
}

翻译成:

_c$ = -8                                ; size = 4
_pa$ = 8                                ; size = 4
_pb$ = 12                               ; size = 4
_ex     PROC                            ; COMDAT
        push    ebp
        mov     ebp, esp
        sub     esp, 204                ; 000000ccH
        push    ebx
        push    esi
        push    edi
        lea     edi, DWORD PTR [ebp-204]
        mov     ecx, 51                 ; 00000033H
        mov     eax, -858993460         ; ccccccccH
        rep stosd
        mov     eax, DWORD PTR _pa$[ebp]
        mov     ecx, DWORD PTR [eax]
        mov     DWORD PTR _c$[ebp], ecx
        mov     eax, DWORD PTR _pa$[ebp]
        mov     ecx, DWORD PTR _pb$[ebp]
        mov     edx, DWORD PTR [ecx]
        mov     DWORD PTR [eax], edx
        mov     eax, DWORD PTR _pb$[ebp]
        mov     ecx, DWORD PTR _c$[ebp]
        mov     DWORD PTR [eax], ecx
        pop     edi
        pop     esi
        pop     ebx
        mov     esp, ebp
        pop     ebp
        ret     0
_ex     ENDP

【讨论】:

  • 感谢您的洞察力。正如 Hans Passant 在他的回答中所说,这是因为我勾选了“显示符号名称”选项,这导致 Visual Studio 将 EBP+8 替换为符号 a。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-03
  • 1970-01-01
  • 1970-01-01
  • 2021-10-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多