《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 function main:
   0x080485b4 <+0>:	push   %ebp
   0x080485b5 <+1>:	mov    %esp,%ebp
   0x080485b7 <+3>:	and    $0xfffffff0,%esp
   0x080485ba <+6>:	push   %esi
   0x080485bb <+7>:	push   %ebx
   0x080485bc <+8>:	sub    $0x38,%esp
   0x080485bf <+11>:	lea    0x1c(%esp),%eax
   0x080485c3 <+15>:	mov    %eax,(%esp)
   0x080485c6 <+18>:	call   0x8048674 <_ZNSt4listIiSaIiEEC2Ev>
   0x080485cb <+23>:	movl   $0x12345678,0x24(%esp)
   0x080485d3 <+31>:	lea    0x24(%esp),%eax
   0x080485d7 <+35>:	mov    %eax,0x4(%esp)
   0x080485db <+39>:	lea    0x1c(%esp),%eax
   0x080485df <+43>:	mov    %eax,(%esp)
   0x080485e2 <+46>:	call   0x80486de <_ZNSt4listIiSaIiEE9push_backERKi>
   0x080485e7 <+51>:	movl   $0xabcdef01,0x28(%esp)
   0x080485ef <+59>:	lea    0x28(%esp),%eax
   0x080485f3 <+63>:	mov    %eax,0x4(%esp)
   0x080485f7 <+67>:	lea    0x1c(%esp),%eax
   0x080485fb <+71>:	mov    %eax,(%esp)
   0x080485fe <+74>:	call   0x8048714 <_ZNSt4listIiSaIiEE10push_frontERKi>
   0x08048603 <+79>:	movl   $0x24242522,0x2c(%esp)
   0x0804860b <+87>:	lea    0x2c(%esp),%eax
   0x0804860f <+91>:	mov    %eax,0x4(%esp)
---Type <return> to continue, or q <return> to quit---
   0x08048613 <+95>:	lea    0x1c(%esp),%eax
   0x08048617 <+99>:	mov    %eax,(%esp)
   0x0804861a <+102>:	call   0x80486de <_ZNSt4listIiSaIiEE9push_backERKi>
   0x0804861f <+107>:	mov    $0x0,%ebx
   0x08048624 <+112>:	lea    0x1c(%esp),%eax
   0x08048628 <+116>:	mov    %eax,(%esp)
   0x0804862b <+119>:	call   0x8048660 <_ZNSt4listIiSaIiEED2Ev>
   0x08048630 <+124>:	mov    %ebx,%eax
   0x08048632 <+126>:	add    $0x38,%esp
   0x08048635 <+129>:	pop    %ebx
   0x08048636 <+130>:	pop    %esi
   0x08048637 <+131>:	mov    %ebp,%esp
   0x08048639 <+133>:	pop    %ebp
   0x0804863a <+134>:	ret    
   0x0804863b <+135>:	mov    %edx,%ebx
   0x0804863d <+137>:	mov    %eax,%esi
   0x0804863f <+139>:	lea    0x1c(%esp),%eax
   0x08048643 <+143>:	mov    %eax,(%esp)
   0x08048646 <+146>:	call   0x8048660 <_ZNSt4listIiSaIiEED2Ev>
   0x0804864b <+151>:	mov    %esi,%eax
   0x0804864d <+153>:	mov    %ebx,%edx
   0x0804864f <+155>:	mov    %eax,(%esp)
   0x08048652 <+158>:	call   0x80484e8 <_Unwind_Resume@plt>
End of assembler dump.

由0x080485c6附近的汇编来看,this指针放在esp+0x1c

在0x080485c6, 0x080485e2,0x080485fe, 0x0804861a, 0x0804862b打断点

(gdb) b *0x080485c6
Breakpoint 1 at 0x80485c6
(gdb) b *0x080485e2
Breakpoint 2 at 0x80485e2
(gdb) b *0x080485fe
Breakpoint 3 at 0x80485fe
(gdb) b *0x0804861a
Breakpoint 4 at 0x804861a
(gdb) b *0x0804862b
Breakpoint 5 at 0x804862b

先看一下list运行构造函数后会怎样.

Breakpoint 1, 0x080485c6 in main ()
(gdb) x /8x $esp+0x1c
0xbffff24c:	0x08048aa9	0x028ea550	0x0804832e	0x00000000
0xbffff25c:	0x009faff4	0x08048a90	0x08048500	0x009faff4
(gdb) ni
0x080485cb in main ()
(gdb) x /8x $esp+0x1c
0xbffff24c:	0xbffff24c	0xbffff24c	0x0804832e	0x00000000
0xbffff25c:	0x009faff4	0x08048a90	0x08048500	0x009faff4


可以看出list对象有两个成员, 且这两个成员的值均指向自身。可见,这两个成员是指针。

再看一下第一个push_back后

Breakpoint 2, 0x080485e2 in main ()
(gdb) x /8x $esp+0x1c
0xbffff24c:	0xbffff24c	0xbffff24c	0x12345678	0x00000000
0xbffff25c:	0x009faff4	0x08048a90	0x08048500	0x009faff4
(gdb) ni
0x080485e7 in main ()
(gdb) x /8x $esp+0x1c
0xbffff24c:	0x0804b008	0x0804b008	0x12345678	0x00000000
0xbffff25c:	0x009faff4	0x08048a90	0x08048500	0x009faff4
(gdb) x /8x 0x0804b008
0x804b008:	0xbffff24c	0xbffff24c	0x12345678	0x00020ff1
0x804b018:	0x00000000	0x00000000	0x00000000	0x00000000

用结构表示如下:

技术分享

再看一下push_front

Breakpoint 3, 0x080485fe in main ()
(gdb) x /8x $esp+0x1c
0xbffff24c:	0x0804b008	0x0804b008	0x12345678	0xabcdef01
0xbffff25c:	0x009faff4	0x08048a90	0x08048500	0x009faff4
(gdb) x /8x 0x0804b008
0x804b008:	0xbffff24c	0xbffff24c	0x12345678	0x00020ff1
0x804b018:	0x00000000	0x00000000	0x00000000	0x00000000
(gdb) ni
0x08048603 in main ()
(gdb) x /8x $esp+0x1c
0xbffff24c:	0x0804b018	0x0804b008	0x12345678	0xabcdef01
0xbffff25c:	0x009faff4	0x08048a90	0x08048500	0x009faff4
(gdb) x /8x 0x0804b018
0x804b018:	0x0804b008	0xbffff24c	0xabcdef01	0x00020fe1
0x804b028:	0x00000000	0x00000000	0x00000000	0x00000000
(gdb) x /8x 0x0804b008
0x804b008:	0xbffff24c	0x0804b018	0x12345678	0x00000011
0x804b018:	0x0804b008	0xbffff24c	0xabcdef01	0x00020fe1


用图形来表示就如下(只表示第一个成员).

技术分享

如果考察这三个地址的第二个成员,就会变成这样的图形

技术分享

同样考察第二个push_back,并参照list的代码,会得到这样的结论.

1.     list有两个成员,第一个成员指向链表的头部,第二个成员指向链表的尾部

2.     链表的每一个节点都有三个元素,第一个_M_next,指向下一个节点.第二个_M_prev指向前一个节点.第三个_M_data存储节点的值.

3.     list所指向的链表每一个节点的_M_next, _M_prev指针应该都不为空的,也必须是指向有效地址.


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。