《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 <[email protected]>
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)可得到下图

时间: 2024-08-07 06:25:12

《coredump问题原理探究》Linux x86版7.1节vector对象的相关文章

《coredump问题原理探究》Linux x86版7.2节vector coredump例子

看一个coredump的例子: [[email protected] s1_ex]$ gdb xuzhina_dump_c07_s1_ex core.27776 GNU gdb (GDB) Red Hat Enterprise Linux (7.2-75.el6) Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses

《coredump问题原理探究》Linux x86版7.5节 Map对象

先看一个例子: 1 #include <map> 2 3 int main() 4 { 5 std::map<int,int> iMap; 6 7 iMap[5] = 6; 8 iMap[8] = 20; 9 iMap[2] = 80; 10 11 return 0; 12 } 看一下汇编: (gdb) disassemble main Dump of assembler code for function main: 0x080486e4 <+0>: push %eb

《coredump问题原理探究》Linux x86版7.7节 set对象

看一下bits/stl_map和bits/stl_set可以看到map和set的定义如下: 84 template <typename _Key, typename _Tp, typename _Compare = std::less<_Key>, 85 typename _Alloc = std::allocator<std::pair<const _Key, _Tp> > > 86 class map 87 { 88 public: 89 typedef

《coredump问题原理探究》Linux x86版7.3节List对象

先看一下例子: 1 #include <list> 2 3 int main() 4 { 5 std::list<int> lst; 6 7 lst.push_back( 0x12345678 ); 8 lst.push_front( 0xabcdef01 ); 9 lst.push_back( 0x24242522 ); 10 11 return 0; 12 } 再看一下汇编: (gdb) disassemble main Dump of assembler code for f

《coredump问题原理探究》Linux x86版7.8节vector相关的iterator对象

在前面看过了一个vectorcoredump的例子,接触了vector的iterator,可以知道vector的iterator只有一个成员_M_current指向vector某一个元素. 先看一个例子: 1 #include <vector> 2 3 void init( std::vector<int>& vec ) 4 { 5 for ( int i = 0; i < 0x10; i++ ) 6 { 7 vec.push_back( i ); 8 } 9 } 1

《coredump问题原理探究》Windows版 笔记

<coredump问题原理探究>Windows版 笔记 Debug 一.环境搭建 1.Win7捕获程序dump 2.Windbg符号表设置(Symbols Search Path) 二.WinDbg命令 三.函数栈帧 1.栈内存布局 2.栈溢出 3.栈的规律 4.定位栈溢出问题的经验方法 四.函数逆向 五.C内存布局 1.基本类型 2.数组类型 3.结构体 六.C++内存布局 1.类的内存布局 2.this指针 3.虚函数表及虚表指针 4.单继承 5.多继承(无公共基类) 七.STL容器内存布

《coredump问题原理探究》Linux x86版6.3节有成员变量的类coredump例子

在探究完类成员变量分布后,来定位一个coredump例子来实践一把: (gdb) bt #0 0x0804863c in xuzhina_dump_c06_s2_ex::print() () #1 0x08048713 in main () 看一下xuzhina_dump_c06_s2_ex::print的汇编: (gdb) disassemble 0x0804863c Dump of assembler code for function _ZN22xuzhina_dump_c06_s2_ex

《coredump问题原理探究》Linux x86版6.2节C++风格数据结构内存布局之有成员变量的类

上面一节已经探究出this指针的辨别,由this指针就可以看到类的内容.在这里,就由this指针来看一下类的成员变量是如何排列. 先看一个例子 1 #include <stdio.h> 2 class xuzhina_dump_c06_s2 3 { 4 private: 5 short m_c; 6 char m_d; 7 int m_e; 8 9 public: 10 xuzhina_dump_c06_s2( int a, int b ) 11 { 12 m_c = (short)(a +

《coredump问题原理探究》Linux x86版6.8节多继承coredump例子

下面看一个coredump的例子: (gdb) bt #0 0x08048662 in xuzhina_dump_c06_s5_ex_child::inheritFrom(char*, int) () #1 0x08048609 in main () 先看一下xuzhina_dump_c06_s5_ex_child::inheritFrom的汇编: (gdb) disassemble 0x08048662 Dump of assembler code for function _ZN28xuzh