C++对象 内存分布

来源:互联网 发布:ubuntu环境变量bashrc 编辑:程序博客网 时间:2024/06/04 18:22

代码如下:

    class T {    public :        T();        virtual int f(void);    private :        int d;    };T::T(void){d = 0x12345678;}int T::f(void){return 12;}void x(T& t) {        t.f();    }int main(void){T t;x(t);return 0;}

下面通过汇编来分析类 T 对象的内存分布。

1. 在  main 函数第一行设置断点, 观察执行  T的构造函数之前的情形:

Dump of assembler code for function main():   0x00010650 <+0>:push{r11, lr}   0x00010654 <+4>:addr11, sp, #4   0x00010658 <+8>:subsp, sp, #8   0x0001065c <+12>:subr3, r11, #12   0x00010660 <+16>:movr0, r3=> 0x00010664 <+20>:bl0x105bc <T::T()>   0x00010668 <+24>:subr3, r11, #12   0x0001066c <+28>:movr0, r3   0x00010670 <+32>:bl0x10624 <x(T&)>   0x00010674 <+36>:movr3, #0   0x00010678 <+40>:b0x10680 <main()+48>   0x0001067c <+44>:bl0x10470 <__cxa_end_cleanup@plt>   0x00010680 <+48>:movr0, r3   0x00010684 <+52>:subsp, r11, #4   0x00010688 <+56>:pop{r11, pc}

此时的栈结构如下:


(gdb) p /x $r0$3 = 0xbefffcc0(gdb) p /x $sp$4 = 0xbefffcc0
此时, r0指向 对象 t 在栈上的初始地址(对象 t大小为2字节)。

2.下面进入 T的构造函数:

(gdb) disassDump of assembler code for function T::T():   0x000105bc <+0>:push{r11}; (str r11, [sp, #-4]!)   0x000105c0 <+4>:addr11, sp, #0   0x000105c4 <+8>:subsp, sp, #12   0x000105c8 <+12>:strr0, [r11, #-8]   0x000105cc <+16>:ldrr3, [r11, #-8]   0x000105d0 <+20>:ldrr2, [pc, #36]; 0x105fc <T::T()+64>   0x000105d4 <+24>:strr2, [r3]   0x000105d8 <+28>:ldrr2, [r11, #-8]   0x000105dc <+32>:movwr3, #22136; 0x5678   0x000105e0 <+36>:movtr3, #4660; 0x1234   0x000105e4 <+40>:strr3, [r2, #4]   0x000105e8 <+44>:ldrr3, [r11, #-8]   0x000105ec <+48>:movr0, r3=> 0x000105f0 <+52>:subsp, r11, #0   0x000105f4 <+56>:pop{r11}; (ldr r11, [sp], #4)   0x000105f8 <+60>:bxlr   0x000105fc <+64>:andeqr0, r1, r0, lsl r7
此时,栈上的内容为:


3. 在 x()里面的情形:

Dump of assembler code for function x(T&):=> 0x00010624 <+0>:push{r11, lr}   0x00010628 <+4>:addr11, sp, #4   0x0001062c <+8>:subsp, sp, #8   0x00010630 <+12>:strr0, [r11, #-8]   0x00010634 <+16>:ldrr3, [r11, #-8]   0x00010638 <+20>:ldrr3, [r3]   0x0001063c <+24>:ldrr3, [r3]   0x00010640 <+28>:ldrr0, [r11, #-8]   0x00010644 <+32>:blxr3   0x00010648 <+36>:subsp, r11, #4   0x0001064c <+40>:pop{r11, pc}
(gdb) p /x $sp$20 = 0xbefffcc0(gdb) p /x $r0$21 = 0xbefffcc0(gdb) p /x $r11$22 = 0xbefffccc

Dump of assembler code for function x(T&):   0x00010624 <+0>:push{r11, lr}   0x00010628 <+4>:addr11, sp, #4   0x0001062c <+8>:subsp, sp, #8   0x00010630 <+12>:strr0, [r11, #-8]   0x00010634 <+16>:ldrr3, [r11, #-8]   0x00010638 <+20>:ldrr3, [r3]   0x0001063c <+24>:ldrr3, [r3]   0x00010640 <+28>:ldrr0, [r11, #-8]=> 0x00010644 <+32>:blxr3   0x00010648 <+36>:subsp, r11, #4   0x0001064c <+40>:pop{r11, pc}End of assembler dump.(gdb) p /x $r3$25 = 0x10600(gdb) x $r3   0x10600 <T::f()>:0xe52db004(gdb) p /x $r0$26 = 0xbefffcc0(gdb) x $r0   0xbefffcc0:0x00010710(gdb) x 0x000107100x10710 <_ZTV1T+8>:0x00010600

此时,栈以及调用关系如下:

如前所说, T 占了8个字节,一个4字节是成员变量的,另一个就是vtbl (虚表)指针所占用。这里虚表指向  T::f()的地址。

虚表信息也可以从 gdb观察到:

(gdb) p t$28 = {_vptr.T = 0x10710 <vtable for T+8>, d = 305419896}(gdb) info vtbl tvtable for 'T' @ 0x10710 (subobject @ 0xbefffcc0):[0]: 0x10600 <T::f()>
(gdb) p &t$29 = (T *) 0xbefffcc0


reference:

1. http://blog.httrack.com/blog/2014/05/09/a-basic-glance-at-the-virtual-table/

2.http://www.lrdev.com/lr/c/virtual.html

3.https://cloudfundoo.wordpress.com/2012/04/27/deep-c-understanding-c-object-layout/

0 0
原创粉丝点击