把函数体同调用相联系成为捆绑。但捆绑在运行前发生成为早捆绑。晚捆绑又称为动态捆绑或运行时捆绑。
c++代码为: class base { int i; public: virtual void print() { } }; class derived : public base { int j; public: void print() { }
virtual void print_another() { } };
int main() { base* b = new derived; b->print(); return 0; }
生成的汇编代码为:
TITLE D:\code\th_in_c++\pvdest\pvdest.cpp .386P include listing.inc if @Version gt 510 .model FLAT else _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS _DATA SEGMENT DWORD USE32 PUBLIC 'DATA' _DATA ENDS CONST SEGMENT DWORD USE32 PUBLIC 'CONST' CONST ENDS _BSS SEGMENT DWORD USE32 PUBLIC 'BSS' _BSS ENDS $$SYMBOLS SEGMENT BYTE USE32 'DEBSYM' $$SYMBOLS ENDS $$TYPES SEGMENT BYTE USE32 'DEBTYP' $$TYPES ENDS _TLS SEGMENT DWORD USE32 PUBLIC 'TLS' _TLS ENDS ; COMDAT ?print@base@@UAEXXZ _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS ; COMDAT ?print@derived@@UAEXXZ _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS ; COMDAT ?print_another@derived@@UAEXXZ _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS ; COMDAT _main _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS ; COMDAT ??0derived@@QAE@XZ _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS ; COMDAT ??0base@@QAE@XZ _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS ; COMDAT ??_7base@@6B@ CONST SEGMENT DWORD USE32 PUBLIC 'CONST' CONST ENDS ; COMDAT ??_7derived@@6B@ CONST SEGMENT DWORD USE32 PUBLIC 'CONST' CONST ENDS FLAT GROUP _DATA, CONST, _BSS ASSUME CS: FLAT, DS: FLAT, SS: FLAT endif PUBLIC ??0derived@@QAE@XZ ; derived::derived PUBLIC _main EXTRN ??2@YAPAXI@Z:NEAR ; operator new EXTRN ??3@YAXPAX@Z:NEAR ; operator delete EXTRN __chkesp:NEAR EXTRN __except_list:DWORD EXTRN ___CxxFrameHandler:NEAR ; COMDAT xdata$x ; File D:\code\th_in_c++\pvdest\pvdest.cpp xdata$x SEGMENT __ehfuncinfo$_main DD 019930520H DD 01H DD FLAT:__unwindtable$_main DD 2 DUP(00H) DD 2 DUP(00H) ORG $+4 __unwindtable$_main DD 0ffffffffH DD FLAT:__unwindfunclet$_main xdata$x ENDS ; COMDAT _main _TEXT SEGMENT _b$ = -16 $T270 = -20 $T271 = -24 __$EHRec$ = -12 _main PROC NEAR ; COMDAT ; File D:\code\th_in_c++\pvdest\pvdest.cpp ; Line 22 push ebp mov ebp, esp push -1 push __ehhandler$_main mov eax, DWORD PTR fs:__except_list push eax mov DWORD PTR fs:__except_list, esp sub esp, 80 ; 00000050H push ebx push esi push edi lea edi, DWORD PTR [ebp-92] mov ecx, 20 ; 00000014H mov eax, -858993460 ; ccccccccH rep stosd ; Line 23 push 12 ; 0000000cH call ??2@YAPAXI@Z ; operator new add esp, 4 mov DWORD PTR $T271[ebp], eax mov DWORD PTR __$EHRec$[ebp+8], 0 cmp DWORD PTR $T271[ebp], 0 je SHORT $L272 mov ecx, DWORD PTR $T271[ebp] //通过ecs将分配给derived对象b的地址传给构造函数 call ??0derived@@QAE@XZ ; derived::derived //调用构造函数 mov DWORD PTR -28+[ebp], eax //保存对象b的_this指针 jmp SHORT $L273 $L272: mov DWORD PTR -28+[ebp], 0 $L273: mov eax, DWORD PTR -28+[ebp] //将对象b的_this指针取到EAX mov DWORD PTR $T270[ebp], eax //将EAX保存到$T270[ebp]中 mov DWORD PTR __$EHRec$[ebp+8], -1 mov ecx, DWORD PTR $T270[ebp] //_this指针取到ecs mov DWORD PTR _b$[ebp], ecx //保存到_b$[ebp}内 ; Line 24 mov edx, DWORD PTR _b$[ebp] //_this指针取到edx; mov eax, DWORD PTR [edx] //该对象中存放的第一个数据vftable的地址取到eax mov esi, esp //? mov ecx, DWORD PTR _b$[ebp] //传递_this指针 call DWORD PTR [eax] //通过vftable中存放的print函数的地址调用print cmp esi, esp //? call __chkesp //? ; Line 25 xor eax, eax ; Line 26 mov ecx, DWORD PTR __$EHRec$[ebp] mov DWORD PTR fs:__except_list, ecx pop edi pop esi pop ebx add esp, 92 ; 0000005cH cmp ebp, esp call __chkesp mov esp, ebp pop ebp ret 0 _TEXT ENDS ; COMDAT text$x text$x SEGMENT __unwindfunclet$_main: mov eax, DWORD PTR $T271[ebp] push eax call ??3@YAXPAX@Z ; operator delete pop ecx ret 0 __ehhandler$_main: mov eax, OFFSET FLAT:__ehfuncinfo$_main jmp ___CxxFrameHandler text$x ENDS _main ENDP PUBLIC ??0base@@QAE@XZ ; base::base PUBLIC ?print@derived@@UAEXXZ ; derived::print PUBLIC ?print_another@derived@@UAEXXZ ; derived::print_another PUBLIC ??_7derived@@6B@ ; derived::`vftable' ; COMDAT ??_7derived@@6B@ CONST SEGMENT ??_7derived@@6B@ DD FLAT:?print@derived@@UAEXXZ ; derived::`vftable' DD FLAT:?print_another@derived@@UAEXXZ CONST ENDS ; COMDAT ??0derived@@QAE@XZ _TEXT SEGMENT _this$ = -4 ??0derived@@QAE@XZ PROC NEAR ; derived::derived, COMDAT push ebp mov ebp, esp sub esp, 68 ; 00000044H push ebx push esi push edi push ecx lea edi, DWORD PTR [ebp-68] mov ecx, 17 ; 00000011H mov eax, -858993460 ; ccccccccH rep stosd pop ecx mov DWORD PTR _this$[ebp], ecx //对象存储区域的开始位置通过ecs传给_this指针 mov ecx, DWORD PTR _this$[ebp] //传递_this指针 call ??0base@@QAE@XZ ; base::base //调用base的构造函数进行初始化 mov eax, DWORD PTR _this$[ebp] mov DWORD PTR [eax], OFFSET FLAT:??_7derived@@6B@ ; derived::`vftable' //_this指针指向的空间的第一块存储区存放derived的vftable mov eax, DWORD PTR _this$[ebp] //通过eax将_this指针返回 pop edi pop esi pop ebx add esp, 68 ; 00000044H cmp ebp, esp call __chkesp mov esp, ebp pop ebp ret 0 ??0derived@@QAE@XZ ENDP ; derived::derived _TEXT ENDS ; COMDAT ?print@derived@@UAEXXZ _TEXT SEGMENT _this$ = -4 ?print@derived@@UAEXXZ PROC NEAR ; derived::print, COMDAT ; Line 14 push ebp mov ebp, esp sub esp, 68 ; 00000044H push ebx push esi push edi push ecx lea edi, DWORD PTR [ebp-68] mov ecx, 17 ; 00000011H mov eax, -858993460 ; ccccccccH rep stosd pop ecx mov DWORD PTR _this$[ebp], ecx ; Line 15 pop edi pop esi pop ebx mov esp, ebp pop ebp ret 0 ?print@derived@@UAEXXZ ENDP ; derived::print _TEXT ENDS ; COMDAT ?print_another@derived@@UAEXXZ _TEXT SEGMENT _this$ = -4 ?print_another@derived@@UAEXXZ PROC NEAR ; derived::print_another, COMDAT ; Line 17 push ebp mov ebp, esp sub esp, 68 ; 00000044H push ebx push esi push edi push ecx lea edi, DWORD PTR [ebp-68] mov ecx, 17 ; 00000011H mov eax, -858993460 ; ccccccccH rep stosd pop ecx mov DWORD PTR _this$[ebp], ecx ; Line 18 pop edi pop esi pop ebx mov esp, ebp pop ebp ret 0 ?print_another@derived@@UAEXXZ ENDP ; derived::print_another _TEXT ENDS PUBLIC ?print@base@@UAEXXZ ; base::print PUBLIC ??_7base@@6B@ ; base::`vftable' ; COMDAT ??_7base@@6B@ CONST SEGMENT ??_7base@@6B@ DD FLAT:?print@base@@UAEXXZ ; base::`vftable' CONST ENDS ; COMDAT ??0base@@QAE@XZ _TEXT SEGMENT _this$ = -4 ??0base@@QAE@XZ PROC NEAR ; base::base, COMDAT push ebp mov ebp, esp sub esp, 68 ; 00000044H push ebx push esi push edi push ecx lea edi, DWORD PTR [ebp-68] mov ecx, 17 ; 00000011H mov eax, -858993460 ; ccccccccH rep stosd pop ecx mov DWORD PTR _this$[ebp], ecx mov eax, DWORD PTR _this$[ebp] mov DWORD PTR [eax], OFFSET FLAT:??_7base@@6B@ ; base::`vftable' //在调用derived的构造函数中首先调用了父类base的构造函数,此处将derived对象的第一块区域存放base的vftable,此构造函数返回后,由derived的构造函数重新设定该存储区域的值为derived的vftable mov eax, DWORD PTR _this$[ebp] pop edi pop esi pop ebx mov esp, ebp pop ebp ret 0 ??0base@@QAE@XZ ENDP ; base::base _TEXT ENDS ; COMDAT ?print@base@@UAEXXZ _TEXT SEGMENT _this$ = -4 ?print@base@@UAEXXZ PROC NEAR ; base::print, COMDAT ; Line 8 push ebp mov ebp, esp sub esp, 68 ; 00000044H //为什么每个函数开头都申请如此大的栈空间?? push ebx push esi push edi push ecx lea edi, DWORD PTR [ebp-68] mov ecx, 17 ; 00000011H mov eax, -858993460 ; ccccccccH rep stosd pop ecx mov DWORD PTR _this$[ebp], ecx ; Line 9 pop edi pop esi pop ebx mov esp, ebp pop ebp ret 0 ?print@base@@UAEXXZ ENDP ; base::print _TEXT ENDS END
生成的汇编代码很多地方还是不明白:比如说注释比较密的地方为什么将_this指针存来存去,call _chkesp是干嘛用的等等.
|