__thiscalll C++底层识别成员函数
2024-08-27 08:18:45
问题描述:
class myClass {
public:
void SetNumber(int nNumber) {
m_nInt = nNumber;
}
private:
int m_nInt;
}; int main(int argc, char* argv[],int _version)
{
myClass Test;
Test.SetNumber(5);
return 0;
}
上述代码中,SetNumber是如何识别得出来m_nInt是类的成员变量???
分析:
main函数反汇编:
;省略进入main函数的部分汇编代码
push 5
lea ecx, [ebp+var_4] ;此处的[ebp+var_4]指的是Test对象的首地址
call j_myClass__SetNumber
;省略调用Set_Number之后的汇编代码
从上述汇编代码可以看得出来,在main函数调用成员函数SetNumber之前,编译器先将实参5压栈,然后将Test对象的首地址保持到寄存器ecx中,最后直接调用成员SetNumber。从汇编代码中,还可以看出SetNumber的函数名是经过了修改的。
SetNumber函数反汇编:
var_44= dword ptr -44h
var_4= dword ptr -4
arg_0= dword ptr 8 ;参数的地址 ;下面是进入函数后,将上一层的调用者的信息保持,压栈。
push ebp
mov ebp, esp
sub esp, 44h
push ebx
push esi
push edi
push ecx
lea edi, [ebp+var_44]
mov ecx, 11h
mov eax, 0CCCCCCCCh
rep stosd
pop ecx ;恢复ecx,this指针。
mov [ebp+var_4], ecx
mov eax, [ebp+var_4]
mov ecx, [ebp+arg_0]
mov [eax], ecx ;赋值,m_nInt=nNumber
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
retn 4 ;被调用者自己恢复栈
myClass__SetNumber endp
从上述的反汇编代码可以看出,在底层成员函数和普通函数是没有区别的。我们所看到的类和对象的概念是编译器提供的,也就是说在调用成员函数的时候,编译器做了一些“小动作”:利用寄存器ecx来保持对象的首地址(即this指针),并以寄存器传参的方式传递给成员函数,这种调用被称为__thiscall。(注意:并不是所有的成员函数调用都是通过ecx来实现的,得看具体的编译器)
__thiscall和__stdcall都是被调用者自己恢复栈。但是两者的区别在于,前者使用到一个寄存器来传递对象的首地址,而非通过栈传递的方式。
最新文章
- PHP实现队列及队列原理
- 数据库表映射到MyEclipse的实体对象
- linux基础-第十七单元 Samba服务
- VS无法启动调试:“生成下面的模块时,启用了优化或没有调试信息“
- Linux下rz命令使用的实例详解
- jenkins插件 build timeout和build timestamp
- 实验12:Problem I: 成绩排序
- 在生产环境使用Docker部署应用
- linux更新系统之后,删除多余的开机启动项
- SPOJ #691. Hotel Floors
- PayPal 开发详解(一):注册PayPal帐号
- USACO Section 2.4: Fractions to Decimals
- [codility]Grocery-store
- 简单的SqlHelper
- linux安装redis-3.0.7
- [AH/HNOI2017]大佬
- 利用AOP实现SqlSugar自动事务
- iOS ----------NSDate 、CFAbsoluteTimeGetCurrent、CACurrentMediaTime 的区别
- Python之历史
- PAT 1057 数零壹