【问题标题】:What does 'dword ptr[this]' mean in VS disassembly of C++ code?VS 反汇编 C++ 代码中的“dword ptr[this]”是什么意思?
【发布时间】:2021-12-23 15:25:36
【问题描述】:

在调用对象的成员函数之前,对象的地址会被移动到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  

【问题讨论】:

  • 您是通过成员函数将类的第一个元素指定为指向自身,还是您写错了?
  • 请编辑您的问题以包含函数的源代码、类声明以及编译器的实际 asm 输出。 (最好剥离到minimal reproducible example,尽可能少的成员和成员函数来演示这种行为,最好还包括godbolt.org上的源+asm的链接)这可能只是一个调试构建的东西如果 this 被定义为 ebp-4 的宏或其他内容,则将寄存器 args 溢出到堆栈中。
  • 你用的是什么反汇编程序?正如我所料,MSVC 的 asm 输出本身 (godbolt.org/z/h44rW3Mxh) 使用 _this$ = -4 / mov DWORD PTR _this$[ebp], ecx,只是将寄存器 arg 溢出到具有该名称的堆栈上的本地。您的反汇编程序显然将帧指针折叠成它定义为this 符号/宏的内容。 (我在 Godbolt 上使用的 MSVC 版本的默认选项,x86 MSVC 19.29.30136,在Do() 中不包括__CheckForDebuggerJustMyCode@4 或运行时检查堆栈中毒(rep stos),但使用this还在。)
  • @PeterCordes 明白了!您能否介意发表您的评论作为答案,以便我选择它! :)

标签: visual-studio assembly visual-c++ x86 disassembly


【解决方案1】:

MSVC 的 asm 输出本身 (https://godbolt.org/z/h44rW3Mxh) 在 wastes instructions storing/reloading incoming register args 这样的调试版本中使用 _this$[ebp]_this$ = -4

_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,在Do() 中不包括__CheckForDebuggerJustMyCode@4 或运行时检查堆栈中毒(rep stos),而是使用this还在。)

有趣的是,push ecx 它使用 (as a micro-optimization) 而不是 sub esp, 4 来保留已存储 ECX 的堆栈空间,从而使 mov 存储变得多余。

(AFAIK,实际上没有编译器确实使用push 来初始化本地变量并为本地变量腾出空间,但对于像这样的情况,这将是一种优化:What C/C++ compiler can use push pop instructions for creating local variables, instead of just increasing esp once?。它只是使用push 对 ESP 的影响,而不关心它存储的内容,即使您启用了优化。在确实需要溢出它的函数中,而不是将其保存在内存中。)


您的反汇编程序显然将帧指针 (EBP +) 折叠成其定义为 this 符号/宏的内容,如果您不环顾其他行,则会更加混乱找出它是如何定义该文本宏或它是什么的。

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

我猜想以这种方式使用 C 本地 var 名称是有道理的,尽管对于熟悉 asm 的人来说它看起来非常奇怪。 (因为只有静态存储可以使用[symbol] 之类的模式寻址,而不涉及任何寄存器。)

【讨论】:

    猜你喜欢
    • 2013-03-05
    • 2014-03-02
    • 2021-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多