本文用到的反汇编工具是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指针。


















