《coredump问题原理探究》Linux x86版7.1节vector对象
先看一下例子:
1 #include <vector> 2 3 int main() 4 { 5 std::vector<int> vec; 6 vec.push_back( 0xffeeffab ); 7 vec.push_back( 0xabcdef01 ); 8 vec.push_back( 0x12345678 ); 9 return 0; 10 }
看一下汇编:
(gdb) b main Breakpoint 1 at 0x8048697 (gdb) r Starting program: /home/xuzhina/code/s1/xuzhina_dump_c07_s1 Breakpoint 1, 0x08048697 in main () Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.149.el6_6.4.i686 libgcc-4.4.7-11.el6.i686 libstdc++-4.4.7-11.el6.i686 (gdb) disassemble Dump of assembler code for function main: 0x08048694 <+0>: push %ebp 0x08048695 <+1>: mov %esp,%ebp => 0x08048697 <+3>: and $0xfffffff0,%esp 0x0804869a <+6>: push %esi 0x0804869b <+7>: push %ebx 0x0804869c <+8>: sub $0x38,%esp 0x0804869f <+11>: lea 0x18(%esp),%eax 0x080486a3 <+15>: mov %eax,(%esp) 0x080486a6 <+18>: call 0x8048740 <_ZNSt6vectorIiSaIiEEC2Ev> 0x080486ab <+23>: movl $0xffeeffab,0x24(%esp) 0x080486b3 <+31>: lea 0x24(%esp),%eax 0x080486b7 <+35>: mov %eax,0x4(%esp) 0x080486bb <+39>: lea 0x18(%esp),%eax 0x080486bf <+43>: mov %eax,(%esp) 0x080486c2 <+46>: call 0x80487b2 <_ZNSt6vectorIiSaIiEE9push_backERKi> 0x080486c7 <+51>: movl $0xabcdef01,0x28(%esp) 0x080486cf <+59>: lea 0x28(%esp),%eax 0x080486d3 <+63>: mov %eax,0x4(%esp) 0x080486d7 <+67>: lea 0x18(%esp),%eax 0x080486db <+71>: mov %eax,(%esp) 0x080486de <+74>: call 0x80487b2 <_ZNSt6vectorIiSaIiEE9push_backERKi> 0x080486e3 <+79>: movl $0x12345678,0x2c(%esp) 0x080486eb <+87>: lea 0x2c(%esp),%eax 0x080486ef <+91>: mov %eax,0x4(%esp) 0x080486f3 <+95>: lea 0x18(%esp),%eax 0x080486f7 <+99>: mov %eax,(%esp) 0x080486fa <+102>: call 0x80487b2 <_ZNSt6vectorIiSaIiEE9push_backERKi> 0x080486ff <+107>: mov $0x0,%ebx 0x08048704 <+112>: lea 0x18(%esp),%eax 0x08048708 <+116>: mov %eax,(%esp) 0x0804870b <+119>: call 0x8048754 <_ZNSt6vectorIiSaIiEED2Ev> 0x08048710 <+124>: mov %ebx,%eax 0x08048712 <+126>: add $0x38,%esp 0x08048715 <+129>: pop %ebx 0x08048716 <+130>: pop %esi 0x08048717 <+131>: mov %ebp,%esp 0x08048719 <+133>: pop %ebp 0x0804871a <+134>: ret 0x0804871b <+135>: mov %edx,%ebx 0x0804871d <+137>: mov %eax,%esi 0x0804871f <+139>: lea 0x18(%esp),%eax 0x08048723 <+143>: mov %eax,(%esp) 0x08048726 <+146>: call 0x8048754 <_ZNSt6vectorIiSaIiEED2Ev> 0x0804872b <+151>: mov %esi,%eax 0x0804872d <+153>: mov %ebx,%edx 0x0804872f <+155>: mov %eax,(%esp) 0x08048732 <+158>: call 0x80485c8 <_Unwind_Resume@plt> End of assembler dump.
由0x080486a6,0x080486c2, 0x080486de, 0x080486fa, 0x0804870b地址附近的指令来看,vector的this指针放在esp+0x18.
在0x080486a6,0x080486c2, 0x080486de, 0x080486fa, 0x0804870b打断点来看看this指针所指向的内容如何变化:
在0x080486a6调用的是vector的构造函数:
(gdb) c Continuing. Breakpoint 2, 0x080486a6 in main () (gdb) x /4x $esp+0x18 0xbffff248: 0xbffff278 0x08049109 0x00210df0 0x080483a4 (gdb) x /4x 0xbffff278 0xbffff278: 0xbffff2f8 0x0027ad36 0x00000001 0xbffff324 (gdb) ni 0x080486ab in main () (gdb) x /4x $esp+0x18 0xbffff248: 0x00000000 0x00000000 0x00000000 0x080483a4
由上可见,一个vector在栈上的占地面积是三个单元.
再看一下第一个push_back之后,vector有什么变化
(gdb) c Continuing. Breakpoint 3, 0x080486c2 in main () (gdb) x /4x $esp+0x18 0xbffff248: 0x00000000 0x00000000 0x00000000 0xffeeffab (gdb) ni 0x080486c7 in main () (gdb) x /4x $esp+0x18 0xbffff248: 0x0804b008 0x0804b00c 0x0804b00c 0xffeeffab (gdb) x /4x 0x0804b008 0x804b008: 0xffeeffab 0x00000000 0x00000000 0x00020ff1
可以看到,vector第一个成员指向的内存0x0804b008刚好放着push_back进来的第一个值0xffeeffab.且vector第二个成员所指向的内存0x0804b00c,与第一个成员刚好差4个字节,和vector里刚好有一个int成员相符.
接着看一下第二个push_back.
(gdb) c Continuing. Breakpoint 4, 0x080486de in main () (gdb) x /4x $esp+0x18 0xbffff248: 0x0804b008 0x0804b00c 0x0804b00c 0xffeeffab (gdb) ni 0x080486e3 in main () (gdb) x /4x $esp+0x18 0xbffff248: 0x0804b018 0x0804b020 0x0804b020 0xffeeffab (gdb) x /4x 0x0804b018 0x804b018: 0xffeeffab 0xabcdef01 0x00000000 0x00020fe1
vector的三个成员的值都有变化.第一个成员由0x0804b008变为0x0804b018,可第一个成员所指向地址的内容却是一样,还是0xffeeffab,而相邻单元放着0xabcdef01,和第二个放入vector的值一样.第二个成员与第一个成员相差8个字节,刚好是2个int字节,和vector拥有2个成员刚好一样.
考察一下第三个push_back:
(gdb) c Continuing. Breakpoint 5, 0x080486fa in main () (gdb) x /4x $esp+0x18 0xbffff248: 0x0804b018 0x0804b020 0x0804b020 0xffeeffab (gdb) ni 0x080486ff in main () (gdb) x /4x $esp+0x18 0xbffff248: 0x0804b028 0x0804b034 0x0804b038 0xffeeffab (gdb) x /4x 0x0804b028 0x804b028: 0xffeeffab 0xabcdef01 0x12345678 0x00000000
仍然可以得到第一个成员指向vector元素的开始,第二个成员是vector元素结束的下一个位置.它们之差与元素大小的商刚好是元素的个数.
如果再考察char,short, long, float, double,数组,结构体,类对象的vector,并结合vector的定义
(参考头文件/usr/include/c++/4.4.7/bits/stl_vector.h)可得到下图
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。