C ++ polymorphism assembly analysis

xiaoxiao2021-04-01  217

One: Description

The polymorphisms caused by the virtual functions in C have a mystery. This article makes the entire calling process through the analysis of assembly code, but the reader is aware of C , and the call to the virtual function should There is a clear concept, and the reader should have a certain assembly basis.

Article structure:

One: Description

Two: C source code

Three: Analysis

3.1: Some useful values ​​used from the analysis from memory

3.2: All kinds of member functions (everyone only need to correspond to the function name and its first address)

3.3 Function call analysis

It is recommended that everyone can figure out the source code. It is best to debug it on your own machine and then look at the analysis according to the execution process of the program.

Analyze the environment and tools:

VC . Net 7.1 RealEase version; prohibition optimization

Two: C source code

#include "stdio.h"

#include

Class CBase1

{

PUBLIC:

CBASE1 () {};

~ CBASE1 () {};

Virtual void virfun1 ();

Virtual void virfun2 ();

Virtual void base1 ();

Int Num;

Int b1num;

}

Class CBase2

{

PUBLIC:

Int Num;

CBASE2 () {};

~ CBASE2 () {};

Virtual void virfun1 ();

Virtual void virfun2 ();

Virtual void base2 ();

}

Class Csub1: Public CBase1

{

PUBLIC:

CSUB1 () {};

~ Csub1 () {};

Virtual void virfun1 ();

}

Class CSUB2: Public CBase1, Public CBase2

{

PUBLIC:

CSUB2 () {};

~ Csub2 () {};

Virtual void virfun1 ();

Virtual void virfun3 ();

Int S2num;

}

Class CSUB3: Public CSUB2

{

PUBLIC:

CSUB3 () {};

~ Csub3 () {};

Virtual void base2 ();

Virtual void virfun2 ();

Virtual void virfun4 ();

}

/ / -------------------------------------------------------------------------------------------- ------------------------------

Void CBase1 :: virfun1 ()

{

Printf ("Run in CBase1 :: Virfun1 () / N");

}

Void CBase1 :: virfun2 ()

{

Printf ("Run in CBase1 :: Virfun2 () / N");

}

Void CBase1 :: Base1 ()

{

Printf ("Run In CBase1 :: Base1 () / N");

}

/ / -------------------------------------------------------------------------------------------- ------------------------------

Void CBase2 :: virfun1 ()

{

Printf ("Run in CBase2 :: Virfun1 () / n");

}

Void CBase2 :: virfun2 ()

{

Printf ("Run in CBase2 :: Virfun2 () / N");

}

Void cbase2 :: base2 () {

Printf ("Run in CBase2 :: Base2 () / N");

}

/ / -------------------------------------------------------------------------------------------- ------------------------------

Void csub1 :: virfun1 ()

{

Printf ("Run IN CSUB1 :: Virfun1 () / N");

}

Void csub2 :: virfun1 ()

{

Printf ("Run IN CSUB2 :: Virfun1 () / N");

}

Void csub2 :: virfun3 ()

{

Printf ("Run IN CSUB2 :: Virfun3 () / N");

}

Void csub3 :: virfun2 ()

{

Printf ("Run IN CSUB3 :: Virfun2 () / N");

}

Void csub3 :: virfun4 ()

{

Printf ("Run IN CSUB3 :: Virfun4 () / n");

}

Void csub3 :: base2 ()

{

Printf ("Run IN CSUB3 :: Base2 () / N");

}

CBASE1 base1;

CBASE2 base2;

CSUB1 SUB1;

CSUB2 SUB2;

CSUB3 SUB3;

CBASE1 * PBASE1 = 0;

CBASE2 * PBase2 = 0;

CSUB1 * PSUB1 = 0;

CSUB2 * PSUB2 = 0;

CSUB3 * PSUB3 = 0;

Void test1 ()

{

Base1.virfun1 ();

Base1.num = 1;

PBASE1-> Virfun1 ();

PBASE1-> Num = 1;

}

Void test2 ()

{

CBASE1 & TEMBASE1 = SUB1;

CBASE1 * Ptembase1 = & sub1;

Sub1.virfun1 ();

PSUB1-> virfun1 ();

PSUB1-> virfun2 ();

TEMBASE1.VIRFUN1 ();

Ptembase1-> virfun1 ();

Sub1.virfun2 ();

PSUB1-> virfun2 ();

Tembase1.virfun2 ();

Ptembase1-> virfun2 ();

Sub1.num = 1;

PSUB1-> NUM = 2;

}

Void test3 ()

{

CBASE1 & TEMBASE1 = SUB2; // << === >> CBASE1 * Ptembase1 = & SUB2;

CBASE2 & TEMBASE2 = SUB2; // << === >> CBASE2 * Ptembase2 = & SUB2;

//sub2.virfun3 ();

//Sub2.virfun2 (); // << === >> PSUB2-> virfun2 ();

// Error C2385: Access to "Virfun2" (in "CSUB2") is not clear

PSUB2-> Virfun1 ();

PSUB2-> S2NUM = 2;

TEMBASE1.NUM = 3;

TEMBASE2.NUM = 4;

PSUB2-> Virfun3 ();

PSUB2-> Base1 ();

PSUB2-> base2 (); tembase1.virfun1 (); // << === >> Ptembase1-> virfun1 ();

Tembase2.virfun1 (); // << === >> ptembase2-> virfun1 ();

TEMBASE1.VIRFUN2 (); // << === >> Ptembase1-> Virfun2 ();

Tembase2.virfun2 (); // << === >> Ptembase2-> virfun2 ();

}

Void test4 ()

{

CBASE1 & TEMBASE1 = SUB3; // << === >> CBASE1 * Ptembase1 = & SUB2;

CBASE2 & TEMBASE2 = SUB3; // << === >> CBASE2 * Ptembase2 = & SUB2;

CSUB2 & TEMSUB2 = SUB3;

PSUB3-> virfun4 ();

PSUB3-> virfun2 ();

Tembase1.virfun2 ();

TEMBASE2.VIRFUN2 ();

Tembase2.base2 ();

Temsub2.base2 ();

}

Int main (void)

{

PBASE1 = & base1;

PBASE2 = & base2;

PSUB1 = & SUB1;

PSUB2 = & SUB2;

PSUB3 = & SUB3;

Printf ("Base1:% LX Base2:% LX / NSUB1:% LX SUB2:% LX SUB3: LX / N",

(unsigned int) PBASE1, (unsigned int) PBASE2, (unsigned int) PSUB1, (int) PSUB2, (int) PSUB3);

Printf ("SIZEOF (...) in BYTE / NBASE1:% Lu Base2:% lu / nsub1:% lu Sub2:% lu Sub3:% lu / n",

Sizeof (Base1), Sizeof (Base2), SIZEOF (SUB2), SIZEOF (SUB3));

TEST1 ();

TEST2 ();

TEST3 ();

TEST4 ();

}

Three: Analysis

3.1: Some useful values ​​used from the memory:

Five global objects

CBASE1 base1;

CBASE2 base2;

CSUB1 SUB1;

CSUB2 SUB2;

CSUB3 SUB3;

The initial distribution in the memory is as follows:

0x0040A6F0 XX XX XX XX 14 83 40 00 SUB2: 40A6F4 Size: 24

0x0040A6F8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

0x0040A700 08 83 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

0x0040A708 00 00 00 F0 82 40 00 Base2: 40A70C Size: 8

0x0040A710 00 00 00 E4 82 40 00 Base1: 40A714 Size: 12

0x0040a718 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

0x0040A720 FC 82 40 00 00 00 00 00 0040a728 00 00 00 00 840 00 SUB3: 40A72C Size: 24

0x0040a730 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

0x0040A738 24 83 40 00 00 00 00

0x0040A740 00 00 00 00 00

0x0040A6F0 xxxxxxxx 00408314 SUB2: 40A6F4 Size: 24

0x0040A6F8 00000000 00000000

0x0040a700 00408308 00000000

0x0040A708 00000000 004082F0 Base2: 40A70C Size: 8

0x0040A710 00000000 004082E4 Base1: 40A714 Size: 12

0x0040A718 00000000 00000000

0x0040A720 004082FC 00000000 SUB1: 40A720 SIZE: 12

0x0040A728 00000000 00408330 SUB3: 40A72C Size: 24

0x0040A730 00000000 00000000

0x0040a738 00408324 00000000

0x0040A740 00000000

The storage of five types of virtual tables is as follows:

CBASE1:

0x004082E4 00401000 -> CBase1 :: virfun1 ()

0x004082E8 004010 -> CBase1 :: virfun2 ()

0x004082ec 00401040 -> CBase1 :: base1 ()

CBASE2:

0x004082F0 00401060 -> CBase2 :: virfun1 ()

0x004082F4 00401080 -> CBase2 :: virfun2 ()

0x004082F8 004010A0 -> CBase2 :: base2 ()

CSUB1:

0x004082FC 004010C0 -> CSUB1 :: virfun1 ()

0x00408300 00401020 -> CBase1 :: virfun2 ()

0x00408304 00401040 -> CBase1 :: base1 ()

The CSUB2 is offset to 0CH content:

0x00408308 00401540 -> CSUB2 :: virfun1`adjustor {12}

0x0040830C 00401080 -> CBase2 :: virfun2 ()

0x00408310 004010A0 -> CBase2 :: base2 ()

The CSUB2 is offset to 0: The content points to the virtual table pointer:

0x00408314 004010E0 -> CSUB2 :: virfun1 ()

0x00408318 00401020 -> CBase1 :: virfun2 ()

0x0040831C 00401040 -> CBase1 :: base1 ()

0x00408320 00401100 -> CSUB2 :: virfun3 ()

CSUB3 is offset to 0CH content:

0x00408324 00401540 -> CSUB2 :: virfun1`adjustor {12}

0x00408328 00401580 -> CSUB3 :: virfun2`adjustor {12}

0x0040832C 00401160 -> CSUB3 :: base2 () CSUB3 Offset to 0 Defense Table Pointer Points:

0x00408330 004010E0 -> CSUB2 :: virfun1 ()

0x00408334 00401120 -> CSUB3 :: virfun2 ()

0x00408338 00401040 -> CBase1 :: base11 ()

0x0040833C 00401100 -> CSUB2 :: virfun3 ()

0x00408340 0040114000 -> CBase1 :: base11 ()

0x00408344 00000000

0x00408348 ffffffff

Two Adjustor:

[THUNK]: CSUB2 :: virfun1`adjustor {12} ':

00401540 83 E9 0C SUB ECX, 0CH

00401543 E9 98 FB FF FF JMP CSUB2 :: Virfun1 (4010E0H)

[THUNK]: CSUB3 :: Virfun2`adjustor {12} ':

00401580 83 E9 0C SUB ECX, 0CH

00401583 E9 98 FB FF FF JMP CSUB3 :: Virfun2 (401120H)

3.2: All kinds of member functions (everyone only need to correspond to the function name and its first address)

55: // ---------------------------------------------- --------------------------------

56: void cbease1 :: virfun1 ()

57: {

00401000 55 Push EBP

00401001 8B EC MOV EBP, ESP

00401003 51 PUSH ECX

00401004 89 4D FC MOV DWORD PTR [EBP-4], ECX

58: Printf ("Run in CBase1 :: virfun1 () / n");

00401007 68 10 81 40 00 Push Offset kernel32_null_thunk_data 30h (408110H)

0040100C E8 65 06 00 00 Call Printf (401676h)

00401011 83 C4 04 Add ESP, 4

59:}

00401014 8B E5 MOV ESP, EBP

00401016 5D POP EBP

00401017 C3 RET

60:

61: Void CBase1 :: virfun2 ()

62: {

00401020 55 PUSH EBP

00401021 8B EC MOV EBP, ESP

00401023 51 PUSH ECX

00401024 89 4D FC MOV DWORD PTR [EBP-4], ECX

63: Printf ("Run in CBase1 :: Virfun2 () / n");

00401027 68 2C 81 40 00 Push Offset Kernel32_null_thunk_data 4CH (40812CH) 0040102C E8 45 06 00 00 Call Printf (401676H)

00401031 83 C4 04 Add ESP, 4

64:}

00401034 8B E5 MOV ESP, EBP

00401036 5D POP EBP

00401037 C3 RET

65:

66: void cbease1 :: base1 ()

67: {

00401040 55 PUSH EBP

00401041 8B EC MOV EBP, ESP

00401043 51 PUSH ECX

00401044 89 4D FC MOV DWORD PTR [EBP-4], ECX

68: Printf ("Run in CBase1 :: Base1 () / n");

00401047 68 48 81 40 00 Push Offset kernel32_null_thunk_data 68h (408148H)

0040104C E8 25 06 00 00 Call Printf (401676h)

00401051 83 C4 04 Add ESP, 4

69:}

00401054 8B E5 MOV ESP, EBP

00401056 5D POP EBP

00401057 C3 RET

70:

71: // ---------------------------------------------- --------------------------------

72: void cbease2 :: virfun1 ()

73: {

00401060 55 PUSH EBP

00401061 8B EC MOV EBP, ESP

00401063 51 PUSH ECX

00401064 89 4D FC MOV DWORD PTR [EBP-4], ECX

74: Printf ("Run in CBase2 :: Virfun1 () / N");

00401067 68 64 81 40 00 Push Offset kernel32_null_thunk_data 84H (408164H)

0040106C E8 05 06 00 00 Call Printf (401676h)

00401071 83 C4 04 Add ESP, 4

75:}

00401074 8B E5 MOV ESP, EBP

00401076 5D POP EBP

00401077 C3 RET

76: void cbase2 :: virfun2 ()

77: {

00401080 55 PUSH EBP

00401081 8B EC MOV EBP, ESP

00401083 51 Push ECX00401084 89 4D FC MOV DWORD PTR [EBP-4], ECX

78: Printf ("Run in CBase2 :: Virfun2 () / N");

00401087 68 80 81 40 00 Push Offset kernel32_null_thunk_data 0a0h (408180H)

0040108C E8 E5 05 00 00 Call Printf (401676h)

00401091 83 C4 04 Add ESP, 4

79:}

00401094 8B E5 MOV ESP, EBP

00401096 5D POP EBP

00401097 C3 RET

80:

81: Void CBase2 :: Base2 ()

82: {

004010A0 55 PUSH EBP

004010A1 8B EC MOV EBP, ESP

004010A3 51 PUSH ECX

004010A4 89 4D FC MOV DWORD PTR [EBP-4], ECX

83: Printf ("Run in CBase2 :: Base2 () / N");

004010A7 68 9C 81 40 00 Push Offset kernel32_null_thunk_data 0bch (40819CH)

004010ac E8 C5 05 00 00 Call Printf (401676h)

004010B1 83 C4 04 Add ESP, 4

84:}

004010B4 8B E5 MOV ESP, EBP

004010B6 5D POP EBP

004010B7 C3 RET

85: // ---------------------------------------------- --------------------------------

86: void csub1 :: virfun1 ()

87: {

004010c0 55 Push EBP

004010C1 8B EC MOV EBP, ESP

004010C3 51 PUSH ECX

004010C4 89 4D FC MOV DWORD PTR [EBP-4], ECX

88: Printf ("Run In CSUB1 :: Virfun1 () / N");

004010C7 68 B8 81 40 00 Push Offset Kernel32_null_thunk_data 0D8H (4081B8H)

004010CC E8 A5 05 00 00 Call Printf (401676h)

004010d1 83 C4 04 Add ESP, 4

89:}

004010D4 8B E5 MOV ESP, EBP

004010D6 5D POP EBP

004010d7 C3 RET90:

91: void csub2 :: virfun1 ()

92: {

004010E0 55 PUSH EBP

004010E1 8B EC MOV EBP, ESP

004010E3 51 PUSH ECX

004010E4 89 4D FC MOV DWORD PTR [EBP-4], ECX

93: Printf ("Run IN CSUB2 :: Virfun1 () / N");

004010E7 68 D4 81 40 00 PUSH OFFSET KERNEL32_NULL_THUNK_DATA 0F4H (4081D4H)

004010EC E8 85 05 00 00 Call Printf (401676H)

004010f1 83 C4 04 Add ESP, 4

94:}

004010F4 8B E5 MOV ESP, EBP

004010f6 5D POP EBP

004010f7 C3 RET

95: void csub2 :: virfun3 ()

96: {

00401100 55 Push EBP

00401101 8B EC MOV EBP, ESP

00401103 51 PUSH ECX

00401104 89 4D FC MOV DWORD PTR [EBP-4], ECX

97: Printf ("Run IN CSUB2 :: Virfun3 () / n");

00401107 68 F0 81 40 00 Push Offset kernel32_null_thunk_data 110h (4081F0H)

0040110C E8 65 05 00 00 Call Printf (401676h)

00401111 83 C4 04 Add ESP, 4

98:}

00401114 8B E5 MOV ESP, EBP

00401116 5D POP EBP

00401117 C3 RET

99:

100: Void CSUB3 :: virfun2 ()

101: {

00401120 55 PUSH EBP

00401121 8B EC MOV EBP, ESP

00401123 51 PUSH ECX

00401124 89 4D FC MOV DWORD PTR [EBP-4], ECX

102: Printf ("Run IN CSUB3 :: Virfun2 () / n");

00401127 68 0C 82 40 00 Push Offset Kernel32_null_thunk_data 12CH (40820CH)

0040112C E8 45 05 00 00 Call Printf (401676h)

00401131 83 C4 04 Add ESP, 4

103:}

00401134 8B E5 MOV ESP, EBP00401136 5D POP EBP

00401137 C3 RET

104: Void CSUB3 :: virfun4 ()

105: {

00401140 55 PUSH EBP

00401141 8B EC MOV EBP, ESP

00401143 51 PUSH ECX

00401144 89 4D FC MOV DWORD PTR [EBP-4], ECX

106: Printf ("Run in CSUB3 :: Virfun4 () / N");

00401147 68 28 82 40 00 Push Offset kernel32_null_thunk_data 148H (408228H)

0040114C E8 25 05 00 00 Call Printf (401676h)

00401151 83 C4 04 Add ESP, 4

107:}

00401154 8B E5 MOV ESP, EBP

00401156 5D POP EBP

00401157 C3 RET

108: Void CSUB3 :: Base2 ()

109: {

00401160 55 PUSH EBP

00401161 8B EC MOV EBP, ESP

00401163 51 PUSH ECX

00401164 89 4D FC MOV DWORD PTR [EBP-4], ECX

110: Printf ("Run In CSUB3 :: Base2 () / N");

00401167 68 44 82 40 00 Push Offset kernel32_null_thunk_data 164H (408244H)

0040116C E8 05 05 00 00 Call Printf (401676h)

00401171 83 C4 04 Add ESP, 4

111:}

00401174 8B E5 MOV ESP, EBP

00401176 5D POP EBP

00401177 C3 RET

3.3 Function call analysis

128: void test1 ()

129: {

00401180 55 Push EBP

00401181 8B EC MOV EBP, ESP

130: Base1.virfun1 ();

00401183 B9 14 A7 40 00 MOV ECX, OFFSET BASE1 (40A714H)

00401188 E8 73 Fe FF FF CALL CBASE1 :: Virfun1 (401000H)

The THIS pointer is stored in the ECX register, and the object directly uses the CALL instruction directly;

131:

132: Base1.num = 1;

0040118D C7 05 18 A7 40 00 01 00 00 00 MOV DWORD PTR [Base1 4 (40A718H)], 1 object directly access the simple member variable: DWORD PTR [Base1] is the virtual table pointer of Base1,

DWORD PTR [Base1 4] is the first member variable of Base1, that is, Base1.Num to be accessed

133:

134: PBASE1-> virfun1 ();

00401197 A1 E0 A6 40 00 MOV EAX, DWORD PTR [PBase1 (40A6E0H)]

The content of the object pointer PBASE1 is the first address of the referred to, save the first address of Base1 to the EAX register.

0040119C 8B 10 MOV EDX, DWORD PTR [EAX]

The virtual table pointer to acquire the object is also available to the EDX register

0040119E 8B 0D E0 A6 40 00 MOV ECX, DWORD PTR [PBASE1 (40A6E0H)]

This pointer to the ECX register

004011A4 FF 12 Call DWORD PTR [EDX]

The first virtual function is obtained by the virtual table pointer, that is, the Virfun1 () called

135:

136: PBASE1-> Num = 1;

004011A6 A1 E0 A6 40 00 MOV EAX, DWORD PTR [PBase1 (40A6E0H)]

Save the first address of BASE1 to the EAX register

004011AB C7 40 04 01 00 00 MOV DWORD PTR [EAX 4], 1

Member variable of access object: The first address 4 is the beginning of a member variable

137:}

004011B2 5D POP EBP

004011B3 C3 RET

138:

139: void test2 ()

140: {

004011c0 55 Push EBP

004011C1 8B EC MOV EBP, ESP

004011C3 83 EC 08 SUB ESP, 8

8-byte temporary variable

141: CBASE1 & TEMBASE1 = SUB1;

004011C6 C7 45 FC 20 A7 40 00 MOV DWORD PTR [TEMBASE1], OFFSET SUB1 (40A720H)

142:

143: CBASE1 * ptembase1 = & sub1;

004011CD C7 45 F8 20 A7 40 00 MOV DWORD PTR [Ptembase1], Offset Sub1 (40A720H)

The references in C are equivalent to the pointer on the storage process. On the 32-bit machine, each reference each accounts for 4 bytes, and the first address of the object is stored.

The virtual table of class CSUB1 is as follows:

CSUB1:

0x004082FC 004010C0 -> CSUB1 :: virfun1 ()

0x00408300 00401020 -> CBase1 :: virfun2 ()

0x00408304 00401040 -> CBase1 :: base1 ()

144:

145: Sub1.virfun1 ();

004011D4 B9 20 A7 40 00 MOV ECX, OFFSET SUB1 (40A720H) 004011D9 E8 E2 Fe FF FF CALL CSUB1 :: Virfun1 (4010C0H)

Object directly calls functions, note that CSUB1 :: virfun1 () is called, not CBase1 :: virfun1 ()

146:

147: PSUB1-> virfun1 ();

004011DE A1 E8 A6 40 00 MOV EAX, DWORD PTR [PSUB1 (40A6E8H)]

004011E3 8B 10 MOV EDX, DWORD PTR [EAX]

004011E5 8B 0D E8 A6 40 00 MOV ECX, DWORD PTR [PSUB1 (40A6E8H)]

004011EB FF 12 Call DWORD PTR [EDX]

Pointer call function, analysis of TEST1 ()

148:

149: PSUB1-> Virfun2 ();

004011ed A1 E8 A6 40 00 MOV EAX, DWORD PTR [PSUB1 (40A6E8H)]

004011f2 8b 10 MOV EDX, DWORD PTR [EAX]

004011f4 8b 0d E8 A6 40 00 MOV ECX, DWORD PTR [PSUB1 (40A6E8H)]

004011fa ff 52 04 Call DWORD PTR [EDX 4]

Pointer call function, analysis of TEST1 ()

150:

151: TEMBASE1.VIRFUN1 ();

004011fd 8b 45 FC MOV Eax, DWORD PTR [TEMBASE1]

Save the first address of the SUB1 to the EAX register

00401200 8B 10 MOV EDX, DWORD PTR [EAX]

Save the object's virtual table pointer to the EDX register

00401202 8B 4D FC MOV ECX, DWORD PTR [TEMBASE1]

This pointer to the ECX register

00401205 FF 12 Call DWORD PTR [EDX]

Quote Call function, by the generated code you can see: C is quoted in nature is a pointer

152:

153: Ptembase1-> virfun1 ();

00401207 8B 45 F8 MOV EAX, DWORD PTR [Ptembase1]

0040120A 8B 10 MOV EDX, DWORD PTR [EAX]

0040120C 8B 4D F8 MOV ECX, DWORD PTR [Ptembase1]

0040120F FF 12 Call DWORD PTR [EDX]

154:

155: Sub1.virfun2 ();

00401211 B9 20 A7 40 00 MOV ECX, OFFSET SUB1 (40A720H) THIS pointer

00401216 E8 05 Fe FF FF CALL CBASE1 :: Virfun2 (401020H)

156:

157: PSUB1-> Virfun2 ();

0040121B A1 E8 A6 40 00 MOV EAX, DWORD PTR [PSUB1 (40A6E8H)] The first address 00401220 8b 10 MOV EDX, DWORD PTR [EAX] Finding Pointer

00401222 8B 0D E8 A6 40 00 MOV ECX, DWORD PTR [PSUB1 (40A6E8H)] THIS pointer

00401228 FF 52 04 Call DWORD PTR [EDX 4] The second function in the virtual table

158:

159: TEMBASE1.VIRFUN2 ();

0040122B 8B 45 FC MOV EAX, DWORD PTR [TEMBASE1] object's first address

0040122e 8b 10 MOV EDX, DWORD PTR [EAX] Finding Pointer

00401230 8B 4D FC MOV ECX, DWORD PTR [TEMBASE1] THIS pointer

00401233 FF 52 04 Call DWORD PTR [EDX 4] The second function in the virtual table

160:

161: Ptembase1-> virfun2 ();

00401236 8B 45 F8 MOV EAX, DWORD PTR [PTEMBase1] object's first address

00401239 8B 10 MOV EDX, DWORD PTR [EAX] Find Table Pointer

0040123B 8B 4D F8 MOV ECX, DWORD PTR [Ptembase1] THIS pointer

0040123E FF 52 04 Call DWORD PTR [EDX 4] The second function in the virtual table

162:

163:

164: Sub1.num = 1;

00401241 C7 05 24 A7 40 00 01 00 00 00 MOV DWORD PTR [SUB1 4 (40A724H)], 1

165:

166: PSUB1-> Num = 2;

0040124B A1 E8 A6 40 00 MOV EAX, DWORD PTR [PSUB1 (40A6E8H)] THIS pointer

00401250 C7 40 04 02 00 00 MOV DWORD PTR [EAX 4], 2

167:

168:}

00401257 8B E5 MOV ESP, EBP

00401259 5D POP EBP

0040125A C3 RET

169:

170: void test3 ()

171: {

00401260 55 Push EBP

00401261 ​​8B EC MOV EBP, ESP

00401263 83 EC 0C SUB ESP, 0CH

12-byte temporary variables, including two references for our declaration, and 4 bytes compiler

172: CBASE1 & TEMBASE1 = SUB2; // << === >> CBASE1 * Ptembase1 = & SUB2;

00401266 C7 45 FC F4 A6 40 00 MOV DWORD PTR [TEMBASE1], OFFSET SUB2 (40A6F4H) Type of CBASE1 TEMBASE1, its contents are the first address of SUB2

Initial storage in memory: (starting from 0x0040A6F4, a total of 24 bytes)

0x0040a6f0 xxxxxxx 00408314

0x0040A6F8 00000000 00000000

0x0040a700 00408308 00000000

0x0040A708 00000000

It can be seen that since the SUB2 has two parent CBASE1 and CBASE2 (the order in which the two classes in the source program has a big impact on the distribution of the SUB2 variables in memory, referring to the offset 0 The virtual table pointer is inherited by CBase1, and the address of the non-inheritance function (CSUB2 own virtual function) is added to the virtual table pointed to by this pointer; inheriting the virtual table pointer at the offset 0CH. The compiler modifies the content in the virtual table according to the implementation of the virtual function in the CSUB2 class.

173:

174: CBase2 & tembase2 = Sub2; // << === >> CBASE2 * Ptembase2 = & sub2;

0040126D B8 F4 A6 40 00 MOV EAX, OFFSET SUB2 (40A6F4H) Take the first address of SUB2

00401272 85 C0 Test Eax, EAX judgment reference is 0

00401274 74 09 JE TEST3 1FH (40127FH) is 0 jump to (40127FH) (not jumping here)

00401276 C7 45 F4 00 A7 40 00 MOV DWORD PTR [EBP-0CH], OFFSET SUB2 0CH (40A700H)

Move the valid address of the object SUB2 to 0CH to a temporary variable

0040127D EB 07 JMP TEST3 26H (401286H)

0040127F C7 45 F4 00 00 00 MOV DWORD PTR [EBP-0CH], 0

If the first address of SUB2 is 0, the temporary variable is also 0

00401286 8B 4D F4 MOV ECX, DWORD PTR [EBP-0CH]

00401289 89 4D F8 MOV DWORD PTR [TEMBASE2], ECX

Assign a temporary variable to tembase2, ie a CBASE2 type reference

It can be seen from the upper analysis that the CBASE2 type is a reference to the entry of the effective address from the SUB2 as the "reference" object, which is consistent with the distribution of the SUB2.

175:

176: //sub2.virfun3 ();

177: //sub2.virfun2 (); // << === >> PSUB2-> Virfun2 ();

178: // Error C2385: Access to "Virfun2" (in "CSUB2") is not clear

CSUB2 does not realize its own virfun2 (), and both parent class have virtual functions of Virfun2, so Sub2.virfun2 () This call is not clear.

179:

180: PSUB2-> virfun1 (); 0040128C 8B 15 EC A6 40 00 MOV EDX, DWORD PTR [PSUB2 (40A6ECH)] Take the first address of the object

00401292 8B 02 MOV EAX, DWORD PTR [EDX] Virtual Design of Offset 0

00401294 8B 0D EC A6 40 00 MOV ECX, DWORD PTR [PSUB2 (40A6ECH)] Take the first address of the object to ECX as the THIS pointer for the object

0040129A FF 10 Call DWORD PTR [EAX] call the first virtual function in the virtual table

181:

182: PSUB2-> S2NUM = 2;

0040129C 8B 0D EC A6 40 00 MOV ECX, DWORD PTR [PSUB2 (40A6ECH)]

004012A2 C7 41 14 02 00 00 00 MOV DWORD PTR [ECX 14H], 2

183:

184: TEMBASE1.NUM = 3;

004012A9 8B 55 FC MOV EDX, DWORD PTR [TEMBASE1]

004012AC C7 42 04 03 00 00 MOV DWORD PTR [EDX 4], 3

185:

186: TEMBASE2.NUM = 4;

004012B3 8B 45 F8 MOV EAX, DWORD PTR [TEMBASE2]

004012B6 C7 40 04 04 00 00 00 MOV DWORD PTR [EAX 4], 4

After performing the three assignment statements, the SUB2 is in the middle of memory:

In single-byte unit:

0x0040A6F0 XX XX XX XX 14 83 40 00

0x0040a6f8 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

0x0040a700 08 83 40 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

0x0040A708 02 00 00 00 00 00 00 00

Take four bytes:

0x0040a6f0 xxxxxxx 00408314

0x0040A6F8 00000003 00000000

0x0040a700 00408308 00000004

0x0040A708 00000002

Thereby, the distribution of each variable in SUB2 has a further understanding of the distribution in memory.

187:

188: PSUB2-> Virfun3 ();

004012BD 8B 0D EC A6 40 00 MOV ECX, DWORD PTR [PSUB2 (40A6ECH)]

004012C3 8B 11 MOV EDX, DWORD PTR [ECX]

004012C5 8B 0D EC A6 40 00 MOV ECX, DWORD PTR [PSUB2 (40A6ECH)]

004012CB FF 52 0C Call DWORD PTR [EDX 0CH]

189:

190: PSUB2-> Base1 ();

004012 CE A1 EC A6 40 00 MOV Eax, DWORD PTR [PSUB2 (40A6ECH)]

004012D3 8B 10 MOV EDX, DWORD PTR [EAX]

004012D5 8B 0D EC A6 40 00 MOV ECX, DWORD PTR [PSUB2 (40A6ECH)]

004012DB FF 52 08 Call Dword PTR [EDX 8]

191:

192: psub2-> base2 ();

004012DE 8B 0D EC A6 40 00 MOV ECX, DWORD PTR [PSUB2 (40A6ECH)] takes the SUB2 first address in ECX

004012E4 83 C1 0C ADD ECX, 0CH The effective address of the offset in SUB2 is used as the THIS pointer used when calling Base2 ()

004012E7 A1 EC A6 40 00 MOV Eax, DWORD PTR [PSUB2 (40A6ECH)] Take SUB2

004012EC 8B 50 0C MOV EDX, DWORD PTR [EAX 0CH] Virtual Table Pointer Offset to 0CH

004012EF FF 52 08 Call DWORD PTR [EDX 8] Call the third virtual function in the virtual table

Note that the THIS pointer used when calling CBase2 :: base1 () and calls the CBase2 :: base2 () function, that is, the content of the ECX register is different, please pay attention to the difference

193:

In C , only the pointers or references support the polymorphisms required in the OO program design. The following two calls seem to be similar on the code, the execution result is the same: all call csub2 :: virfun1 (), but should notice that the reference TEMBASE1 and TEMBASE2 are different: Reference TEMBASE1 content is the first address of SUB2, reference TEMBASE2 The content is offset from the SUB2 to 0CH. The following specific analysis:

194: tembase1.virfun1 (); // << === >> ptembase1-> virfun1 ();

004012F2 8B 45 FC MOV Eax, DWORD PTR [TEMBASE1]

Sub2's first address moved to EAX

004012F5 8B 10 MOV EDX, DWORD PTR [EAX]

The virtual table pointer offset in SUB2 is shifted to EDX

004012F7 8B 4D FC MOV ECX, DWORD PTR [TEMBASE1]

The first address of the SUB2 moves to the THIS pointer used by ECX as the call function

004012FA FF 12 Call DWORD PTR [EDX]

Call the first function in the virtual table, ie csub2 :: virfun1 ()

The CSUB2 is offset to 0: The content points to the virtual table pointer:

0x00408314 004010E0 -> CSUB2 :: virfun1 ()

0x00408318 00401020 -> CBase1 :: virfun2 ()

0x0040831C 00401040 -> CBase1 :: base1 ()

0x00408320 00401100 -> CSUB2 :: virfun3 ()

195:

196: tembase2.virfun1 (); // << === >> Ptembase2-> virfun1 ();

004012FC 8B 45 F8 MOV EAX, DWORD PTR [TEMBASE2]

The address of the offset from the SUB2 is moved to EAX

004012FF 8B 10 MOV EDX, DWORD PTR [EAX] Subset is shifted to 0CH Move to EDX

00401301 8B 4D F8 MOV ECX, DWORD PTR [TEMBASE2]

The address of the offset of SUB2 is moved to ECX as the THIS pointer used by the call function?

00401304 FF 12 Call DWORD PTR [EDX]

Call the first function in the virtual table of 0ch, but the THIS pointer required to see the function is not right: actually executed CSUB2 :: virfun1 (), then the value of the ECX before the execution should be the first address of SUB2 Talented. Let us look at the content in the virtual table:

The CSUB2 is offset to 0CH content:

0x00408308 00401540 -> CSUB2 :: virfun1`adjustor {12}

0x0040830C 00401080 -> CBase2 :: virfun2 ()

0x00408310 004010A0 -> CBase2 :: base2 ()

The first item in this virtual table is not the address of the CSUB2 :: virfun1 (), but a so-called Adjustor address, let's take a look at this Adjustor:

[THUNK]: CSUB2 :: virfun1`adjustor {12} ':

00401540 83 E9 0C SUB ECX, 0CH

00401543 E9 98 FB FF FF JMP CSUB2 :: Virfun1 (4010E0H)

At this point, everything is clear: In Adjustor, the value of ECX finally changed to the first address of the SUB2 we think, and finally executed CSUB2 :: virfun1 (). The call to the following two functions is similar, but the CSUB2 is offset to 0CH The second item is not the address of the Adjustor, but the address of the cbase2 :: virfun2 (), then call TEMBASE2 .virfun2 () When the value of ECX is what is the address of the offset of SUB2 is 0ch.

197:

198: tembase1.virfun2 (); // << === >> ptembase1-> virfun2 ();

00401306 8B 45 FC MOV EAX, DWORD PTR [TEMBASE1]

00401309 8B 10 MOV EDX, DWORD PTR [EAX]

0040130B 8B 4D FC MOV ECX, DWORD PTR [TEMBASE1]

0040130E FF 52 04 Call DWORD PTR [EDX 4]

199:

200: tembase2.virfun2 (); // << === >> Ptembase2-> virfun2 ();

00401311 8B 45 F8 MOV EAX, DWORD PTR [TEMBASE2]

00401314 8B 10 MOV EDX, DWORD PTR [EAX]

00401316 8B 4D F8 MOV ECX, DWORD PTR [TEMBASE2]

00401319 FF 52 04 Call DWORD PTR [EDX 4] 201:}

0040131C 8B E5 MOV ESP, EBP

0040131E 5D POP EBP

0040131F C3 RET

202:

There is no essential difference in the call and above analysis in TEST4 (). Interested friends can analyze themselves.

203: void test4 ()

204: {

00401320 55 Push EBP

00401321 8B EC MOV EBP, ESP

00401323 83 EC 10 SUB ESP, 10h

205: CBASE1 & TEMBASE1 = SUB3; // << === >> CBASE1 * Ptembase1 = & SUB2;

00401326 C7 45 FC 2C A7 40 00 MOV DWORD PTR [TEMBASE1], OFFSET SUB3 (40A72CH)

206:

207: CBASE2 & TEMBASE2 = SUB3; // << === >> CBASE2 * Ptembase2 = & SUB2;

0040132D B8 2C A7 40 00 MOV EAX, Offset Sub3 (40A72CH)

00401332 85 C0 Test Eax, EAX

00401334 74 09 JE TEST4 1FH (40133FH)

00401336 C7 45 F0 38 A7 40 00 MOV DWORD PTR [EBP-10H], OFFSET SUB3 0CH (40A738H)

0040133D EB 07 JMP TEST4 26H (401346H)

0040133F C7 45 F0 00 00 00 MOV DWORD PTR [EBP-10H], 0

00401346 8B 4D F0 MOV ECX, DWORD PTR [EBP-10H]

00401349 89 4D F8 MOV DWORD PTR [TEMBASE2], ECX

208:

209: CSUB2 & TEMSUB2 = SUB3;

0040134C C7 45 F4 2C A7 40 00 MOV DWORD PTR [Temsub2], Offset Sub3 (40A72CH)

210:

211: PSUB3-> Virfun4 ();

00401353 8B 15 F0 A6 40 00 MOV EDX, DWORD PTR [PSUB3 (40A6F0H)]

00401359 8B 02 MOV EAX, DWORD PTR [EDX]

0040135B 8B 0D F0 A6 40 00 MOV ECX, DWORD PTR [PSUB3 (40A6F0H)]

00401361 FF 50 10 Call DWORD PTR [EAX 10h]

212:

213: PSUB3-> Virfun2 ();

00401364 8B 0D F0 A6 40 00 MOV ECX, DWORD PTR [PSUB3 (40A6F0H)] 0040136A 8B 11 MOV EDX, DWORD PTR [ECX]

0040136C 8B 0D F0 A6 40 00 MOV ECX, DWORD PTR [PSUB3 (40A6F0H)]

00401372 FF 52 04 Call DWORD PTR [EDX 4]

214:

215: TEMBASE1.VIRFUN2 ();

00401375 8B 45 FC MOV EAX, DWORD PTR [TEMBASE1]

00401378 8B 10 MOV EDX, DWORD PTR [EAX]

0040137A 8B 4D FC MOV ECX, DWORD PTR [TEMBASE1]

0040137D FF 52 04 Call DWORD PTR [EDX 4]

216:

217: tembase2.virfun2 ();

00401380 8B 45 F8 MOV EAX, DWORD PTR [TEMBASE2]

00401383 8B 10 MOV EDX, DWORD PTR [EAX]

00401385 8B 4D F8 MOV ECX, DWORD PTR [TEMBASE2]

00401388 FF 52 04 Call DWORD PTR [EDX 4]

218:

219: tembase2.base2 ();

0040138B 8B 45 F8 MOV EAX, DWORD PTR [TEMBASE2]

0040138E 8B 10 MOV EDX, DWORD PTR [EAX]

00401390 8B 4D F8 MOV ECX, DWORD PTR [TEMBASE2]

00401393 FF 52 08 Call DWORD PTR [EDX 8]

220:

221: Temsub2.base2 ();

00401396 8B 4D F4 MOV ECX, DWORD PTR [TEMSUB2]

00401399 83 C1 0C Add ECX, 0CH

0040139C 8B 45 F4 MOV EAX, DWORD PTR [Temsub2]

0040139F 8B 50 0C MOV EDX, DWORD PTR [EAX 0CH]

004013A2 FF 52 08 Call DWORD PTR [EDX 8]

222:}

004013A5 8B E5 MOV ESP, EBP

004013A7 5D POP EBP

004013A8 C3 RET

转载请注明原文地址:https://www.9cbs.com/read-131246.html

New Post(0)