您的位置:首页 > 运维架构 > Linux

《coredump问题原理探究》Linux x86版7.11节string对象

2015-11-24 22:51 676 查看
在定位map coredump的那一节已经接触了string对象.在这里重温一下.

看一个例子:

1 #include <string>
2 #include <stdio.h>
3
4 int main()
5 {
6     std::string str;
7     char* ptr = "hello world!";
8
9     for ( int i = 0; i < 0x10; i++ )
10     {
11         str.append( ptr );
12     }
13
14     return 0;
15 }


看一下汇编:

(gdb) disassemble main
Dump of assembler code for function main:
0x08048584 <+0>:	push   %ebp
0x08048585 <+1>:	mov    %esp,%ebp
0x08048587 <+3>:	and    $0xfffffff0,%esp
0x0804858a <+6>:	push   %esi
0x0804858b <+7>:	push   %ebx
0x0804858c <+8>:	sub    $0x28,%esp
0x0804858f <+11>:	lea    0x14(%esp),%eax
0x08048593 <+15>:	mov    %eax,(%esp)
0x08048596 <+18>:	call   0x8048460 <_ZNSsC1Ev@plt>
0x0804859b <+23>:	movl   $0x80486d4,0x18(%esp)
0x080485a3 <+31>:	movl   $0x0,0x1c(%esp)
0x080485ab <+39>:	jmp    0x80485c6 <main+66>
0x080485ad <+41>:	mov    0x18(%esp),%eax
0x080485b1 <+45>:	mov    %eax,0x4(%esp)
0x080485b5 <+49>:	lea    0x14(%esp),%eax
0x080485b9 <+53>:	mov    %eax,(%esp)
0x080485bc <+56>:	call   0x80484a0 <_ZNSs6appendEPKc@plt>
0x080485c1 <+61>:	addl   $0x1,0x1c(%esp)
0x080485c6 <+66>:	cmpl   $0xf,0x1c(%esp)
0x080485cb <+71>:	setle  %al
0x080485ce <+74>:	test   %al,%al
0x080485d0 <+76>:	jne    0x80485ad <main+41>
0x080485d2 <+78>:	mov    $0x0,%ebx
0x080485d7 <+83>:	lea    0x14(%esp),%eax
0x080485db <+87>:	mov    %eax,(%esp)
0x080485de <+90>:	call   0x8048490 <_ZNSsD1Ev@plt>
0x080485e3 <+95>:	mov    %ebx,%eax
0x080485e5 <+97>:	add    $0x28,%esp
0x080485e8 <+100>:	pop    %ebx
0x080485e9 <+101>:	pop    %esi
0x080485ea <+102>:	mov    %ebp,%esp
0x080485ec <+104>:	pop    %ebp
0x080485ed <+105>:	ret
0x080485ee <+106>:	mov    %edx,%ebx
0x080485f0 <+108>:	mov    %eax,%esi
0x080485f2 <+110>:	lea    0x14(%esp),%eax
0x080485f6 <+114>:	mov    %eax,(%esp)
0x080485f9 <+117>:	call   0x8048490 <_ZNSsD1Ev@plt>
0x080485fe <+122>:	mov    %esi,%eax
0x08048600 <+124>:	mov    %ebx,%edx
0x08048602 <+126>:	mov    %eax,(%esp)
0x08048605 <+129>:	call   0x80484c0 <_Unwind_Resume@plt>
End of assembler dump.


在0x080485bc打断点.

由上面汇编可知,esp+0x14是string对象的this指针, 字符串”hello world”放在esp+0x18.

构造完毕的string对象

(gdb) x /wx $esp+0x14
0xbffff664:	0x00d2ff5c
(gdb) x /8wx 0x00d2ff5c
0xd2ff5c <_ZNSs4_Rep20_S_empty_rep_storageE+12>:	0x00000000	0x00000000	0x00000000	0x00000000
0xd2ff6c <_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE>:	0x00000000	0x00000000	0x00000000	0x00000000


由_ZNSs4_Rep20_S_empty_rep_storageE+12这一行,我们看一下把string对象的this指针-12,看看内容是怎样?

(gdb) x /8wx 0x00d2ff5c-0xc
0xd2ff50 <_ZNSs4_Rep20_S_empty_rep_storageE>:	0x00000000	0x00000000	0x00000000	0x00000000
0xd2ff60 <_ZNSt10moneypunctIwLb0EE2idE>:	0x00000000	0x00000000	0x00000000	0x00000000


看不出什么东西。

调用第一次append后.

(gdb) ni
0x080485c1 in main ()
(gdb) x /wx $esp+0x14
0xbffff664:	0x0804a014
(gdb) x /8wx 0x0804a014
0x804a014:	0x6c6c6568	0x6f77206f	0x21646c72	0x00000000
0x804a024:	0x00020fe1	0x00000000	0x00000000	0x00000000
(gdb) x /8wx 0x0804a014-0xc
0x804a008:	0x0000000c	0x0000000c	0x00000000	0x6c6c6568
0x804a018:	0x6f77206f	0x21646c72	0x00000000	0x00020fe1


由于字符串”helloworld!”的大小是12(0xc),而0x804a008开始的两个单元都是0xc,究竟哪一个才是实际大小。而0x0804a014所存放的就是”hello world!”.

看一下多调用几次append之后会怎样:

(gdb) c
Continuing.

Breakpoint 1, 0x080485bc in main ()
(gdb) ni
0x080485c1 in main ()
(gdb) x /wx $esp+0x14
0xbffff664:	0x0804a034
(gdb) x /8wx 0x0804a034-0xc
0x804a028:	0x00000018	0x00000018	0x00000000	0x6c6c6568
0x804a038:	0x6f77206f	0x21646c72	0x6c6c6568	0x6f77206f
(gdb) c
Continuing.

Breakpoint 1, 0x080485bc in main ()
(gdb) ni
0x080485c1 in main ()
(gdb) x /wx $esp+0x14
0xbffff664:	0x0804a064
(gdb) x /16wx 0x0804a064-0xc
0x804a058:	0x00000024	0x00000030	0x00000000	0x6c6c6568
0x804a068:	0x6f77206f	0x21646c72	0x6c6c6568	0x6f77206f
0x804a078:	0x21646c72	0x6c6c6568	0x6f77206f	0x21646c72
0x804a088:	0x00000000	0x00000000	0x00000000	0x00000000
(gdb) c
Continuing.

Breakpoint 1, 0x080485bc in main ()
(gdb) ni
0x080485c1 in main ()
(gdb) x /wx $esp+0x14
0xbffff664:	0x0804a064
(gdb) x /16wx 0x0804a064-0xc
0x804a058:	0x00000030	0x00000030	0x00000000	0x6c6c6568
0x804a068:	0x6f77206f	0x21646c72	0x6c6c6568	0x6f77206f
0x804a078:	0x21646c72	0x6c6c6568	0x6f77206f	0x21646c72
0x804a088:	0x6c6c6568	0x6f77206f	0x21646c72	0x00000000
(gdb) c
Continuing.

Breakpoint 1, 0x080485bc in main ()
(gdb) ni
0x080485c1 in main ()
(gdb) x /wx $esp+0x14
0xbffff664:	0x0804a0ac
(gdb) x /16wx 0x0804a0ac-0xc
0x804a0a0:	0x0000003c	0x00000060	0x00000000	0x6c6c6568
0x804a0b0:	0x6f77206f	0x21646c72	0x6c6c6568	0x6f77206f
0x804a0c0:	0x21646c72	0x6c6c6568	0x6f77206f	0x21646c72
0x804a0d0:	0x6c6c6568	0x6f77206f	0x21646c72	0x6c6c6568


可见,string对象有如下特征:

1. 第一个成员是字符串大小

2. 第二个成员是字符串对象的最大空间

3. 第四个成员存放着字符串

4. 当字符串的大小超过对象最大空间时,字符串对象会重新分配一段连续内存。

5. 当字符串对象刚刚构造完成时,并没有分配任何空间。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: