当前位置: 首页 > news >正文

从汇编的角度了解C++原理——类的储存结构和函数调用

本文用到的反汇编工具是objconv,使用方法可以看我另一篇文章https://blog.csdn.net/weixin_45001971/article/details/128660642。

1、类的储存结构和函数调用

以这段代码为例。
在这里插入图片描述
编译后对obj文件反汇编,得到以下汇编代码,配合常量的值来分析汇编的含义。

main:
        sub     rsp, 72                                
        mov     dword [rsp+20H], 10    //栈顶偏移20个字节的位置定义为num变量
        lea     rcx, [rsp+28H]         //把rsp+28H的指针放入rcx寄存器               
        call    ??0A@@QEAA@XZ          //A类型的构造函数               
        mov     eax, 4294967295        //4294967295就是-1,eax寄存器用来存放返回值           
        add     rsp, 72                                
        ret                                           

??0A@@QEAA@XZ:; Function begin			//构造函数
        mov     qword [rsp+8H], rcx                 
        mov     rax, qword [rsp+8H]    //把rcx寄存器的值赋到rax寄存器             
        mov     dword [rax], 10        //定义rsp+28H的位置为d1变量             
        mov     rax, qword [rsp+8H]                   
        mov     byte [rax+4H], 20      //定义rsp+28H+4H的位置为d2变量               
        mov     rax, qword [rsp+8H]                   
        mov     dword [rax+8H], 30     //定义rsp+28H+8H的位置为d3变量                
        mov     rax, qword [rsp+8H]                    
        mov     byte [rax+0CH], 40     //定义rsp+28H+0CH的位置为d4变量                
        mov     rax, qword [rsp+8H]                   
        ret                                  
; ??0A@@QEAA@XZ End of function

从上面的例子可以看出以下几点。

第一点

类的函数执行过程分为以下两步:
1、把对象的地址放入rcx寄存器。
2、执行函数。
执行函数时,如果需要访问this指针,会先取rcx的值,作为this,然后再进一步操作。

第二点

类的储存结构遵循了4个字节的对齐原则,这跟我们在书本上的学的一样,d2变量虽然是char类型,只占一个字节,但d3和d2的首地址仍然相差4个字节,上述例子中A类的储存结构可以这样表示。
在这里插入图片描述
图画的不太好,简单示意一下。

除了前面说的之外,值得注意的是,struct和class以及private和public等写法在汇编代码里并没有体现出区别,所以这些关键字仅在编译阶段对语法的限制起作用。

验证

对例程做以下修改。
在这里插入图片描述
输出
在这里插入图片描述
与汇编里显示的一致。

2、子类的储存结构

修改代码如下:
在这里插入图片描述
反汇编得到。

main:
        sub     rsp, 72                     
        lea     rcx, [rsp+20H]       	//取this                 
        call    ??0B@@QEAA@XZ           //构造            
        lea     rcx, [rsp+20H]                       
        call    ?func1@A@@QEAAXXZ       //调用A类的func1    
        lea     rcx, [rsp+20H]                       
        call    ?func2@A@@QEAAXXZ       //调用A类的func2              
        mov     eax, 4294967295                        
        add     rsp, 72                                
        ret  
                                                  
??0A@@QEAA@XZ:; Function begin			//A类的构造函数
        mov     qword [rsp+8H], rcx                   
        mov     rax, qword [rsp+8H]                  
        mov     dword [rax], 10                 
        mov     rax, qword [rsp+8H]                    
        mov     byte [rax+4H], 20                      
        mov     rax, qword [rsp+8H]                    
        mov     dword [rax+8H], 30                     
        mov     rax, qword [rsp+8H]                    
        mov     byte [rax+0CH], 40                     
        mov     rax, qword [rsp+8H]                     
        ret                                             
        
??0B@@QEAA@XZ:							//B类的构造函数
        mov     qword [rsp+8H], rcx     //把this指针放在rsp+8H      
        sub     rsp, 40                 //函数压栈   rsp-40    
        mov     rcx, qword [rsp+30H]   	//rsp+30H等价rsp+48,也就是把this放入rcx            
        call    ??0A@@QEAA@XZ           //调用A类的构造函数          
        mov     rax, qword [rsp+30H]                   
        mov     dword [rax+10H], 50     //this指针往后偏移16字节的位置定义为d5               
        mov     rax, qword [rsp+30H]                  
        add     rsp, 40                 //出栈              
        ret                                           

?func1@A@@QEAAXXZ:; Function begin
        mov     qword [rsp+8H], rcx                    
        mov     rax, qword [rsp+8H]                 
        mov     dword [rax], 11                         
        ret  
                                                   
?func2@A@@QEAAXXZ:; Function begin
        mov     qword [rsp+8H], rcx                 
        mov     rax, qword [rsp+8H]                    
        mov     dword [rax], 12                        
        ret                                           

从示例中可以看到,子类中定义的成员,是拼接在父类成员的后面的,A类的大小是16,B类的成员d5被定义在this指针往后偏移16个字节的位置,如下图所示。
在这里插入图片描述
类里面的构造函数以及普通方法调用过程都是一样的,先把this指针存入rcx寄存器,然后执行函数的过程中从rcx寄存器取this指针。

相关文章:

  • 烟台网站建设学校/网站策划
  • wordpress 页面类型/企业线上培训课程
  • 企业网站建设报价/濮阳市网站建设
  • 网站建设补充协议模板/廊坊百度快照优化
  • 网站关键词推广优化/班级优化大师下载
  • 郑州营销网站托管公司/bt磁力猪
  • 双向bfs-字串变换
  • 软考报名有没有学历要求?2023年软考报名条件分享
  • linux下调节GPU的功率限制
  • 冥想第六百七十五天
  • 牛客竞赛每日俩题 - 动态规划4
  • python 列表生成式
  • MongoDB面试题整理-四年经验
  • 机器学习笔记之深度玻尔兹曼机(一)玻尔兹曼机系列整体介绍
  • 【Linux】探索缓冲区的概念 | Git 三板斧 | 实现简易进度条
  • JS语言基础
  • 详解分布式系统核心概念——CAP、CP和AP
  • 【JavaEE初阶】第二节.进程篇