In the previous section, you have explored the arrangement of the member variables of a class, and now look at the arrangement of virtual function tables and member variables and the arrangement between virtual functions.
Let's look at an example:
1 #include <stdio.h> 2 class Xuzhina_dump_c06_s3 3 { 4 private: 5 int m_a; 6 Public : 7 xuzhina_dump_c06_s3 () {m_a = 0;} 8 Virtual Void Inc () {m_a++;} 9 virtual void Dec () {m_a--;} virtual void print () One { printf ("%d\n", m_a); 14}; A . int main (), { xuzhina_dump_c06_s3* test = new Xuzhina_dump_c06_s3; n if (test! = NULL) 20
{ test->inc (); test->inc (); test->print (); + 0; 26}
Assembly Code:
(GDB) disassemble maindump of assembler code for function main:0x08048560 <+0>: Push%EBP 0x08048561 < +1>: mov%esp,%ebp 0x08048563 <+3>: Push%ebx 0x08048564 <+4>: and $0xfffffff0,%esp 0x08048567 <+7>: Sub $0x20,%esp 0x0804856a <+10>: Movl $0x8, (%ESP) 0x08048571 <+17>: Call 0x8048450 <[email protected]> 0x08048576 <+22>: mov%eax,%ebx 0x08048578 <+24>: mov%ebx, (%ESP) 0x0804857b <+27>: Call 0x80485cc <_ZN19xuzhina_dump_c06_s3C2Ev> 0x08048580 < ; +32>: mov%ebx,0x1c (%ESP) 0x08048584 <+36>: Cmpl $0x0,0x1c (%ESP) 0x08048589 <+41>: je 0X80485C1 <main+97> 0x0804858b <+43>: mov 0x1c (%ESP),%eax 0x0804858f <+47>: mov (%EAX) ,%eax 0x08048591 <+49>: mov (%EAX),%eax 0x08048593 <+51>: mov 0x1c (%ESP),%edx 0x08048597 < ; +55>: mov%edx, (%ESP) 0x0804859a <+58>: Call *%eax 0x0804859c <+60>: mov 0x1c (%ESP),%eax 0x080485a0 <+64 : mov (%EAX),%eax 0x080485a2 <+66>: mov (%EAX),%eax 0x080485a4 <+68>: mov 0x1c (%ESP) ,%edx 0x080485a8 <+72>: mov%edx, (%ESP) 0x080485ab <+75>: Call *%eax 0X080485AD <+77>: mov 0x1c (%ESP),%eax 0x080485b1 <+81>: mov (%EAX),%eax 0x080485b3 <+83>: Add $0x8,%eax 0x080485b6 <+86>: mov (%EAX),%eax 0x080485b8 <+88>: mov 0x1c (%ESP),%edx 0X080485BC <+92> : mov%edx, (%ESP) 0X080485BF <+95>: Call *%eax 0x080485c1 <+97>: mov $0x0,%eax 0x080485 C6 <+102>: mov-0x4 (%EBP),%ebx 0x080485c9 <+105>: Leave 0x080485ca <+106>: ret End of Assembler dump.
The above code shows that, after executing the constructor, the value of the m_a of Test will become 0. And by the above assembly you can see that the this pointer is placed in the EBX register before and after the constructor is called.
At 0x08048578,0x08048580, take a look at the address that the this pointer points to is not the result.
(GDB) Tbreak *0x08048578temporary Breakpoint 1 at 0x8048578 (GDB) tbreak *0x08048580temporary Breakpoint 2 at 0x8048580 (gdb ) rstarting Program:/HOME/BUCKXU/WORK/6/3/XUZHINA_DUMP_C6_S3 temporary breakpoint 1, 0x08048578 in Main () (GDB) x/4x $eb x0x804a008: 0x00000000 0x00000000 0x00000000 0x00020ff1 (gdb) ccontinuing.temporary Breakpoint 2, 0x08048580 in Main () (GDB) x/4x $ebx 0x804a008: 0x080486d0 0x00000000 0x00000000 0x00020ff1
Very strange, according to the previous section of the content, address 0x804a008 should be stored m_a, will be initialized to 0. What exactly is the constructor of class Xuzhina_dump_c06_s3 doing? And what is 0X080486D0?
Take a look at the constructor of class Xuzhina_dump_c06_s3:
(GDB) disassemble _zn19xuzhina_dump_c06_s3c2evdump of assembler code for function _zn19xuzhina_dump_c06_s3c2ev: 0x080485cc <+0>: push %ebp 0x080485cd <+1>: mov %esp,%ebp 0x080485cf <+3 : mov 0x8 (%EBP),%eax 0x080485d2 <+6>: movl $0x80486d0, (%eax) 0x080485d8 <+12>: mov 0x8 (%EBP),%eax 0x080485db <+15>: movl $0x0,0x4 (%eax) 0x080485e2 <+22>: pop %ebp 0x080485e3 <+23>: ret End of assembler dump.
The Assembly of the constructor shows that the value of 0x80486d0 is set in the constructor, but it is unclear what it is. and
0x080485d8 <+12>: mov 0x8 (%EBP),%eax 0x080485db <+15>: movl $0x0,0x4 (%EAX)
It just corresponds.
7 Xuzhina_dump_c06_s3 () {m_a = 0;}
That is, the first member variable of the class Xuzhina_dump_c06_s3 M_a placed where the this pointer is offset, so what is 0x80486d0, the position of the m_a?
Look again at the assembly of the main function:
(GDB) disassemble maindump of assembler code for function main:0x08048560 <+0>: Push%EBP 0x08048561 < +1>: mov%esp,%ebp 0x08048563 <+3>: Push%ebx 0x08048564 <+4>: and $0xfffffff0,%esp 0x08048567 <+7>: Sub $0x20,%esp 0x0804856a <+10>: Movl $0x8, (%ESP) 0x08048571 <+17>: Call 0x8048450 <[email protected]> 0x08048576 <+22>: mov%eax,%ebx 0x08048578 <+24>: mov%ebx, (%ESP) 0x0804857b <+27>: Call 0x80485cc <_ZN19xuzhina_dump_c06_s3C2Ev>=> 0x08048580 <+32>: mov%ebx,0x1c (%ESP) 0x08048584 <+36>: Cmpl $0x0,0x1c (%ESP) 0x08048589 <+41>: je 0X80485C1 <main+97> 0x0804858b <+43>: mov 0x1c (%ESP),%eax 0x0804858f <+47>: mov (%e AX),%eax 0x08048591 <+49>: mov (%EAX),%eax 0x08048593 <+51>: mov 0x1c (%ESP),%edx 0x08048597 <+55>: mov%edx, (%ESP) 0x0804859a <+58>: Call *%eax 0x0804859c <+60>: mov 0x1c (%ESP),%eax 0x080485a0 < +64>: mov (%eax),%eax 0x080485a2 <+66>: mov (%EAX),%eax 0x080485a4 <+68>: mov 0x1c (%e SP),%edx 0x080485a8 <+72>: mov%edx, (%ESP) 0x080485ab <+75>: Call *%eax 0X080485AD <+77> ;: mov 0x1c (%ESP),%eax 0x080485b1 <+81>: mov (%EAX),%eax 0x080485b3 <+83>: Add $0x8,%eax 0x080485b6 <+86>: mov (%EAX),%eax 0x080485b8 <+88>: mov 0x1c (%ESP),%edx 0X080485BC <+92& GT: mov%edx, (%ESP) 0X080485BF <+95>: Call *%eax 0x080485c1 <+97>: mov $0x0,%eax 0x080 485c6 <+102>: mov-0x4 (%EBP),%ebx 0x080485c9 <+105>: Leave 0x080485ca <+106>: ret End of assembler dump.
By
0x0804857b <+27>: call 0x80485cc <_ZN19xuzhina_dump_c06_s3C2Ev> 0x08048580 <+32>: mov %ebx,0x1c (%ESP)
The esp+0x1c is used to store this pointer.
Take a look at these instructions:
0x0804858b <+43>: mov 0x1c (%ESP),%eax 0x0804858f <+47>: mov (%EAX),%eax 0x08048591 <+49> : mov (%EAX),%eax 0x08048593 <+51>: mov 0x1c (%ESP),%edx 0x08048597 <+55>: mov%edx, (%esp ) 0x0804859a <+58>: Call *%eax 0x0804859c <+60>: mov 0x1c (%ESP),%eax 0x080485a0 <+64>: MOV (%EAX),%eax 0x080485a2 <+66>: mov (%EAX),%eax 0x080485a4 <+68>: mov 0x1c (%ESP),%edx 0x080485a8 <+72>: mov%edx, (%ESP) 0x080485ab <+75>: Call *%eax 0X080485AD <+77>: mov 0x1c (%ESP),%eax 0x080485b1 <+81>: mov (%EAX),%eax 0x080485b3 <+83>: Add $0x8,%eax 0x0804 85b6 <+86>: mov (%EAX),%eax 0x080485b8 <+88>: mov 0x1c (%ESP),%edx 0X080485BC <+92>: M OV%edx, (%ESP) 0X080485BF <+95>: Call *%eax
Because it is a sequential structure, we know that these three directives correspond exactly
test->inc (); test->inc (); test->print ();
Analyze the third paragraph of the Assembly:
0X080485AD <+77>: mov 0x1c (%esp),%eax 0x080485b1 <+81>: mov (%eax),%eax 0X080485B3 <+83>: add $0x8,%eax 0x080485b6 <+86>: mov (%eax),%eax 0x080485b8 <+88>: mov 0x1c (%esp),%edx 0X080485BC <+92>: mov %edx, (%ESP) 0X080485BF <+95>: call *%eax
The visible eax is just a pointer to the virtual function of the print. And this pointer is finally made by esp+0x1c. By
0X080485AD <+77>: mov 0x1c (%esp),%eax 0x080485b1 <+81>: mov (%eax),%eax
It is true that the first member of the this pointer is taken out, that is, the member is a virtual function table pointer. According to the above analysis, the value of this virtual function table pointer is 0x80486d0. To verify that it is not a virtual function table pointer.
(gdb) x/4x 0x80486d00x80486d0 <_ztv19xuzhina_dump_c06_s3+8>: 0x080485e4 0x080485f8 0x0804860c 0x75783931 (gdb) shell c++filt _ztv19xuzhina_dump_c06_s3vtable for XUZHINA_DUMP_C06_S3 (GDB) Info symbol 0x080485e4xuzhina_dump_c06_s3::inc () in section. Text OF/HOME/BUCKXU/WORK/6/3/XUZHINA_DUMP_C6_S3 (GDB) Info symbol 0X080485F8XUZHINA_DUMP_C06_S3::d EC () in section. Text OF/HOME/BUCKXU/WORK/6/3/XUZHINA_DUMP_C6_S3 (GDB) Info symbol 0X0804860CXUZHINA_DUMP_C06_S3::p rint () in section. Text Of/home/buckxu/work/6/3/xuzhina_dump_c6_s3
As you can see, 0x80486d0 points to the virtual function table, and the table entry order is exactly the same as the declaration order of the virtual function.
From the above analysis, the memory layout of the object pointed to by test is as follows:
Coredump Problem Theory Research "Linux version x86 6.4 section virtual function