从汇编看c++的虚拟继承以及其内存布局
作者: 发布时间:[ 2013/7/2 10:15:42 ] 推荐标签:
接下来是Bottom构造函数的汇编码:
??0Bottom@@QAE@HHHH@Z PROC ; Bottom::Bottom, COMDAT
; _this$ = ecx
; 28 : Bottom(int ll, int jj, int kk, int ii) : Top(ii), Left(jj, ii), Right(kk, ii) {
push ebp
mov ebp, esp
push ecx;压栈ecx的目的是为保存对象b的首地址预留空间
mov DWORD PTR _this$[ebp], ecx;ecx里面保存这对象b的首地址,存放到刚才空间
cmp DWORD PTR _$initVBases$[ebp], 0;_$initVBases所代表的内存里面的内容存放的是调用Bottom构造器时压入的标志,其值为1
;这里与0进行比较
je SHORT $LN1@Bottom;如果上面比较结果相等,跳到标号处$LN1@Bottom执行,否则顺序执行,这里是顺序执行
mov eax, DWORD PTR _this$[ebp];将对象b的首地址给寄存器eax
mov DWORD PTR [eax], OFFSET ??_8Bottom@@7BLeft@@@;将Bottom-Left的vtable首地址写入对象b首地址处内存
mov ecx, DWORD PTR _this$[ebp];将对象b的首地址给寄存器ecx
mov DWORD PTR [ecx+8], OFFSET ??_8Bottom@@7BRight@@@;将Bottom-Right的vtable首地址写入偏移对象b首地址8byte处
;即写入对象Right的首地址处内存
mov edx, DWORD PTR _ii$[ebp];将参数ii的值给寄存器edx
push edx;压栈寄存器edx,作为参数传递给虚基类的构造函数Top
mov ecx, DWORD PTR _this$[ebp];将对象b的首地址给寄存器ecx
add ecx, 20 ; 将对象b的首地址加上20,得到虚基类Top的首地址,存放到寄存器ecx,作为隐含参数传递给虚基类Top的构造函数
call ??0Top@@QAE@H@Z ; 调用虚基类Top的构造函数
$LN1@Bottom:;
push 0;标志0,说明已经调用过虚基类Top的构造函数,在调用Right和Left的构造函数时,不会再调用了。
mov eax, DWORD PTR _ii$[ebp];将参数ii的值给寄存器eax
push eax;压栈eax,给Left的构造函数传递参数
mov ecx, DWORD PTR _jj$[ebp];将参数jj的值给寄存器ecx
push ecx;压栈ecx,给Left的构造函数传递参数
mov ecx, DWORD PTR _this$[ebp];将对象b的首地址(也是对象Left的首地址)给寄存器ecx,作为隐含参数传递给Left构造函数
call ??0Left@@QAE@HH@Z ; 调用Left构造函数
push 0;压栈标志0,说明已经调用过虚基类Top的构造函数,在调用Right和Left的构造函数时,不会再调用了
mov edx, DWORD PTR _ii$[ebp];将参数ii的值给寄存器edx
push edx;压栈edx,给Right构造函数传递参数
mov eax, DWORD PTR _kk$[ebp];将参数kk的值给寄存器eax
push eax;压栈eax,给Right的构造函数传递参数
mov ecx, DWORD PTR _this$[ebp];将对象b的首地址给ecx
add ecx, 8;将对象b的首地址加上8,得到对象Right的首地址,存入寄存器ecx,作为隐含参数传递给Right构造函数
call ??0Right@@QAE@HH@Z ; 调用Right构造函数
; 29 : l = ll;
mov ecx, DWORD PTR _this$[ebp];将对象b的首地址给寄存器ecx
mov edx, DWORD PTR _ll$[ebp];将参数ll的值给寄存器edx
mov DWORD PTR [ecx+16], edx;将寄存器edx的内容写入偏移对象b首地址16byte处,即给对象b的成员变量l赋值
; 30 : }
mov eax, DWORD PTR _this$[ebp]
mov esp, ebp
pop ebp
ret 20 ; 00000014H
??0Bottom@@QAE@HHHH@Z ENDP
下面是Left构造函数的汇编码:
??0Left@@QAE@HH@Z PROC ; Left::Left, COMDAT
; _this$ = ecx
; 12 : Left(int jj, int ii) : Top(ii) {
push ebp
mov ebp, esp
push ecx;压栈ecx寄存器,是为保存对象Left的首地址预留空间
mov DWORD PTR _this$[ebp], ecx;寄存器ecx里面含有对象Left的首地址,存入刚才预留空间
cmp DWORD PTR _$initVBases$[ebp], 0;_$initVBases所代表的内存,里面含有调用Left构造函数传入的标志,其值为0
;这里是将它的值和0作比较
je SHORT $LN1@Left;如果上面比较相等,则跳转到标号$LN1@Left处执行,否则顺序执行,这里跳转到标号执行,因此不会调用
;虚基类Top的构造函数,避免重复调用
;标号之前的语句在构造对象b的时候都不会执行
mov eax, DWORD PTR _this$[ebp];将Left对象的首地址给eax寄存器
mov DWORD PTR [eax], OFFSET ??_8Left@@7B@;将??_8Left@@7B@所带表的内存地址(即Left的vtable首地址)写入对象Left的首地址处内存
;由于这一句在构造对象b时不执行,设置无效
mov ecx, DWORD PTR _ii$[ebp];将参数ii的值给寄存器ecx
push ecx;将ecx压栈,给虚基类Top构造函数传递参数,但是这一句在构造对象b时不执行,因此传参无效
mov ecx, DWORD PTR _this$[ebp];将对象Left的首地址给ecx寄存器
add ecx, 8;将Left的首地址加上8,得到Top对象的首地址,作为隐含参数传递给Top的构造函数
call ??0Top@@QAE@H@Z ; 调用Top的构造函数,但是在构造对象b时,这句不执行,因此调用无效
$LN1@Left:
; 13 : j = jj;
mov edx, DWORD PTR _this$[ebp];将对象Left的首地址给寄存器edx
mov eax, DWORD PTR _jj$[ebp];将参数jj给寄存器eax
mov DWORD PTR [edx+4], eax;将eax寄存器里面的内容写入偏移对象Left首地址4byte处内存,即给成员变量j赋值jj
; 14 : }
mov eax, DWORD PTR _this$[ebp]
mov esp, ebp
pop ebp
ret 12 ; 0000000cH
??0Left@@QAE@HH@Z ENDP
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11