【发布时间】: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