问题描述:

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都是被调用者自己恢复栈。但是两者的区别在于,前者使用到一个寄存器来传递对象的首地址,而非通过栈传递的方式。

__thiscalll C++底层识别成员函数的更多相关文章

  1. C++反汇编第一讲,认识构造函数,析构函数,以及成员函数

    C++反汇编第一讲,认识构造函数,析构函数,以及成员函数 以前说过在C系列下的汇编,怎么认识函数.那么现在是C++了,隐含有构造和析构函数 一丶认识构造函数 高级代码: class MyTest { ...

  2. 成员函数指针与高性能C++委托

    1 引子 标准C++中没有真正的面向对象的函数指针.这一点对C++来说是不幸的,因为面向对象的指针(也叫做“闭包(closure)”或“委托(delegate)”)在一些语言中已经证明了它宝贵的价值. ...

  3. [转]成员函数指针与高性能的C++委托

    原文(作者:Don Clugston):Member Function Pointers and the Fastest Possible C++ Delegates 译文(作者:周翔): 成员函数指 ...

  4. 理解ATL中的一些汇编代码(通过Thunk技术来调用类成员函数)

    我们知道ATL(活动模板库)是一套很小巧高效的COM开发库,它本身的核心文件其实没几个,COM相关的(主要是atlbase.h, atlcom.h),另外还有一个窗口相关的(atlwin.h), 所以 ...

  5. C++ 对象成员函数(非静态方法)

    1.神奇的inline语法与语义 inline语义C99和C++98都有.之前在单源文件编写的时候一直没有发现问题,但是一考虑到多文件的链接,就发现矛盾了. 一些inline的原则: 1. inlin ...

  6. C++类成员函数

    c++的两大特色是多态和模板.其中多态是通过继承和虚函数来实现的,其中虚函数是通过每个对象里面的虚表来实现的.如果这个对象的类有虚函数,那么这个类就有一张虚表,存的是每个虚函数的入口地址,而这个类的每 ...

  7. 成员函数指针与高效C++委托 (delegate)

    下载实例源代码 - 18.5 Kb 下载开发包库文件 - 18.6 Kb 概要 很遗憾, C++ 标准中没能提供面向对象的函数指针. 面向对象的函数指针也被称为闭包(closures) 或委托(del ...

  8. 【OOP】C++ const成员函数

    预备知识 1.代码转换分析技巧 在早期某些编译器会将C++代码翻译为C代码,然后使用C编译器生成可执行文件.其中翻译的一个转化就是:将this指针显式添加到成员函数的第一个参数位置上,并在成员函数调用 ...

  9. C++模板编程中只特化模板类的一个成员函数

    模板编程中如果要特化或偏特化(局部特化)一个类模板,需要特化该类模板的所有成员函数.类模板中大多数成员函数的功能可能是一模一样的,特化时我们可能只需要重新实现1.2个成员函数即可.在这种情况下,如果全 ...

随机推荐

  1. thinkphp URL 模式

    兼容ThinkPHP三种url模式的nginx rewrite location / { root /var/www; index index.html index.htm index.php; if ...

  2. spring配置hibernate映射文件-------通配符

    <!-- 这里一定要注意是使用spring的mappingLocations属性进行通配的 -->      <property name="mappingLocation ...

  3. ActiveMQ部署和503的错误

    最近部署ActiveMQ的时候,发现有的服务器可以打开后台管理网址,有的服务器无法打开,Jetty报503 Service Unavailable. 搞了很久终于发现了问题,现将部署和解决过程做笔记如 ...

  4. AJAX跨域资源共享 CORS 详解

    CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing). 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从 ...

  5. org.apache.flume.ChannelException: Take list for MemoryTransaction, capacity 100 full, consider committing more frequently, increasing capacity, or increasing thread count

    flume在抽取MySQL数据到kafka时报错,如下 [SinkRunner-PollingRunner-DefaultSinkProcessor] ERROR org.apache.flume.s ...

  6. HBase协处理器的使用(添加Solr二级索引)

    给HBase添加一二级索引,HBase协处理器结合solr 代码如下 package com.hbase.coprocessor; import java.io.IOException; import ...

  7. SpringBoot-新建项目

    在开发SpringBoot之前,先下载STS开发工具,当然也可以用myeclipse等工具. STS官方下载地址:https://spring.io/tools/sts 下载安装完成后:File--& ...

  8. Valid Parentheses有效括号匹配。利用栈。

    问题描述:给定一个字符串,其中只包含字符‘{’,    '}',    '[',    ']',   '(',    ')'确定如果输入字符串是有效的.括号必须以正确的顺序排列,“()”和“()[]{ ...

  9. Java 创建线程的两种方法

    Java提供了线程类Thread来创建多线程的程序.其实,创建线程与创建普通的类的对象的操作是一样的,而线程就是Thread类或其子类的实例对象.每个Thread对象描述了一个单独的线程.要产生一个线 ...

  10. Delphi_检查exe文件是否是"随机基址"

    ZC: cnpack 还是蛮好用的 1.代码: procedure TForm1.btnRandomizedBaseAddressClick(Sender: TObject); var pDosHdr ...