'dword ptr[this]' 在 C++ 代码的 VS 反汇编中意味着什么?

What does 'dword ptr[this]' mean in VS disassembly of C++ code?

在调用对象的成员函数之前,对象的地址会被移动到ECX。

函数内部,ECX会被移动到dword ptr [this],什么意思?

C++ 源代码

#include <iostream>

class CAdd 
{
public:
    CAdd(int x, int y) : _x(x), _y(y) {}
    int Do() { return _x + _y; }

private:
    int _x;
    int _y;

};

int main()
{
    CAdd ca(1, 2);
    int n = ca.Do();
    std::cout << n << std::endl;
}

反汇编

...
    CAdd ca(1, 2);
00A87B4F  push        2  
00A87B51  push        1  
00A87B53  lea         ecx,[ca]  ; the instance address
00A87B56  call        CAdd::CAdd (0A6BA32h)  

    int Do() { return _x + _y; }
00A7FFB0  push        ebp  
00A7FFB1  mov         ebp,esp  
00A7FFB3  sub         esp,0CCh  
00A7FFB9  push        ebx  
00A7FFBA  push        esi  
00A7FFBB  push        edi  
00A7FFBC  push        ecx  
00A7FFBD  lea         edi,[ebp-0Ch]  
00A7FFC0  mov         ecx,3  
00A7FFC5  mov         eax,0CCCCCCCCh  
00A7FFCA  rep stos    dword ptr es:[edi]  
00A7FFCC  pop         ecx  
00A7FFCD  mov         dword ptr [this],ecx     ; ========= QUESTION HERE!!! =========
00A7FFD0  mov         ecx,offset _CC7F790E_main@cpp (0BC51F2h)  
00A7FFD5  call        @__CheckForDebuggerJustMyCode@4 (0A6AC36h)  
00A7FFDA  mov         eax,dword ptr [this]     ; ========= AND HERE!!! =========
00A7FFDD  mov         eax,dword ptr [eax]  
00A7FFDF  mov         ecx,dword ptr [this]  
00A7FFE2  add         eax,dword ptr [ecx+4]  
00A7FFE5  pop         edi  
00A7FFE6  pop         esi  
00A7FFE7  pop         ebx  
00A7FFE8  add         esp,0CCh  
00A7FFEE  cmp         ebp,esp  
00A7FFF0  call        __RTC_CheckEsp (0A69561h)  
00A7FFF5  mov         esp,ebp  
00A7FFF7  pop         ebp  
00A7FFF8  ret  

MSVC 的 asm 输出本身 (https://godbolt.org/z/h44rW3Mxh) uses _this$[ebp] with _this$ = -4, in a debug build like this which wastes instructions storing/reloading incoming register args.

_this$ = -4
int CAdd::Do(void) PROC                             ; CAdd::Do, COMDAT
        push    ebp
        mov     ebp, esp
        push    ecx                ; dummy push instead of sub to reserve 4 bytes
        mov     DWORD PTR _this$[ebp], ecx
        mov     eax, DWORD PTR _this$[ebp]
  ...

这只是将寄存器 arg 溢出到堆栈上具有该名称的局部变量。 (我在 Godbolt 上使用的 MSVC 版本的默认选项,x86 MSVC 19.29.30136,不包括 __CheckForDebuggerJustMyCode@4Do() 中的运行时检查堆栈中毒(rep stos),但是this 的用法仍然存在。)

有趣的是,push ecx 它使用 () 而不是 sub esp, 4 来保留堆栈 space 已经存储的 ECX,使 mov 存储冗余.

(AFAIK,实际上没有编译器使用 push 为本地人初始化和生成 space,但这将是对这种情况的优化:。它只是使用 push 对 ESP 的影响,而不关心它存储的内容,即使您启用了优化。在一个函数中它仍然需要溢出它,而不是将它保存在内存中。)


您的反汇编程序显然将帧指针 (EBP +) 折叠成它定义的 this 符号/宏, 如果您不必四处查看其他行来了解它是如何定义该文本宏或它是什么的。

你用的是什么反汇编器? Visual Studio 的调试器内置的那个?

我猜它以这种方式使用 C 局部变量名是有道理的,尽管对于熟悉 asm 的人来说它看起来超级奇怪。 (因为只有静态存储可以使用 [symbol] 不涉及任何寄存器的模式寻址。)